fix(skirmish): Improve determinism for restarted games by resetting slot values#2373
fix(skirmish): Improve determinism for restarted games by resetting slot values#2373Caball009 wants to merge 4 commits intoTheSuperHackers:mainfrom
Conversation
…andomized slot values.
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Include/GameNetwork/GameInfo.h | Adds Bool m_saveOffOriginalInfo member to GameSlot and changes saveOffOriginalInfo() return type from void to Bool; changes are minimal and correct. |
| Core/GameEngine/Source/GameNetwork/GameInfo.cpp | Implements the gate flag: initializes m_saveOffOriginalInfo = TRUE in reset(), saves original values only on the first call, returns TRUE/FALSE to distinguish first-start vs restart; logic is sound. |
| GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp | Uses the new return value to restore original (pre-randomization) slot values on game restart, with a debug assert to flag unexpected non-skirmish restarts; see note about assert firing per-slot in a loop. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[startNewGame called] --> B{loadingSaveGame?}
B -- Yes --> G[Skip slot info logic]
B -- No --> C[Loop over all slots]
C --> D{slot->saveOffOriginalInfo\nreturn value?}
D -- TRUE\nfirst start\nm_saveOffOriginalInfo was TRUE --> E[Original values saved\ncolor/startPos/playerTemplate\nm_saveOffOriginalInfo = FALSE]
D -- FALSE\nrestart\nm_saveOffOriginalInfo was FALSE --> F[DEBUG_ASSERTCRASH if not GAME_SKIRMISH\nRestore slot to original values\nsetColor / setStartPos / setPlayerTemplate]
E --> H[populateRandomSideAndColor]
F --> H
G --> H
H --> I[populateRandomStartPosition]
I --> J[Continue game start...]
Prompt To Fix All With AI
This is a comment left during a code review.
Path: GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp
Line: 1246-1253
Comment:
**Assert fires for every slot, including unoccupied ones**
The outer loop iterates all `MAX_SLOTS` slots unconditionally, so on a skirmish restart the `DEBUG_ASSERTCRASH` (and the restore logic below it) will execute for *every* slot — including `SLOT_CLOSED` / `SLOT_OPEN` slots — rather than only for occupied ones. For empty slots the restore is harmless (values are already `-1`), but the repeated assert is noisy in debug sessions. Consider guarding this block with an occupancy check:
```suggestion
{
DEBUG_ASSERTCRASH(m_gameMode == GAME_SKIRMISH, ("Expected skirmish game mode but got %d", m_gameMode));
if (slot->isOccupied())
{
// 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());
slot->setPlayerTemplate(slot->getOriginalPlayerTemplate());
}
```
How can I resolve this? If you propose a fix, please make it concise.Last reviewed commit: "Updated comment date..."
| slot->saveOffOriginalInfo(); | ||
| if (!slot->saveOffOriginalInfo()) | ||
| { | ||
| DEBUG_ASSERTCRASH(m_gameMode == GAME_SKIRMISH, ("Expected skirmish game mode but got %d", m_gameMode)); |
There was a problem hiding this comment.
Consider adding or using a function to grab strings for game mode.
| } | ||
|
|
||
| void GameSlot::saveOffOriginalInfo() | ||
| Bool GameSlot::saveOffOriginalInfo() |
There was a problem hiding this comment.
What does this mean? saveOffOriginalInfo?
| 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 skirmish games may not start with the same logical seed value as the first start. This depends on whether there are players with a random color / position / faction. Those random values are determined by using and updating the logical seed on the first start, after which the random values are stored. That means that for restarted games the logical seed isn't used or updated for those purposes. This PR resets those values to improve determinism for restarted games.
You can put a breakpoint after
GameLogic::startNewGameand compare the values oftheGameLogicSeedfor the first start and following starts and see how the values for the first start deviate from restarts.TODO: