Skip to content

Commit 2bf436a

Browse files
committed
feat(replay): Check CRC messages from all players in replays.
1 parent 20f4254 commit 2bf436a

9 files changed

Lines changed: 328 additions & 157 deletions

File tree

Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2055,12 +2055,14 @@ void GameLogic::logicMessageDispatcher( GameMessage *msg, void *userData )
20552055
break;
20562056
}
20572057

2058-
20592058
//---------------------------------------------------------------------------------------------
20602059
case GameMessage::MSG_LOGIC_CRC:
20612060
{
20622061
if (TheNetwork)
20632062
{
2063+
if (TheNetwork->sawCRCMismatch())
2064+
break;
2065+
20642066
Int slotIndex = -1;
20652067
for (Int i=0; i<MAX_SLOTS; ++i)
20662068
{
@@ -2079,29 +2081,44 @@ void GameLogic::logicMessageDispatcher( GameMessage *msg, void *userData )
20792081
#if defined(RTS_DEBUG)
20802082
// don't even put this in release, cause someone might hack it.
20812083
if (!TheDebugIgnoreSyncErrors)
2082-
{
2083-
#endif
2084-
m_shouldValidateCRCs = TRUE;
2085-
#if defined(RTS_DEBUG)
2086-
}
20872084
#endif
2085+
m_validationModeCRC = CRCMODE_NETWORK;
20882086
}
20892087

2090-
UnsignedInt newCRC = msg->getArgument(0)->integer;
2088+
const UnsignedInt newCRC = msg->getArgument(0)->integer;
20912089
//DEBUG_LOG(("Received CRC of %8.8X from %ls on frame %d", newCRC,
20922090
//msgPlayer->getPlayerDisplayName().str(), m_frame));
2091+
20932092
m_cachedCRCs[msgPlayer->getPlayerIndex()] = newCRC;
20942093
}
20952094
else if (TheRecorder && TheRecorder->isPlaybackMode())
20962095
{
2097-
UnsignedInt newCRC = msg->getArgument(0)->integer;
2098-
//DEBUG_LOG(("Saw CRC of %X from player %d. Our CRC is %X. Arg count is %d",
2096+
if (TheRecorder->sawCRCMismatch())
2097+
break;
2098+
2099+
DEBUG_ASSERTCRASH(msg->getArgument(1)->boolean == msgPlayer->isLocalPlayer(),
2100+
("CRC message origin is unexpected; playback message argument doesn't match message player index"));
2101+
2102+
const UnsignedInt newCRC = msg->getArgument(0)->integer;
2103+
//DEBUG_LOG(("Saw CRC of %X from player %d. Our CRC is %X. Arg count is %d",
20992104
//newCRC, msgPlayer->getPlayerIndex(), getCRC(), msg->getArgumentCount()));
21002105

2101-
TheRecorder->handleCRCMessage(newCRC, msgPlayer->getPlayerIndex(), (msg->getArgument(1)->boolean));
2106+
if (msgPlayer->isLocalPlayer())
2107+
{
2108+
TheRecorder->handlePlaybackCRCMessage(newCRC);
2109+
}
2110+
else
2111+
{
2112+
#if defined(RTS_DEBUG)
2113+
// don't even put this in release, cause someone might hack it.
2114+
if (!TheDebugIgnoreSyncErrors)
2115+
#endif
2116+
m_validationModeCRC = CRCMODE_REPLAY;
2117+
2118+
TheRecorder->handlePlayerCRCMessage(msgPlayer->getPlayerIndex(), newCRC);
2119+
}
21022120
}
21032121
break;
2104-
21052122
}
21062123

21072124
//---------------------------------------------------------------------------------------------

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@ class GlobalData : public SubsystemInterface
367367
Bool m_afterIntro; ///< we need to tell the game our intro is done
368368
Bool m_allowExitOutOfMovies; ///< flag to allow exit out of movies only after the Intro has played
369369

370+
Bool m_replayOnlyCheckLocalPlayer; ///< flag to check only the CRC messages from the player that recorded a replay
371+
370372
Bool m_loadScreenRender; ///< flag to disallow rendering of almost everything during a loadscreen
371373

372374
Real m_keyboardScrollFactor; ///< Factor applied to game scrolling speed via keyboard scrolling

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ class Player : public Snapshot
221221

222222
void deletePlayerAI();
223223

224-
UnicodeString getPlayerDisplayName() { return m_playerDisplayName; }
224+
UnicodeString getPlayerDisplayName() const { return m_playerDisplayName; }
225225
NameKeyType getPlayerNameKey() const { return m_playerNameKey; }
226226

