Skip to content

Commit d31c6c5

Browse files
authored
fix(skirmish): Improve determinism for restarted games by resetting slot values (TheSuperHackers#2373)
1 parent f3fb705 commit d31c6c5

File tree

6 files changed

+90
-7
lines changed

6 files changed

+90
-7
lines changed

Core/GameEngine/Include/GameNetwork/GameInfo.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ class GameSlot
100100
void setNATBehavior( FirewallHelperClass::FirewallBehaviorType NATBehavior) { m_NATBehavior = NATBehavior; }
101101
FirewallHelperClass::FirewallBehaviorType getNATBehavior() const { return m_NATBehavior; }
102102

103-
void saveOffOriginalInfo();
103+
void saveOriginalSetup();
104+
Bool hasSavedOriginalSetup() const { return m_hasSavedOriginalSetup; }
104105
Int getOriginalPlayerTemplate() const { return m_origPlayerTemplate; }
105106
Int getOriginalColor() const { return m_origColor; }
106107
Int getOriginalStartPos() const { return m_origStartPos; }
@@ -130,6 +131,7 @@ class GameSlot
130131
Bool m_isAccepted;
131132
Bool m_hasMap;
132133
Bool m_isMuted;
134+
Bool m_hasSavedOriginalSetup;
133135
Int m_color; ///< color, or -1 for random
134136
Int m_startPos; ///< start position, or -1 for random
135137
Int m_playerTemplate; ///< PlayerTemplate

Core/GameEngine/Source/GameNetwork/GameInfo.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,23 @@ void GameSlot::reset()
7070
m_disconnected = FALSE;
7171
m_port = 0;
7272
m_isMuted = FALSE;
73+
m_hasSavedOriginalSetup = FALSE;
7374
m_origPlayerTemplate = -1;
7475
m_origStartPos = -1;
7576
m_origColor = -1;
7677
}
7778

