From efe4c5d6c198425e151330dfc8ae71481a8a7057 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Sun, 1 Mar 2026 15:45:38 +0100 Subject: [PATCH 1/6] fix(skirmish): Improve determinism for restarted games by resetting randomized slot values. --- .../GameEngine/Include/GameNetwork/GameInfo.h | 3 ++- .../Source/GameNetwork/GameInfo.cpp | 25 +++++++++++++------ .../Source/GameLogic/System/GameLogic.cpp | 9 ++++++- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/Core/GameEngine/Include/GameNetwork/GameInfo.h b/Core/GameEngine/Include/GameNetwork/GameInfo.h index d17a3bd3c12..f4904be9ed3 100644 --- a/Core/GameEngine/Include/GameNetwork/GameInfo.h +++ b/Core/GameEngine/Include/GameNetwork/GameInfo.h @@ -100,7 +100,7 @@ class GameSlot void setNATBehavior( FirewallHelperClass::FirewallBehaviorType NATBehavior) { m_NATBehavior = NATBehavior; } FirewallHelperClass::FirewallBehaviorType getNATBehavior() const { return m_NATBehavior; } - void saveOffOriginalInfo(); + Bool saveOffOriginalInfo(); Int getOriginalPlayerTemplate() const { return m_origPlayerTemplate; } Int getOriginalColor() const { return m_origColor; } Int getOriginalStartPos() const { return m_origStartPos; } @@ -130,6 +130,7 @@ class GameSlot Bool m_isAccepted; Bool m_hasMap; Bool m_isMuted; + Bool m_saveOffOriginalInfo; Int m_color; ///< color, or -1 for random Int m_startPos; ///< start position, or -1 for random Int m_playerTemplate; ///< PlayerTemplate diff --git a/Core/GameEngine/Source/GameNetwork/GameInfo.cpp b/Core/GameEngine/Source/GameNetwork/GameInfo.cpp index 475f51a8683..c24b0f7a734 100644 --- a/Core/GameEngine/Source/GameNetwork/GameInfo.cpp +++ b/Core/GameEngine/Source/GameNetwork/GameInfo.cpp @@ -70,20 +70,29 @@ void GameSlot::reset() m_disconnected = FALSE; m_port = 0; m_isMuted = FALSE; + m_saveOffOriginalInfo = TRUE; m_origPlayerTemplate = -1; m_origStartPos = -1; m_origColor = -1; } -void GameSlot::saveOffOriginalInfo() +Bool GameSlot::saveOffOriginalInfo() { - DEBUG_LOG(("GameSlot::saveOffOriginalInfo() - orig was color=%d, pos=%d, house=%d", - m_origColor, m_origStartPos, m_origPlayerTemplate)); - m_origPlayerTemplate = m_playerTemplate; - m_origStartPos = m_startPos; - m_origColor = m_color; - DEBUG_LOG(("GameSlot::saveOffOriginalInfo() - color=%d, pos=%d, house=%d", - m_color, m_startPos, m_playerTemplate)); + if (m_saveOffOriginalInfo) + { + DEBUG_LOG(("GameSlot::saveOffOriginalInfo() - orig was color=%d, pos=%d, house=%d", + m_origColor, m_origStartPos, m_origPlayerTemplate)); + m_origPlayerTemplate = m_playerTemplate; + m_origStartPos = m_startPos; + m_origColor = m_color; + DEBUG_LOG(("GameSlot::saveOffOriginalInfo() - color=%d, pos=%d, house=%d", + m_color, m_startPos, m_playerTemplate)); + + m_saveOffOriginalInfo = FALSE; + return TRUE; + } + + return FALSE; } static Int getSlotIndex(const GameSlot *slot) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 21474009798..5052766099e 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -1241,7 +1241,14 @@ void GameLogic::startNewGame( Bool loadingSaveGame ) { GameSlot *slot = TheGameInfo->getSlot(i); if (!loadingSaveGame) { - slot->saveOffOriginalInfo(); + if (!slot->saveOffOriginalInfo()) + { + // TheSuperHackers @fix Caball009 02/03/2026 Random color, position and faction are based on the logical seed. For improved determinism, + // restarted games should set the original values so that the games start with the exact same logical seed values as the first time. + slot->setColor(slot->getOriginalColor()); + slot->setStartPos(slot->getOriginalStartPos()); + slot->setPlayerTemplate(slot->getOriginalPlayerTemplate()); + } } if (slot->isAI()) { From 60e9d4116190136cab1851e77d23b21bd6bb6171 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Sun, 1 Mar 2026 15:47:03 +0100 Subject: [PATCH 2/6] Added assertion. --- .../Code/GameEngine/Source/GameLogic/System/GameLogic.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 5052766099e..4bbadc8512d 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -1243,6 +1243,8 @@ void GameLogic::startNewGame( Bool loadingSaveGame ) if (!loadingSaveGame) { if (!slot->saveOffOriginalInfo()) { + DEBUG_ASSERTCRASH(m_gameMode == GAME_SKIRMISH, ("Expected skirmish game mode but got %d", m_gameMode)); + // TheSuperHackers @fix Caball009 02/03/2026 Random color, position and faction are based on the logical seed. For improved determinism, // restarted games should set the original values so that the games start with the exact same logical seed values as the first time. slot->setColor(slot->getOriginalColor()); From fafaa32ab13279e7691d4f786009f89fd87fb86e Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Thu, 19 Mar 2026 14:33:29 +0100 Subject: [PATCH 3/6] Updated comment date. --- .../Code/GameEngine/Source/GameLogic/System/GameLogic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index c63bea052c3..67887829156 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -1245,7 +1245,7 @@ void GameLogic::startNewGame( Bool loadingSaveGame ) { DEBUG_ASSERTCRASH(m_gameMode == GAME_SKIRMISH, ("Expected skirmish game mode but got %d", m_gameMode)); - // TheSuperHackers @fix Caball009 02/03/2026 Random color, position and faction are based on the logical seed. For improved determinism, + // TheSuperHackers @fix Caball009 19/03/2026 Random color, position and faction are based on the logical seed. For improved determinism, // restarted games should set the original values so that the games start with the exact same logical seed values as the first time. slot->setColor(slot->getOriginalColor()); slot->setStartPos(slot->getOriginalStartPos()); From b020a5f98a16795a79a98d08dd9b2b06724342b5 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Sat, 21 Mar 2026 13:18:58 +0100 Subject: [PATCH 4/6] Tweaked comment. --- .../Code/GameEngine/Source/GameLogic/System/GameLogic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 67887829156..c066e80e12d 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -1246,7 +1246,7 @@ void GameLogic::startNewGame( Bool loadingSaveGame ) DEBUG_ASSERTCRASH(m_gameMode == GAME_SKIRMISH, ("Expected skirmish game mode but got %d", m_gameMode)); // TheSuperHackers @fix Caball009 19/03/2026 Random color, position and faction are based on the logical seed. For improved determinism, - // restarted games should set the original values so that the games start with the exact same logical seed values as the first time. + // restarted games now set the original values so that the games start with the exact same logical seed values as the first time. slot->setColor(slot->getOriginalColor()); slot->setStartPos(slot->getOriginalStartPos()); slot->setPlayerTemplate(slot->getOriginalPlayerTemplate()); From 1132ca069bc48314bb0502c6ca7465c0805cb3d3 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Sat, 21 Mar 2026 13:36:18 +0100 Subject: [PATCH 5/6] Added 'gameModeToString' function. --- .../GameEngine/Include/GameLogic/GameLogic.h | 2 ++ .../Source/GameLogic/System/GameLogic.cpp | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h index 160d1dbd4cf..aef22d49ffb 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h @@ -79,6 +79,8 @@ enum GameMode CPP_11(: Int) GAME_NONE }; +const char* gameModeToString(GameMode mode); + enum { CRC_CACHED, diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index c066e80e12d..80d2eb18db8 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -213,6 +213,30 @@ void setFPMode() _controlfp(newVal, _MCW_PC | _MCW_RC); } +//------------------------------------------------------------------------------------------------- +const char* gameModeToString(GameMode mode) +{ + switch (mode) + { + case GAME_SINGLE_PLAYER: + return "GAME_SINGLE_PLAYER"; + case GAME_LAN: + return "GAME_LAN"; + case GAME_SKIRMISH: + return "GAME_SKIRMISH"; + case GAME_REPLAY: + return "GAME_REPLAY"; + case GAME_SHELL: + return "GAME_SHELL"; + case GAME_INTERNET: + return "GAME_INTERNET"; + case GAME_NONE: + return "GAME_NONE"; + default: + return "GAME_UNKNOWN"; + } +} + // ------------------------------------------------------------------------------------------------ /** GameLogic class constructor */ // ------------------------------------------------------------------------------------------------ From 6c21148ec262e0aa6dab3b7dac5fd59fd0294fae Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Sat, 21 Mar 2026 13:36:32 +0100 Subject: [PATCH 6/6] Tweaked debug assertion. --- .../Code/GameEngine/Source/GameLogic/System/GameLogic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 80d2eb18db8..b150503d13e 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -1267,7 +1267,7 @@ void GameLogic::startNewGame( Bool loadingSaveGame ) if (!loadingSaveGame) { if (!slot->saveOffOriginalInfo()) { - DEBUG_ASSERTCRASH(m_gameMode == GAME_SKIRMISH, ("Expected skirmish game mode but got %d", m_gameMode)); + DEBUG_ASSERTCRASH(m_gameMode == GAME_SKIRMISH, ("Expected GAME_SKIRMISH but got %s", gameModeToString(m_gameMode))); // TheSuperHackers @fix Caball009 19/03/2026 Random color, position and faction are based on the logical seed. For improved determinism, // restarted games now set the original values so that the games start with the exact same logical seed values as the first time.