227227
AsciiString getSide() const { return m_side; }

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

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,50 @@ class RecorderClass : public SubsystemInterface
6767
class CRCInfo
6868
{
6969
public:
70+
struct MismatchData
71+
{
72+
MismatchData() :
73+
mismatched(false),
74+
playerIndex(0),
75+
queueSize(0),
76+
playbackCRC(0),
77+
playerCRC(0)
78+
{}
79+
80+
MismatchData(Byte playerIndex, UnsignedShort queueSize, UnsignedInt playbackCRC, UnsignedInt playerCRC) :
81+
mismatched(true),
82+
playerIndex(playerIndex),
83+
queueSize(queueSize),
84+
playbackCRC(playbackCRC),
85+
playerCRC(playerCRC)
86+
{}
87+
88+
Bool mismatched;
89+
Byte playerIndex;
90+
UnsignedShort queueSize;
91+
UnsignedInt playbackCRC;
92+
UnsignedInt playerCRC;
93+
};
94+
7095
CRCInfo();
71-
CRCInfo(UnsignedInt localPlayer, Bool isMultiplayer);
72-
void addCRC(UnsignedInt val);
73-
UnsignedInt readCRC();
74-
int GetQueueSize() const { return m_data.size(); }
75-
UnsignedInt getLocalPlayer() const { return m_localPlayer; }
76-
void setSawCRCMismatch() { m_sawCRCMismatch = TRUE; }
77-
Bool sawCRCMismatch() const { return m_sawCRCMismatch; }
96+
void init(Bool isMultiplayer, Int localPlayerIndex);
97+
void addPlaybackCRC(UnsignedInt val);
98+
void addPlayerCRC(Int playerIndex, UnsignedInt val);
99+
void setSawCRCMismatch();
100+
Bool sawCRCMismatch() const;
101+
Byte getLocalPlayerIndex() const;
102+
MismatchData getMismatchData();
78103

79104
protected:
80-
Bool m_sawCRCMismatch;
105+
UnsignedInt getLargestQueueSize() const;
106+
UnsignedInt getPlaybackCRC();
107+
81108
Bool m_skippedOne;
82-
UnsignedInt m_localPlayer;
83-
std::list<UnsignedInt> m_data;
109+
Bool m_sawCRCMismatch;
110+
Byte m_localPlayerIndex;
111+
std::list<UnsignedInt> m_playbackData;
112+
std::vector<UnsignedInt> m_playerData[MAX_PLAYER_COUNT];
113+
Bool m_inactivePlayer[MAX_PLAYER_COUNT];
84114
};
85115

86116
public:
@@ -110,8 +140,9 @@ class RecorderClass : public SubsystemInterface
110140
#endif
111141
Bool isPlaybackInProgress() const;
112142

113-
public:
114-
void handleCRCMessage(UnsignedInt newCRC, Int playerIndex, Bool fromPlayback);
143+
void handlePlaybackCRCMessage(UnsignedInt newCRC);
144+
void handlePlayerCRCMessage(Int playerIndex, UnsignedInt newCRC);
145+
void checkForMismatch();
115146

116147
// read in info relating to a replay, conditionally setting up m_file for playback
117148
struct ReplayHeader

GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,13 @@ class GameLogic : public SubsystemInterface, public Snapshot
298298

299299
private:
300300

301+
enum CRCValidationMode CPP_11(: UnsignedByte)
302+
{
303+
CRCMODE_NONE,
304+
CRCMODE_NETWORK,
305+
CRCMODE_REPLAY,
306+
};
307+
301308
/**
302309
overrides to thing template buildable status. doesn't really belong here,
303310
but has to go somewhere. (srj)
@@ -317,7 +324,7 @@ class GameLogic : public SubsystemInterface, public Snapshot
317324
// CRC cache system -----------------------------------------------------------------------------
318325
UnsignedInt m_CRC; ///< Cache of previous CRC value
319326
std::map<Int, UnsignedInt> m_cachedCRCs; ///< CRCs we've seen this frame
320-
Bool m_shouldValidateCRCs; ///< Should we validate CRCs this frame?
327+
CRCValidationMode m_validationModeCRC; ///< (How) should we validate CRCs this frame?
321328
//-----------------------------------------------------------------------------------------------
322329
//Bool m_loadingScene;
323330
Bool m_loadingMap;

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,13 @@ Int parseJobs(char *args[], int num)
465465
return 1;
466466
}
467467

468+
Int parseReplayCRC(char* args[], int num)
469+
{
470+
TheWritableGlobalData->m_replayOnlyCheckLocalPlayer = TRUE;
471+
472+
return 1;
473+
}
474+
468475
Int parseXRes(char *args[], int num)
469476
{
470477
if (num > 1)
@@ -1166,6 +1173,9 @@ static CommandLineParam paramsForEngineInit[] =
11661173
// TheSuperHackers @feature xezon 03/08/2025 Force full viewport for 'Control Bar Pro' Addons like GenTool did it.
11671174
{ "-forcefullviewport", parseFullViewport },
11681175

1176+
// TheSuperHackers @feature Caball009 03/06/2026 Enable checking only the CRC messages from the player that recorded a replay.
1177+
{ "-replayLocalPlayerCRC", parseReplayCRC },
1178+
11691179
#if defined(RTS_DEBUG)
11701180
{ "-noaudio", parseNoAudio },
11711181
{ "-map", parseMapName },

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,7 @@ GlobalData::GlobalData()
10141014
m_playSizzle = TRUE;
10151015
m_afterIntro = FALSE;
10161016
m_allowExitOutOfMovies = FALSE;
1017+
m_replayOnlyCheckLocalPlayer = FALSE;
10171018
m_loadScreenRender = FALSE;
10181019

10191020
m_keyboardDefaultScrollFactor = m_keyboardScrollFactor = 0.5f;

0 commit comments

Comments
 (0)