Skip to content

bugfix(namekeys): Remove hardcoded NameKeyIDs from dummy strings for modded files#2349

Open
Caball009 wants to merge 5 commits intoTheSuperHackers:mainfrom
Caball009:fix_retail_namekey_ids
Open

bugfix(namekeys): Remove hardcoded NameKeyIDs from dummy strings for modded files#2349
Caball009 wants to merge 5 commits intoTheSuperHackers:mainfrom
Caball009:fix_retail_namekey_ids

Conversation

@Caball009
Copy link

@Caball009 Caball009 commented Feb 24, 2026

Perhaps it's best to keep the issue open because it touches on a larger issue that this PR does not fix.

#1516 adds three strings with hardcoded name key IDs. This PR fixes the following issue:

Unfortunately, hardcoding the IDs doesn't work for modded files. This became apparent after this replay started to mismatch after #1516 at 4:00: TEOD_0986_P11.zip mod files This mod expects the three strings to have IDs 265 - 267.

I've added a second commit with debug assertions for the correct name key ID with unmodded files to help us detect undesirable additions or removals of name keys.

TODO:

  • Check hash and name key ID values for Generals.
  • Replicate in Generals.

@Caball009 Caball009 added Bug Something is not working right, typically is user facing Major Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour ThisProject The issue was introduced by this project, or this task is specific to this project labels Feb 24, 2026
@Caball009 Caball009 changed the title Fix retail namekey ids bugfix(namekeys): Remove hardcoded NameKeyIDs from dummy strings for modded files Feb 24, 2026
@Caball009 Caball009 marked this pull request as ready for review February 28, 2026 15:26
@greptile-apps
Copy link

greptile-apps bot commented Feb 28, 2026

Greptile Summary

This PR fixes a replay desync bug for modded Zero Hour files by replacing the hardcoded name key ID reservations (IDs 97–99) introduced in #1516 with an explicit, position-based syncNameKeyID() call placed after TheAudio initialization. It also adds verifyNameKeyID() debug assertions guarded by CRC checks to help detect unintended additions or removals of name keys in unmodded builds.

Key changes:

  • Removes the reactive addReservedKey() mechanism that forcefully injected three dummy file-system strings at fixed IDs 97–99 after every nameToKey / nameToLowercaseKey call; mods could shift those IDs to 265–267 (or elsewhere), causing client mismatches.
  • Renames the internal nameToKeyImpl / nameToLowercaseKeyImpl private methods back to the public nameToKey / nameToLowercaseKey names now that the wrapper layer that called addReservedKey() is no longer needed.
  • Adds syncNameKeyID() (Zero Hour + RETAIL_COMPATIBLE_CRC only), called once at a deterministic point in GameEngine::init(), to allocate the three dummy strings at whatever IDs naturally follow the current load state — making the fix transparent to mods.
  • Adds two CRC-guarded verifyNameKeyID() debug assertions in GameEngine::init() (before TheScienceStore expecting ID 1, and before TheUpgradeCenter expecting ID 2265) to catch future regressions in unmodded builds.
  • Generals support remains a TODO per the PR description.

Confidence Score: 4/5

  • This PR safely fixes the hardcoded name key ID bug for modded files without causing functional regressions for vanilla builds.
  • The core logic is sound: replacing reactive ID injection with a single explicit syncNameKeyID() call at a stable init point correctly addresses the mod compatibility issue. The CRC guards on verifyNameKeyID() prevent false assertions on mods or Generals builds. One minor comment clarification suggestion on verifyNameKeyID() (line 141) improves precision but doesn't affect safety. The known incomplete item (Generals support) is clearly documented in the PR TODO and does not affect the Zero Hour fix.
  • GeneralsMD/Code/GameEngine/Source/Common/NameKeyGenerator.cpp — minor comment clarity improvement recommended for line 141 to disambiguate the valid call sites.

Sequence Diagram

sequenceDiagram
    participant GE as GameEngine::init()
    participant NKG as NameKeyGenerator
    participant SS as TheScienceStore
    participant AU as TheAudio
    participant TF as TheThingFactory
    participant UC as TheUpgradeCenter

    GE->>NKG: verifyNameKeyID(1) [if CRC==0xA1E7F8E6]
    Note over NKG: DEBUG_ASSERTCRASH m_nextID==1
    GE->>SS: initSubsystem (allocates name keys)
    GE->>AU: initSubsystem
    GE->>NKG: syncNameKeyID() [ZH + RETAIL_COMPATIBLE_CRC]
    Note over NKG: nameToLowercaseKey("Data\\English\\Language9x.ini")<br/>nameToLowercaseKey("Data\\Audio\\Tracks\\English\\GLA_02.mp3")<br/>nameToLowercaseKey("Data\\Audio\\Tracks\\GLA_02.mp3")
    GE->>TF: initSubsystem (allocates more name keys)
    GE->>NKG: verifyNameKeyID(2265) [if CRC==0x6209AF6E]
    Note over NKG: DEBUG_ASSERTCRASH m_nextID==2265
    GE->>UC: initSubsystem
Loading

Last reviewed commit: 1159e66

Copy link

@xezon xezon left a comment

Choose a reason for hiding this comment

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

Looks plausible. Needs to be replicated to Generals.

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 ThisProject The issue was introduced by this project, or this task is specific to this project ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants