From b62cdc59da4639174f442e8a3a7d01c17242a5e3 Mon Sep 17 00:00:00 2001 From: Jacob Ledbetter Date: Sun, 2 Aug 2026 17:01:23 -0600 Subject: [PATCH 1/5] bugfix(network): Sort command list fast path by sort number --- Core/GameEngine/Source/GameNetwork/NetCommandList.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp b/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp index 1ca2d4a87e2..52a79484d65 100644 --- a/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp +++ b/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp @@ -169,10 +169,10 @@ NetCommandRef * NetCommandList::addMessage(NetCommandRef *&msg) { NetCommandRef *theNext = m_lastMessageInserted->getNext(); if ((m_lastMessageInserted->getCommand()->getNetCommandType() == msg->getCommand()->getNetCommandType()) && (m_lastMessageInserted->getCommand()->getPlayerID() == msg->getCommand()->getPlayerID()) && - isCommandIdNewer(msg->getCommand()->getID(), m_lastMessageInserted->getCommand()->getID()) && + isCommandIdNewer(msg->getCommand()->getSortNumber(), m_lastMessageInserted->getCommand()->getSortNumber()) && ((theNext == nullptr) || ((theNext->getCommand()->getNetCommandType() > msg->getCommand()->getNetCommandType()) || (theNext->getCommand()->getPlayerID() > msg->getCommand()->getPlayerID()) || - isCommandIdNewer(theNext->getCommand()->getID(), msg->getCommand()->getID())))) { + isCommandIdNewer(theNext->getCommand()->getSortNumber(), msg->getCommand()->getSortNumber())))) { // Make sure this command isn't already in the list. if (isEqualCommandMsg(m_lastMessageInserted->getCommand(), msg->getCommand())) { From f2dd8923e7cf0233a2945e385e1b8b0abfcb966a Mon Sep 17 00:00:00 2001 From: Jacob Ledbetter Date: Mon, 3 Aug 2026 07:47:57 -0600 Subject: [PATCH 2/5] refactor(network): Clarify command list fast path --- .../Source/GameNetwork/NetCommandList.cpp | 57 ++++++++++++------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp b/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp index 52a79484d65..151913c3bc4 100644 --- a/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp +++ b/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp @@ -134,9 +134,20 @@ static bool isCommandIdNewer(UnsignedShort newVal, UnsignedShort oldVal) #endif } +static bool isCommandOrderedAfter(const NetCommandMsg *candidate, const NetCommandMsg *reference) +{ + if (candidate->getNetCommandType() != reference->getNetCommandType()) { + return candidate->getNetCommandType() > reference->getNetCommandType(); + } + if (candidate->getPlayerID() != reference->getPlayerID()) { + return candidate->getPlayerID() > reference->getPlayerID(); + } + return isCommandIdNewer(candidate->getSortNumber(), reference->getSortNumber()); +} + /** * Insert sorts msg. Assumes that all the previous message inserts were done using this function. - * The message is sorted in based first on command type, then player id, and then command id. + * The message is sorted based first on command type, then player id, and then sort number. */ NetCommandRef * NetCommandList::addMessage(NetCommandMsg *cmdMsg) { if (cmdMsg == nullptr) { @@ -166,16 +177,22 @@ NetCommandRef * NetCommandList::addMessage(NetCommandRef *&msg) { // Messages that are inserted in order should just be put in one right after the other. // So saving the placement of the last message inserted can give us a huge boost in // efficiency. - NetCommandRef *theNext = m_lastMessageInserted->getNext(); - if ((m_lastMessageInserted->getCommand()->getNetCommandType() == msg->getCommand()->getNetCommandType()) && - (m_lastMessageInserted->getCommand()->getPlayerID() == msg->getCommand()->getPlayerID()) && - isCommandIdNewer(msg->getCommand()->getSortNumber(), m_lastMessageInserted->getCommand()->getSortNumber()) && - ((theNext == nullptr) || ((theNext->getCommand()->getNetCommandType() > msg->getCommand()->getNetCommandType()) || - (theNext->getCommand()->getPlayerID() > msg->getCommand()->getPlayerID()) || - isCommandIdNewer(theNext->getCommand()->getSortNumber(), msg->getCommand()->getSortNumber())))) { + NetCommandMsg *command = msg->getCommand(); + NetCommandMsg *lastCommand = m_lastMessageInserted->getCommand(); + NetCommandRef *nextCommandRef = m_lastMessageInserted->getNext(); + + bool canInsertAfterLast = lastCommand->getNetCommandType() == command->getNetCommandType() + && lastCommand->getPlayerID() == command->getPlayerID() + && isCommandIdNewer(command->getSortNumber(), lastCommand->getSortNumber()); + + if (canInsertAfterLast && nextCommandRef != nullptr) { + canInsertAfterLast = isCommandOrderedAfter(nextCommandRef->getCommand(), command); + } + + if (canInsertAfterLast) { // Make sure this command isn't already in the list. - if (isEqualCommandMsg(m_lastMessageInserted->getCommand(), msg->getCommand())) { + if (isEqualCommandMsg(lastCommand, command)) { // This command is already in the list, don't duplicate it. deleteInstance(msg); @@ -183,20 +200,17 @@ NetCommandRef * NetCommandList::addMessage(NetCommandRef *&msg) { return nullptr; } - if (theNext == nullptr) { - // this means that m_lastMessageInserted == m_last, so m_last should point to the msg that is being inserted. - msg->setNext(m_lastMessageInserted->getNext()); - msg->setPrev(m_lastMessageInserted); - m_lastMessageInserted->setNext(msg); - m_lastMessageInserted = msg; + msg->setNext(nextCommandRef); + msg->setPrev(m_lastMessageInserted); + m_lastMessageInserted->setNext(msg); + + if (nextCommandRef == nullptr) { m_last = msg; } else { - msg->setNext(m_lastMessageInserted->getNext()); - msg->setPrev(m_lastMessageInserted); - m_lastMessageInserted->setNext(msg); - msg->getNext()->setPrev(msg); - m_lastMessageInserted = msg; + nextCommandRef->setPrev(msg); } + + m_lastMessageInserted = msg; return msg; } } @@ -291,8 +305,7 @@ NetCommandRef * NetCommandList::addMessage(NetCommandRef *&msg) { return msg; } - // Find the position within the player's section based on the command ID. - // If the command type doesn't require a command ID, sort by whatever it should be sorted by. + // Find the position within the player's section based on the sort number. while (tempmsg != nullptr && msg->getCommand()->getNetCommandType() == tempmsg->getCommand()->getNetCommandType() && msg->getCommand()->getPlayerID() == tempmsg->getCommand()->getPlayerID() From ace9531b877f51d185886a4d625e31516168f983 Mon Sep 17 00:00:00 2001 From: Jacob Ledbetter Date: Mon, 3 Aug 2026 09:08:02 -0600 Subject: [PATCH 3/5] bugfix(network): Reject duplicate ACK sort collisions --- .../Source/GameNetwork/NetCommandList.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp b/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp index 151913c3bc4..0dbacb6bb3b 100644 --- a/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp +++ b/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp @@ -313,6 +313,21 @@ NetCommandRef * NetCommandList::addMessage(NetCommandRef *&msg) { tempmsg = tempmsg->getNext(); } + // Equal sort numbers can represent different ACKs, so check the entire + // equal-sort run before inserting another message. + NetCommandRef *equalSortMsg = tempmsg; + while (equalSortMsg != nullptr + && msg->getCommand()->getNetCommandType() == equalSortMsg->getCommand()->getNetCommandType() + && msg->getCommand()->getPlayerID() == equalSortMsg->getCommand()->getPlayerID() + && msg->getCommand()->getSortNumber() == equalSortMsg->getCommand()->getSortNumber()) { + if (isEqualCommandMsg(equalSortMsg->getCommand(), msg->getCommand())) { + deleteInstance(msg); + msg = nullptr; + return nullptr; + } + equalSortMsg = equalSortMsg->getNext(); + } + if (tempmsg == nullptr) { // Make sure this command isn't already in the list. if (isEqualCommandMsg(m_last->getCommand(), msg->getCommand())) { From 7bafb05f017b0e4ccae4bdd339d8795b0d19f611 Mon Sep 17 00:00:00 2001 From: Jacob Ledbetter Date: Mon, 3 Aug 2026 09:33:37 -0600 Subject: [PATCH 4/5] docs(network): Annotate base game command list fixes --- Core/GameEngine/Source/GameNetwork/NetCommandList.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp b/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp index 0dbacb6bb3b..a51f0bc91ad 100644 --- a/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp +++ b/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp @@ -181,6 +181,8 @@ NetCommandRef * NetCommandList::addMessage(NetCommandRef *&msg) { NetCommandMsg *lastCommand = m_lastMessageInserted->getCommand(); NetCommandRef *nextCommandRef = m_lastMessageInserted->getNext(); + // TheSuperHackers @bugfix CryoTheRenegade 03/08/2026 Keep both cached + // insertion boundaries consistent with the full scan's polymorphic sort key. bool canInsertAfterLast = lastCommand->getNetCommandType() == command->getNetCommandType() && lastCommand->getPlayerID() == command->getPlayerID() && isCommandIdNewer(command->getSortNumber(), lastCommand->getSortNumber()); @@ -313,8 +315,8 @@ NetCommandRef * NetCommandList::addMessage(NetCommandRef *&msg) { tempmsg = tempmsg->getNext(); } - // Equal sort numbers can represent different ACKs, so check the entire - // equal-sort run before inserting another message. + // TheSuperHackers @bugfix CryoTheRenegade 03/08/2026 Equal sort numbers can + // represent different ACKs, so check the entire equal-sort run for duplicates. NetCommandRef *equalSortMsg = tempmsg; while (equalSortMsg != nullptr && msg->getCommand()->getNetCommandType() == equalSortMsg->getCommand()->getNetCommandType() From 4c4ac92c1ace12808450b30b0f3de114b47293aa Mon Sep 17 00:00:00 2001 From: Jacob Ledbetter Date: Mon, 3 Aug 2026 12:29:10 -0600 Subject: [PATCH 5/5] style(network): Address command list review feedback --- .../Source/GameNetwork/NetCommandList.cpp | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp b/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp index a51f0bc91ad..30e26837354 100644 --- a/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp +++ b/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp @@ -134,14 +134,18 @@ static bool isCommandIdNewer(UnsignedShort newVal, UnsignedShort oldVal) #endif } -static bool isCommandOrderedAfter(const NetCommandMsg *candidate, const NetCommandMsg *reference) +static bool isCommandOrderedAfter(const NetCommandMsg* candidate, const NetCommandMsg* reference) { - if (candidate->getNetCommandType() != reference->getNetCommandType()) { + if (candidate->getNetCommandType() != reference->getNetCommandType()) + { return candidate->getNetCommandType() > reference->getNetCommandType(); } - if (candidate->getPlayerID() != reference->getPlayerID()) { + + if (candidate->getPlayerID() != reference->getPlayerID()) + { return candidate->getPlayerID() > reference->getPlayerID(); } + return isCommandIdNewer(candidate->getSortNumber(), reference->getSortNumber()); } @@ -177,9 +181,9 @@ NetCommandRef * NetCommandList::addMessage(NetCommandRef *&msg) { // Messages that are inserted in order should just be put in one right after the other. // So saving the placement of the last message inserted can give us a huge boost in // efficiency. - NetCommandMsg *command = msg->getCommand(); - NetCommandMsg *lastCommand = m_lastMessageInserted->getCommand(); - NetCommandRef *nextCommandRef = m_lastMessageInserted->getNext(); + NetCommandMsg* command = msg->getCommand(); + NetCommandMsg* lastCommand = m_lastMessageInserted->getCommand(); + NetCommandRef* nextCommandRef = m_lastMessageInserted->getNext(); // TheSuperHackers @bugfix CryoTheRenegade 03/08/2026 Keep both cached // insertion boundaries consistent with the full scan's polymorphic sort key. @@ -187,14 +191,17 @@ NetCommandRef * NetCommandList::addMessage(NetCommandRef *&msg) { && lastCommand->getPlayerID() == command->getPlayerID() && isCommandIdNewer(command->getSortNumber(), lastCommand->getSortNumber()); - if (canInsertAfterLast && nextCommandRef != nullptr) { + if (canInsertAfterLast && nextCommandRef != nullptr) + { canInsertAfterLast = isCommandOrderedAfter(nextCommandRef->getCommand(), command); } - if (canInsertAfterLast) { + if (canInsertAfterLast) + { // Make sure this command isn't already in the list. - if (isEqualCommandMsg(lastCommand, command)) { + if (isEqualCommandMsg(lastCommand, command)) + { // This command is already in the list, don't duplicate it. deleteInstance(msg); @@ -206,9 +213,13 @@ NetCommandRef * NetCommandList::addMessage(NetCommandRef *&msg) { msg->setPrev(m_lastMessageInserted); m_lastMessageInserted->setNext(msg); - if (nextCommandRef == nullptr) { + if (nextCommandRef == nullptr) + { + // this means that m_lastMessageInserted == m_last, so m_last should point to the msg that is being inserted. m_last = msg; - } else { + } + else + { nextCommandRef->setPrev(msg); } @@ -317,16 +328,19 @@ NetCommandRef * NetCommandList::addMessage(NetCommandRef *&msg) { // TheSuperHackers @bugfix CryoTheRenegade 03/08/2026 Equal sort numbers can // represent different ACKs, so check the entire equal-sort run for duplicates. - NetCommandRef *equalSortMsg = tempmsg; + NetCommandRef* equalSortMsg = tempmsg; while (equalSortMsg != nullptr && msg->getCommand()->getNetCommandType() == equalSortMsg->getCommand()->getNetCommandType() && msg->getCommand()->getPlayerID() == equalSortMsg->getCommand()->getPlayerID() - && msg->getCommand()->getSortNumber() == equalSortMsg->getCommand()->getSortNumber()) { - if (isEqualCommandMsg(equalSortMsg->getCommand(), msg->getCommand())) { + && msg->getCommand()->getSortNumber() == equalSortMsg->getCommand()->getSortNumber()) + { + if (isEqualCommandMsg(equalSortMsg->getCommand(), msg->getCommand())) + { deleteInstance(msg); msg = nullptr; return nullptr; } + equalSortMsg = equalSortMsg->getNext(); }