Skip to content

Commit 9a1b761

Browse files
authored
[GEN][ZH] Implement fake CRC for Generals CD 1.08, Zero Hour CD 1.04 executable compatibility (#965)
This change implements fake exe CRC for Generals CD 1.08 and Zero Hour CD 1.04 and allows VC6 builds to matchmake with retail builds in the Network Lobby and Online Lobby. It also suppresses version mismatch warnings in the Replay Load menu when loading compatible replays.
1 parent f603a12 commit 9a1b761

File tree

5 files changed

+103
-26
lines changed

5 files changed

+103
-26
lines changed

Generals/Code/GameEngine/Include/Common/crc.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ class CRC
4747
// UnsignedInt get( void ) { return htonl(crc); } ///< Get the combined CRC
4848
UnsignedInt get( void );
4949

50+
#if (defined(_MSC_VER) && _MSC_VER < 1300) && defined(RETAIL_COMPATIBLE_CRC)
51+
void set( UnsignedInt v )
52+
{
53+
crc = v;
54+
}
55+
#endif
56+
5057
private:
5158
void addCRC( UnsignedByte val ); ///< CRC a 4-byte block
5259

@@ -120,6 +127,13 @@ class CRC
120127
return crc;
121128
}
122129

130+
#if (defined(_MSC_VER) && _MSC_VER < 1300) && defined(RETAIL_COMPATIBLE_CRC)
131+
void set( UnsignedInt v )
132+
{
133+
crc = v;
134+
}
135+
#endif
136+
123137
private:
124138
UnsignedInt crc;
125139
};

Generals/Code/GameEngine/Source/Common/GlobalData.cpp

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -986,23 +986,42 @@ GlobalData::GlobalData()
986986

987987
// lets CRC the executable! Whee!
988988
const Int blockSize = 65536;
989-
Char buffer[ _MAX_PATH ];
990989
CRC exeCRC;
991-
GetModuleFileName( NULL, buffer, sizeof( buffer ) );
992-
File *fp = TheFileSystem->openFile(buffer, File::READ | File::BINARY);
993-
if (fp != NULL) {
994-
unsigned char crcBlock[blockSize];
995-
Int amtRead = 0;
996-
while ( (amtRead=fp->read(crcBlock, blockSize)) > 0 )
997-
{
998-
exeCRC.computeCRC(crcBlock, amtRead);
990+
File *fp;
991+
// TheSuperHackers @tweak SkyAero/xezon 27/05/2025
992+
// Simulate the EXE's CRC value to force Network and Replay compatibility with another build.
993+
#if (defined(_MSC_VER) && _MSC_VER < 1300) && defined(RETAIL_COMPATIBLE_CRC)
994+
995+
#define GENERALS_108_CD_EXE_CRC 0x93d1eab4
996+
#define GENERALS_108_STEAM_EXE_CRC 0x8d6e4dd7
997+
#define GENERALS_108_EAAPP_EXE_CRC 0xb07fbd50
998+
999+
exeCRC.set(GENERALS_108_CD_EXE_CRC);
1000+
DEBUG_LOG(("Fake EXE CRC is 0x%8.8X\n", exeCRC.get()));
1001+
1002+
#else
1003+
{
1004+
Char buffer[ _MAX_PATH ];
1005+
GetModuleFileName( NULL, buffer, sizeof( buffer ) );
1006+
fp = TheFileSystem->openFile(buffer, File::READ | File::BINARY);
1007+
if (fp != NULL) {
1008+
unsigned char crcBlock[blockSize];
1009+
Int amtRead = 0;
1010+
while ( (amtRead=fp->read(crcBlock, blockSize)) > 0 )
1011+
{
1012+
exeCRC.computeCRC(crcBlock, amtRead);
1013+
}
1014+
DEBUG_LOG(("EXE CRC is 0x%8.8X\n", exeCRC.get()));
1015+
fp->close();
1016+
fp = NULL;
9991017
}
1000-
fp->close();
1001-
fp = NULL;
10021018
}
1019+
#endif
1020+
1021+
UnsignedInt version = 0;
10031022
if (TheVersion)
10041023
{
1005-
UnsignedInt version = TheVersion->getVersionNumber();
1024+
version = TheVersion->getVersionNumber();
10061025
exeCRC.computeCRC( &version, sizeof(UnsignedInt) );
10071026
}
10081027
// Add in MP scripts to the EXE CRC, since the game will go out of sync if they change
@@ -1030,7 +1049,7 @@ GlobalData::GlobalData()
10301049
}
10311050

10321051
m_exeCRC = exeCRC.get();
1033-
DEBUG_LOG(("EXE CRC: 0x%8.8X\n", m_exeCRC));
1052+
DEBUG_LOG(("EXE+Version(%d.%d)+SCB CRC is 0x%8.8X\n", version >> 16, version & 0xffff, m_exeCRC));
10341053

10351054
m_movementPenaltyDamageState = BODY_REALLYDAMAGED;
10361055

Generals/Code/Main/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/GeneratedVersion.h
3535
)
3636

3737
# Based on original binary values for these variables.
38+
if (IS_VS6_BUILD)
39+
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/BuildVersion.h
40+
"#pragma once
41+
42+
#define VERSION_MAJOR 1
43+
#define VERSION_MINOR 7
44+
#define VERSION_BUILDNUM 601
45+
"
46+
)
47+
else()
3848
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/BuildVersion.h
3949
"#pragma once
4050
@@ -43,6 +53,7 @@ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/BuildVersion.h
4353
#define VERSION_BUILDNUM 601
4454
"
4555
)
56+
endif()
4657

4758
target_link_options(g_generals PRIVATE "/NODEFAULTLIB:libci.lib")
4859

GeneralsMD/Code/GameEngine/Include/Common/crc.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ class CRC
4747
// UnsignedInt get( void ) { return htonl(crc); } ///< Get the combined CRC
4848
UnsignedInt get( void );
4949

50+
#if (defined(_MSC_VER) && _MSC_VER < 1300) && defined(RETAIL_COMPATIBLE_CRC)
51+
void set( UnsignedInt v )
52+
{
53+
crc = v;
54+
}
55+
#endif
56+
5057
private:
5158
void addCRC( UnsignedByte val ); ///< CRC a 4-byte block
5259

@@ -120,6 +127,13 @@ class CRC
120127
return crc;
121128
}
122129

130+
#if (defined(_MSC_VER) && _MSC_VER < 1300) && defined(RETAIL_COMPATIBLE_CRC)
131+
void set( UnsignedInt v )
132+
{
133+
crc = v;
134+
}
135+
#endif
136+
123137
private:
124138
UnsignedInt crc;
125139
};

GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -995,23 +995,42 @@ GlobalData::GlobalData()
995995

996996
// lets CRC the executable! Whee!
997997
const Int blockSize = 65536;
998-
Char buffer[ _MAX_PATH ];
999998
CRC exeCRC;
1000-
GetModuleFileName( NULL, buffer, sizeof( buffer ) );
1001-
File *fp = TheFileSystem->openFile(buffer, File::READ | File::BINARY);
1002-
if (fp != NULL) {
1003-
unsigned char crcBlock[blockSize];
1004-
Int amtRead = 0;
1005-
while ( (amtRead=fp->read(crcBlock, blockSize)) > 0 )
1006-
{
1007-
exeCRC.computeCRC(crcBlock, amtRead);
999+
File *fp;
1000+
// TheSuperHackers @tweak SkyAero/xezon 27/05/2025
1001+
// Simulate the EXE's CRC value to force Network and Replay compatibility with another build.
1002+
#if (defined(_MSC_VER) && _MSC_VER < 1300) && defined(RETAIL_COMPATIBLE_CRC)
1003+
1004+
#define GENERALSMD_104_CD_EXE_CRC 0x4f6c5afe
1005+
#define GENERALSMD_104_STEAM_EXE_CRC 0xcb430f5f
1006+
#define GENERALSMD_104_EAAPP_EXE_CRC 0x488d90f9
1007+
1008+
exeCRC.set(GENERALSMD_104_CD_EXE_CRC);
1009+
DEBUG_LOG(("Fake EXE CRC is 0x%8.8X\n", exeCRC.get()));
1010+
1011+
#else
1012+
{
1013+
Char buffer[ _MAX_PATH ];
1014+
GetModuleFileName( NULL, buffer, sizeof( buffer ) );
1015+
fp = TheFileSystem->openFile(buffer, File::READ | File::BINARY);
1016+
if (fp != NULL) {
1017+
unsigned char crcBlock[blockSize];
1018+
Int amtRead = 0;
1019+
while ( (amtRead=fp->read(crcBlock, blockSize)) > 0 )
1020+
{
1021+
exeCRC.computeCRC(crcBlock, amtRead);
1022+
}
1023+
DEBUG_LOG(("EXE CRC is 0x%8.8X\n", exeCRC.get()));
1024+
fp->close();
1025+
fp = NULL;
10081026
}
1009-
fp->close();
1010-
fp = NULL;
10111027
}
1028+
#endif
1029+
1030+
UnsignedInt version = 0;
10121031
if (TheVersion)
10131032
{
1014-
UnsignedInt version = TheVersion->getVersionNumber();
1033+
version = TheVersion->getVersionNumber();
10151034
exeCRC.computeCRC( &version, sizeof(UnsignedInt) );
10161035
}
10171036
// Add in MP scripts to the EXE CRC, since the game will go out of sync if they change
@@ -1039,7 +1058,7 @@ GlobalData::GlobalData()
10391058
}
10401059

10411060
m_exeCRC = exeCRC.get();
1042-
DEBUG_LOG(("EXE CRC: 0x%8.8X\n", m_exeCRC));
1061+
DEBUG_LOG(("EXE+Version(%d.%d)+SCB CRC is 0x%8.8X\n", version >> 16, version & 0xffff, m_exeCRC));
10431062

10441063
m_movementPenaltyDamageState = BODY_REALLYDAMAGED;
10451064

0 commit comments

Comments
 (0)