78-
void GameSlot::saveOffOriginalInfo()
79+
void GameSlot::saveOriginalSetup()
7980
{
80-
DEBUG_LOG(("GameSlot::saveOffOriginalInfo() - orig was color=%d, pos=%d, house=%d",
81+
DEBUG_LOG(("GameSlot::saveOriginalSetup() - orig was color=%d, pos=%d, house=%d",
8182
m_origColor, m_origStartPos, m_origPlayerTemplate));
8283
m_origPlayerTemplate = m_playerTemplate;
8384
m_origStartPos = m_startPos;
8485
m_origColor = m_color;
85-
DEBUG_LOG(("GameSlot::saveOffOriginalInfo() - color=%d, pos=%d, house=%d",
86+
DEBUG_LOG(("GameSlot::saveOriginalSetup() - color=%d, pos=%d, house=%d",
8687
m_color, m_startPos, m_playerTemplate));
88+
89+
m_hasSavedOriginalSetup = TRUE;
8790
}
8891

8992
static Int getSlotIndex(const GameSlot *slot)
@@ -1597,7 +1600,7 @@ void SkirmishGameInfo::xfer( Xfer *xfer )
15971600
m_slot[slot]->setPlayerTemplate(origPlayerTemplate);
15981601
m_slot[slot]->setStartPos(origStartPos);
15991602
m_slot[slot]->setColor(origColor);
1600-
m_slot[slot]->saveOffOriginalInfo();
1603+
m_slot[slot]->saveOriginalSetup();
16011604

16021605
m_slot[slot]->setTeamNumber(teamNumber);
16031606
m_slot[slot]->setColor(color);

Generals/Code/GameEngine/Include/GameLogic/GameLogic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ enum GameMode CPP_11(: Int)
7878
GAME_NONE
7979
};
8080

81+
const char* toString(GameMode mode);
82+
8183
enum
8284
{
8385
CRC_CACHED,

Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,30 @@ void setFPMode()
202202
_controlfp(newVal, _MCW_PC | _MCW_RC);
203203
}
204204

205+
//-------------------------------------------------------------------------------------------------
206+
const char* toString(GameMode mode)
207+
{
208+
switch (mode)
209+
{
210+
case GAME_SINGLE_PLAYER:
211+
return "GAME_SINGLE_PLAYER";
212+
case GAME_LAN:
213+
return "GAME_LAN";
214+
case GAME_SKIRMISH:
215+
return "GAME_SKIRMISH";
216+
case GAME_REPLAY:
217+
return "GAME_REPLAY";
218+
case GAME_SHELL:
219+
return "GAME_SHELL";
220+
case GAME_INTERNET:
221+
return "GAME_INTERNET";
222+
case GAME_NONE:
223+
return "GAME_NONE";
224+
default:
225+
return "GAME_UNKNOWN";
226+
}
227+
}
228+
205229
// ------------------------------------------------------------------------------------------------
206230
/** GameLogic class constructor */
207231
// ------------------------------------------------------------------------------------------------
@@ -1081,7 +1105,20 @@ void GameLogic::startNewGame( Bool loadingSaveGame )
10811105
{
10821106
GameSlot *slot = TheGameInfo->getSlot(i);
10831107
if (!loadingSaveGame) {
1084-
slot->saveOffOriginalInfo();
1108+
if (slot->hasSavedOriginalSetup())
1109+
{
1110+
DEBUG_ASSERTCRASH(m_gameMode == GAME_SKIRMISH, ("Expected GAME_SKIRMISH but got %s", toString(m_gameMode)));
1111+
1112+
// TheSuperHackers @fix Caball009 19/03/2026 Random color, position and faction are based on the logical seed. For improved determinism,
1113+
// restarted games now set the original values so that the games start with the exact same logical seed values as the first time.
1114+
slot->setColor(slot->getOriginalColor());
1115+
slot->setStartPos(slot->getOriginalStartPos());
1116+
slot->setPlayerTemplate(slot->getOriginalPlayerTemplate());
1117+
}
1118+
else
1119+
{
1120+
slot->saveOriginalSetup();
1121+
}
10851122
}
10861123
if (slot->isAI())
10871124
{

GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ enum GameMode CPP_11(: Int)
7979
GAME_NONE
8080
};
8181

82+
const char* toString(GameMode mode);
83+
8284
enum
8385
{
8486
CRC_CACHED,

GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,30 @@ void setFPMode()
213213
_controlfp(newVal, _MCW_PC | _MCW_RC);
214214
}
215215

216+
//-------------------------------------------------------------------------------------------------
217+
const char* toString(GameMode mode)
218+
{
219+
switch (mode)
220+
{
221+
case GAME_SINGLE_PLAYER:
222+
return "GAME_SINGLE_PLAYER";
223+
case GAME_LAN:
224+
return "GAME_LAN";
225+
case GAME_SKIRMISH:
226+
return "GAME_SKIRMISH";
227+
case GAME_REPLAY:
228+
return "GAME_REPLAY";
229+
case GAME_SHELL:
230+
return "GAME_SHELL";
231+
case GAME_INTERNET:
232+
return "GAME_INTERNET";
233+
case GAME_NONE:
234+
return "GAME_NONE";
235+
default:
236+
return "GAME_UNKNOWN";
237+
}
238+
}
239+
216240
// ------------------------------------------------------------------------------------------------
217241
/** GameLogic class constructor */
218242
// ------------------------------------------------------------------------------------------------
@@ -1241,7 +1265,20 @@ void GameLogic::startNewGame( Bool loadingSaveGame )
12411265
{
12421266
GameSlot *slot = TheGameInfo->getSlot(i);
12431267
if (!loadingSaveGame) {
1244-
slot->saveOffOriginalInfo();
1268+
if (slot->hasSavedOriginalSetup())
1269+
{
1270+
DEBUG_ASSERTCRASH(m_gameMode == GAME_SKIRMISH, ("Expected GAME_SKIRMISH but got %s", toString(m_gameMode)));
1271+
1272+
// TheSuperHackers @fix Caball009 19/03/2026 Random color, position and faction are based on the logical seed. For improved determinism,
1273+
// restarted games now set the original values so that the games start with the exact same logical seed values as the first time.
1274+
slot->setColor(slot->getOriginalColor());
1275+
slot->setStartPos(slot->getOriginalStartPos());
1276+
slot->setPlayerTemplate(slot->getOriginalPlayerTemplate());
1277+
}
1278+
else
1279+
{
1280+
slot->saveOriginalSetup();
1281+
}
12451282
}
12461283
if (slot->isAI())
12471284
{

0 commit comments

Comments
 (0)