Skip to content

bugfix(saveload): Serialize base state machine in TurretStateMachine and DozerActionStateMachine#2896

Merged
xezon merged 3 commits into
TheSuperHackers:mainfrom
bobtista:bobtista/fix/statemachine-xfer-base-state
Jul 22, 2026
Merged

bugfix(saveload): Serialize base state machine in TurretStateMachine and DozerActionStateMachine#2896
xezon merged 3 commits into
TheSuperHackers:mainfrom
bobtista:bobtista/fix/statemachine-xfer-base-state

Conversation

@bobtista

@bobtista bobtista commented Jul 19, 2026

Copy link
Copy Markdown

Fixes:

  • Turret state machines revert to their default state after loading a save game
  • Dozer action state machines revert to their default state after loading a save game

TurretStateMachine::xfer and DozerActionStateMachine::xfer override the base but never call StateMachine::xfer, so the active state ID, sleep timer, goal, and lock flag are never serialized. On load the machine snaps back to its default state.

Now both chain to StateMachine::xfer/loadPostProcess, matching every other state-machine subclass. Bumped to version 2 and gated the base call so existing version-1 saves still load. Audited all 18 StateMachine subclasses — these two were the only ones missing it.

Todo:

  • Replicate to Generals

@greptile-apps

greptile-apps Bot commented Jul 19, 2026

Copy link
Copy Markdown

Greptile Summary

Fixes missing StateMachine::xfer / loadPostProcess chains in TurretStateMachine and DozerActionStateMachine, which caused both machines to silently snap back to their default state on save-game load. The fix is applied symmetrically to both the Generals/ and GeneralsMD/ codebases (note: the PR description's "Todo: Replicate to Generals" checkbox is already completed in this diff).

  • Both xfer overrides are bumped to version 2 and call StateMachine::xfer inside a version >= 2 guard, preserving backward compatibility with existing version-1 saves and retail-compatible saves (RETAIL_COMPATIBLE_XFER_SAVE keeps the version at 1).
  • Both loadPostProcess overrides now chain to StateMachine::loadPostProcess() unconditionally; the base implementation is a no-op, so this is safe for all save versions.
  • The pattern matches every other corrected state-machine subclass in the codebase (e.g., AIGuard, AITNGuard, AIGuardRetaliate).

Confidence Score: 5/5

Safe to merge — the change strictly adds missing base-class chaining behind a version guard, leaving all existing save files loadable without any behavioral change.

The version bump is correctly gated so v1 saves continue to load as before. The RETAIL_COMPATIBLE_XFER_SAVE guard preserves retail-save compatibility. StateMachine::loadPostProcess is a no-op, making the unconditional chain in both overrides harmless. The same pattern is already established across other corrected subclasses in the codebase. Both codebases (Generals and GeneralsMD) are updated consistently.

No files require special attention.

Important Files Changed

Filename Overview
GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp Bumps TurretStateMachine xfer to version 2; gates StateMachine::xfer call behind version >= 2 guard; adds StateMachine::loadPostProcess chain
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp Bumps DozerActionStateMachine xfer to version 2; gates StateMachine::xfer after existing m_task xfer; adds StateMachine::loadPostProcess chain
Generals/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp Mirror of GeneralsMD fix — identical version bump and base-xfer chain for TurretStateMachine
Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp Mirror of GeneralsMD fix — identical version bump and base-xfer chain for DozerActionStateMachine

Sequence Diagram

sequenceDiagram
    participant Caller
    participant DerivedSM as TurretStateMachine / DozerActionStateMachine
    participant BaseSM as StateMachine

    Note over Caller,BaseSM: Save (version 2)
    Caller->>DerivedSM: xfer(xfer)
    DerivedSM->>DerivedSM: "xferVersion(&version, 2)"
    DerivedSM->>DerivedSM: "xferUser(&m_task) [DozerOnly]"
    DerivedSM->>BaseSM: "StateMachine::xfer(xfer) [version>=2]"
    BaseSM->>BaseSM: "xferVersion(&v, 1)"
    BaseSM->>BaseSM: xfer sleepTill, defaultStateID, curStateID, snapshot, goal, lock

    Note over Caller,BaseSM: Load (version 2)
    Caller->>DerivedSM: xfer(xfer)
    DerivedSM->>DerivedSM: xferVersion reads 2
    DerivedSM->>DerivedSM: "xferUser(&m_task) [DozerOnly]"
    DerivedSM->>BaseSM: "StateMachine::xfer(xfer) [version>=2]"
    BaseSM->>BaseSM: restores m_currentState, goal, lock

    Note over Caller,BaseSM: Load (version 1 - legacy save)
    Caller->>DerivedSM: xfer(xfer)
    DerivedSM->>DerivedSM: xferVersion reads 1
    DerivedSM->>DerivedSM: "xferUser(&m_task) [DozerOnly]"
    Note over DerivedSM: base xfer skipped - machine resets to default (old behaviour preserved)

    Note over Caller,BaseSM: loadPostProcess (all versions)
    Caller->>DerivedSM: loadPostProcess()
    DerivedSM->>BaseSM: StateMachine::loadPostProcess() [no-op]
Loading

Reviews (5): Last reviewed commit: "fix(savegame): serialize base StateMachi..." | Re-trigger Greptile

@bobtista bobtista self-assigned this Jul 19, 2026
@bobtista bobtista added the Bug Something is not working right, typically is user facing label Jul 19, 2026
Comment thread GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp Outdated
@Caball009 Caball009 added Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Saveload Is Saveload/Xfer related labels Jul 19, 2026

@Skyaero42 Skyaero42 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find

@xezon xezon left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I observed save bug in USA 02: after save (not load) the Aircraft Carrier loses its target. Will this change fix that?

Comment thread GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp
@bobtista
bobtista force-pushed the bobtista/fix/statemachine-xfer-base-state branch from c4742a5 to 1bba86b Compare July 20, 2026 22:19
@bobtista

Copy link
Copy Markdown
Author

I observed save bug in USA 02: after save (not load) the Aircraft Carrier loses its target. Will this change fix that?

is there an issue and repro steps you can point me to?

@xezon

xezon commented Jul 21, 2026

Copy link
Copy Markdown

is there an issue and repro steps you can point me to?

Repro:

  • Load USA 02
  • Select Air Craft Carrier
  • Force Fire terrain (see planes attacking relentlessly)
  • Save Game (No Load)
  • Observe planes

Result:

Planes stop attacking target.

@xezon xezon left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

@bobtista

Copy link
Copy Markdown
Author

is there an issue and repro steps you can point me to?

Repro:

  • Load USA 02
  • Select Air Craft Carrier
  • Force Fire terrain (see planes attacking relentlessly)
  • Save Game (No Load)
  • Observe planes

Result:

Planes stop attacking target.

#2996 :)

@xezon

xezon commented Jul 22, 2026

Copy link
Copy Markdown

Needs to be replicated to Generals.

@xezon xezon changed the title fix(savegame): serialize base StateMachine state in Turret and Dozer action state machines bugfix(savegame): Serialize base state machine in TurretStateMachine and DozerActionStateMachine Jul 22, 2026
@xezon xezon changed the title bugfix(savegame): Serialize base state machine in TurretStateMachine and DozerActionStateMachine bugfix(ai): Serialize base state machine in TurretStateMachine and DozerActionStateMachine Jul 22, 2026
@xezon xezon changed the title bugfix(ai): Serialize base state machine in TurretStateMachine and DozerActionStateMachine bugfix(saveload): Serialize base state machine in TurretStateMachine and DozerActionStateMachine Jul 22, 2026
@xezon
xezon merged commit 84e7402 into TheSuperHackers:main Jul 22, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Something is not working right, typically is user facing Gen Relates to Generals Minor Severity: Minor < Major < Critical < Blocker Saveload Is Saveload/Xfer related ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants