Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions GeneralsMD/Code/GameEngine/Include/Common/NameKeyGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ class NameKeyGenerator : public SubsystemInterface
// Get a string out of the INI. Store it into a NameKeyType
static void parseStringAsNameKeyType( INI *ini, void *instance, void *store, const void* userData );

#if RETAIL_COMPATIBLE_CRC
#if RTS_ZEROHOUR
void syncNameKeyID();
#endif
void verifyNameKeyID(UnsignedInt expectedNextID) const;
#endif

private:

enum
Expand All @@ -114,14 +121,6 @@ class NameKeyGenerator : public SubsystemInterface
SOCKET_COUNT = 45007
};

#if RTS_ZEROHOUR && RETAIL_COMPATIBLE_CRC
Bool addReservedKey();
#endif

NameKeyType nameToKeyImpl(const AsciiString& name);
NameKeyType nameToLowercaseKeyImpl(const AsciiString& name);
NameKeyType nameToKeyImpl(const char* name);
NameKeyType nameToLowercaseKeyImpl(const char *name);
NameKeyType createNameKey(UnsignedInt hash, const AsciiString& name);

void freeSockets();
Expand Down
14 changes: 14 additions & 0 deletions GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,11 @@ void GameEngine::init()
#endif/////////////////////////////////////////////////////////////////////////////////////////////


#if RETAIL_COMPATIBLE_CRC
if (xferCRC.getCRC() == 0xA1E7F8E6)
TheNameKeyGenerator->verifyNameKeyID(1);
#endif

initSubsystem(TheScienceStore,"TheScienceStore", MSGNEW("GameEngineSubsystem") ScienceStore(), &xferCRC, "Data\\INI\\Default\\Science", "Data\\INI\\Science");
initSubsystem(TheMultiplayerSettings,"TheMultiplayerSettings", MSGNEW("GameEngineSubsystem") MultiplayerSettings(), &xferCRC, "Data\\INI\\Default\\Multiplayer", "Data\\INI\\Multiplayer");
initSubsystem(TheTerrainTypes,"TheTerrainTypes", MSGNEW("GameEngineSubsystem") TerrainTypeCollection(), &xferCRC, "Data\\INI\\Default\\Terrain", "Data\\INI\\Terrain");
Expand All @@ -524,6 +529,10 @@ void GameEngine::init()
if (!TheAudio->isMusicAlreadyLoaded())
setQuitting(TRUE);

#if RTS_ZEROHOUR && RETAIL_COMPATIBLE_CRC
TheNameKeyGenerator->syncNameKeyID();
#endif

#ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
sprintf(Buf,"----------------------------------------------------------------------------After TheAudio = %f seconds",((double)(endTime64-startTime64)/(double)(freq64)));
Expand Down Expand Up @@ -578,6 +587,11 @@ void GameEngine::init()
#endif/////////////////////////////////////////////////////////////////////////////////////////////


#if RETAIL_COMPATIBLE_CRC
if (xferCRC.getCRC() == 0x6209AF6E)
TheNameKeyGenerator->verifyNameKeyID(2265);
#endif

initSubsystem(TheUpgradeCenter,"TheUpgradeCenter", MSGNEW("GameEngineSubsystem") UpgradeCenter, &xferCRC, "Data\\INI\\Default\\Upgrade", "Data\\INI\\Upgrade");
initSubsystem(TheGameClient,"TheGameClient", createGameClient(), nullptr);

Expand Down
79 changes: 18 additions & 61 deletions GeneralsMD/Code/GameEngine/Source/Common/NameKeyGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,72 +123,29 @@ AsciiString NameKeyGenerator::keyToName(NameKeyType key)
}

//-------------------------------------------------------------------------------------------------
#if RTS_ZEROHOUR && RETAIL_COMPATIBLE_CRC
// TheSuperHackers @info xezon 04/09/2025 This key reservation is required for CRC compatibility,
// because the name keys are somehow CRC relevant. It was originally used by the file exist cache
// of the file system in Zero Hour.
Bool NameKeyGenerator::addReservedKey()
#if RETAIL_COMPATIBLE_CRC
#if RTS_ZEROHOUR
// TheSuperHackers @bugfix Caball009 24/02/2026 Originally the game would hash three files
// for the file exist cache of the file system in Zero Hour.
// TheScienceStore and TheUpgradeCenter rely on having the exact same name key IDs across all clients.
// That means that we still need to hash 3 dummy strings to keep the name key IDs synchronized with retail.
void NameKeyGenerator::syncNameKeyID()
{
switch (m_nextID)
{
case 97: nameToLowercaseKeyImpl("Data\\English\\Language9x.ini"); return true;
case 98: nameToLowercaseKeyImpl("Data\\Audio\\Tracks\\English\\GLA_02.mp3"); return true;
case 99: nameToLowercaseKeyImpl("Data\\Audio\\Tracks\\GLA_02.mp3"); return true;
}
return false;
nameToLowercaseKey("Data\\English\\Language9x.ini");
nameToLowercaseKey("Data\\Audio\\Tracks\\English\\GLA_02.mp3");
nameToLowercaseKey("Data\\Audio\\Tracks\\GLA_02.mp3");
}
#endif

//-------------------------------------------------------------------------------------------------
NameKeyType NameKeyGenerator::nameToKey(const AsciiString& name)
void NameKeyGenerator::verifyNameKeyID(UnsignedInt expectedNextID) const
{
const NameKeyType key = nameToKeyImpl(name);

#if RTS_ZEROHOUR && RETAIL_COMPATIBLE_CRC
while (addReservedKey());
#endif

return key;
// this should only be called before the initialization of TheScienceStore and TheUpgradeCenter in GameEngine::init
DEBUG_ASSERTCRASH(expectedNextID == m_nextID,
("Retail client expects items to start with name key ID %d for unmodded files, but starts with %d", expectedNextID, m_nextID));
}

//-------------------------------------------------------------------------------------------------
NameKeyType NameKeyGenerator::nameToLowercaseKey(const AsciiString& name)
{
const NameKeyType key = nameToLowercaseKeyImpl(name);

#if RTS_ZEROHOUR && RETAIL_COMPATIBLE_CRC
while (addReservedKey());
#endif

return key;
}

//-------------------------------------------------------------------------------------------------
NameKeyType NameKeyGenerator::nameToKey(const char* name)
{
const NameKeyType key = nameToKeyImpl(name);

#if RTS_ZEROHOUR && RETAIL_COMPATIBLE_CRC
while (addReservedKey());
#endif

return key;
}

//-------------------------------------------------------------------------------------------------
NameKeyType NameKeyGenerator::nameToLowercaseKey(const char *name)
{
const NameKeyType key = nameToLowercaseKeyImpl(name);

#if RTS_ZEROHOUR && RETAIL_COMPATIBLE_CRC
while (addReservedKey());
#endif

return key;
}

//-------------------------------------------------------------------------------------------------
NameKeyType NameKeyGenerator::nameToKeyImpl(const AsciiString& name)
NameKeyType NameKeyGenerator::nameToKey(const AsciiString& name)
{
const UnsignedInt hash = calcHashForString(name.str()) % SOCKET_COUNT;

Expand All @@ -205,7 +162,7 @@ NameKeyType NameKeyGenerator::nameToKeyImpl(const AsciiString& name)
}

//-------------------------------------------------------------------------------------------------
NameKeyType NameKeyGenerator::nameToLowercaseKeyImpl(const AsciiString& name)
NameKeyType NameKeyGenerator::nameToLowercaseKey(const AsciiString& name)
{
const UnsignedInt hash = calcHashForLowercaseString(name.str()) % SOCKET_COUNT;

Expand All @@ -222,7 +179,7 @@ NameKeyType NameKeyGenerator::nameToLowercaseKeyImpl(const AsciiString& name)
}

//-------------------------------------------------------------------------------------------------
NameKeyType NameKeyGenerator::nameToKeyImpl(const char* name)
NameKeyType NameKeyGenerator::nameToKey(const char* name)
{
const UnsignedInt hash = calcHashForString(name) % SOCKET_COUNT;

Expand All @@ -239,7 +196,7 @@ NameKeyType NameKeyGenerator::nameToKeyImpl(const char* name)
}

//-------------------------------------------------------------------------------------------------
NameKeyType NameKeyGenerator::nameToLowercaseKeyImpl(const char* name)
NameKeyType NameKeyGenerator::nameToLowercaseKey(const char *name)
{
const UnsignedInt hash = calcHashForLowercaseString(name) % SOCKET_COUNT;

Expand Down
Loading