Skip to content

bugfix(saveload): Restore retail compatibility for Generals save games - #3406

Open
Caball009 wants to merge 5 commits into
TheSuperHackers:mainfrom
Caball009:Caball009/restore_gen_save_game_compatibility
Open

Caball009 wants to merge 5 commits into
TheSuperHackers:mainfrom
Caball009:Caball009/restore_gen_save_game_compatibility

Conversation

@Caball009

@Caball009 Caball009 commented Oct 3, 2026 •

Copy link
Copy Markdown

This PR fixes two issues that broke retail compatibility for Generals save games.

#613 unconditionally bumped the xfer version from 7 to 8, which broke save games created by our client for retail.
#2655 added 3 disabled types to the DisabledType enum as a backport from Zero Hour. This increased DisabledType::DISABLED_COUNT and impacted the xfer logic for Object::m_disabledTillFrame. This broke loading retail save games with our client.

It seems reasonable to (re)use xfer version 8 for both fixes since previous save games created by our clients are not compatible with retail so they might as well be unsupported from here on out.

TODO:

  • Replicate to Zero Hour?

@Caball009 Caball009 added Bug Something is not working right, typically is user facing Major Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ThisProject The issue was introduced by this project, or this task is specific to this project Saveload Is Saveload/Xfer related labels Oct 3, 2026
@coderabbitai

coderabbitai Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f28d7349-6969-4ad0-98f6-f1fbfa7e5f7d
📥 Commits

Reviewing files that changed from the base of the PR and between b362c44 and 5a45bac.

📒 Files selected for processing (1)
  • Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 2 remain after this review.


Walkthrough

Object::xfer selects version 7 for retail-compatible saves and version 8 otherwise. For versions below 8, it serializes status flags using the legacy 29-bit representation. For versions 7 and below, it uses the legacy disabled-frame layout.

Changes

Save Compatibility

Layer / File(s) Summary
Status flag compatibility
Generals/Code/GameEngine/Include/Common/BitFlags.h, Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp
BitFlags::size() is now static and constexpr, and returns NUMBITS. For pre-version-8 status data, Object::xfer masks the serialized value to the lower 29 bits and converts only those bits.
Transfer version and timer serialization
Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp
Object::xfer selects version 7 for retail-compatible saves and version 8 otherwise. For versions 7 and below, it serializes the first eight disabled-frame entries and entries 11 and 12. Later versions serialize the full array.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: omaraglan

Merge Risk: 🟡 Moderate · up to 5a45b

Retail-compatible saves can write invalid object status and change the live object; loading a legacy save can also retain an incorrect status. Fix both paths before merging.

Architecture Summary

Architecture risk: 🔵 Low · up to 5a45b

The change affects 1 system.

Changed systems: Generals

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — Generals (service) was modified; 2 changed files map to changed impact.

Before / after behavior

  • observed — Modified behavior in Generals/Code/GameEngine/Include/Common/BitFlags.h: BitFlags::size() is now static and constexpr, returning NUMBITS instead of the wrapped bitset’s runtime size.
  • observed — Modified behavior in Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp: Object::xfer now documents status and disabled-frame serialization changes and selects version 7 for RETAIL_COMPATIBLE_XFER_SAVE, retaining version 8 otherwise; previously the version was always 8.
  • observed — Modified behavior in Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp: For pre-version-8 status conversion, the code now asserts the expected 29 original status bits plus 16 additional types, masks the serialized value to the lower 29 bits, and converts only those 29 bits. Previously it converted all 32 bits without masking, potentially interpreting unused Generals bits as statuses.
  • observed — Modified behavior in Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp: For versions 7 and below, Object::xfer now transfers the first eight disabled-frame entries and entries 11 and 12 separately, leaving the intervening Zero Hour-only entries out of the legacy format. Newer versions transfer the full array; previously every version transferred the entire array.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Issue #3211 requires retail save loading in Generals. Object::xfer uses version 7 when RETAIL_COMPATIBLE_XFER_SAVE is enabled. For versions below 8, it transfers the original 29 status bits and th…
Out of Scope Changes check ✅ Passed The Object::xfer changes restore legacy save serialization for issue #3211. The BitFlags::size() change supports the compile-time assertion for the Generals status-bit count. No unrelated changes …
Title check ✅ Passed The title clearly summarizes the main change: restoring retail compatibility for Generals save games.
Description check ✅ Passed The description explains the save-game compatibility issues and the fixes addressed by this pull request.
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Critical risk] Changes save game serialization format for a shipped game.

The PR appears safe to merge; no new actionable issue was found.

Summary

The PR restores retail-compatible Generals save transfers by writing object version 7 where configured, mapping object status bits, and preserving the retail disabled-state layout. Since the previous review, only explanatory comments changed.

Reviews (8) · Last reviewed commit: "Addressed feedback (3)."

Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2f8b57be-1908-4c17-9179-d0f2687c49b7
📥 Commits

Reviewing files that changed from the base of the PR and between 2817000 and 04cfa29.

📒 Files selected for processing (1)
  • Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.

Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp
@Caball009
Caball009 marked this pull request as draft October 3, 2026 11:21
@Caball009
Caball009 force-pushed the Caball009/restore_gen_save_game_compatibility branch from 04cfa29 to b362c44 Compare October 3, 2026 11:51

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: efcf6888-4fab-40e8-81db-7df9a38bdeca
📥 Commits

Reviewing files that changed from the base of the PR and between 04cfa29 and b362c44.

📒 Files selected for processing (2)
  • Generals/Code/GameEngine/Include/Common/BitFlags.h
  • Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 2 remain after this review.

Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Outdated
@Caball009
Caball009 force-pushed the Caball009/restore_gen_save_game_compatibility branch 2 times, most recently from 167ab9b to 5a45bac Compare October 3, 2026 12:04
@Caball009
Caball009 marked this pull request as ready for review October 3, 2026 12:11
Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Outdated
@Caball009
Caball009 force-pushed the Caball009/restore_gen_save_game_compatibility branch from 5a45bac to b7be39f Compare October 3, 2026 13:57

@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.

Implementation looks very complicated.

Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Outdated
Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Outdated
Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Outdated
Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Outdated
Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Outdated
Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Outdated
Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Outdated
Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Outdated
Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Outdated
@Caball009
Caball009 force-pushed the Caball009/restore_gen_save_game_compatibility branch from c9ff2f6 to 9269923 Compare October 3, 2026 15:21

@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.

Looking much better now

Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp
Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Outdated
Comment thread Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp
@Caball009
Caball009 force-pushed the Caball009/restore_gen_save_game_compatibility branch from 9be6200 to ea8a75d Compare October 3, 2026 15:49

@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.

What a mess

@xezon

xezon commented Oct 3, 2026

Copy link
Copy Markdown

Need to copy to ZH I think

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 Major Severity: Minor < Major < Critical < Blocker Saveload Is Saveload/Xfer related ThisProject The issue was introduced by this project, or this task is specific to this project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Loading a retail save game is broken in generals.

2 participants