@@ -100,6 +100,50 @@ static FILE* openStatsLogFile()
100100}
101101#endif
102102
103+ RecorderClass::CRCInfo::CRCInfo () :
104+ m_sawCRCMismatch(FALSE ),
105+ m_skippedOne(FALSE ),
106+ m_localPlayer(0 )
107+ {}
108+
109+ RecorderClass::CRCInfo::CRCInfo (UnsignedInt localPlayer, Bool isMultiplayer)
110+ {
111+ m_sawCRCMismatch = FALSE ;
112+ m_skippedOne = !isMultiplayer;
113+ m_localPlayer = localPlayer;
114+ }
115+
116+ void RecorderClass::CRCInfo::addCRC (UnsignedInt val)
117+ {
118+ // TheSuperHackers @fix helmutbuhler 03/04/2025
119+ // In Multiplayer, the first MSG_LOGIC_CRC message somehow doesn't make it through the network.
120+ // Perhaps this happens because the network is not yet set up on frame 0.
121+ // So we also don't queue up the first local crc message, otherwise the crc
122+ // messages wouldn't match up anymore and we'd desync immediately during playback.
123+ if (!m_skippedOne)
124+ {
125+ m_skippedOne = TRUE ;
126+ return ;
127+ }
128+
129+ m_data.push_back (val);
130+ // DEBUG_LOG(("CRCInfo::addCRC() - crc %8.8X pushes list to %d entries (full=%d)", val, m_data.size(), !m_data.empty()));
131+ }
132+
133+ UnsignedInt RecorderClass::CRCInfo::readCRC ()
134+ {
135+ if (m_data.empty ())
136+ {
137+ DEBUG_LOG ((" CRCInfo::readCRC() - bailing, full=0, size=%d" , m_data.size ()));
138+ return 0 ;
139+ }
140+
141+ UnsignedInt val = m_data.front ();
142+ m_data.pop_front ();
143+ // DEBUG_LOG(("CRCInfo::readCRC() - returning %8.8X, full=%d, size=%d", val, !m_data.empty(), m_data.size()));
144+ return val;
145+ }
146+
103147void RecorderClass::logGameStart (AsciiString options)
104148{
105149 if (!m_file)
@@ -933,96 +977,21 @@ AsciiString RecorderClass::getCurrentReplayFilename()
933977 return AsciiString::TheEmptyString;
934978}
935979
936- // TheSuperHackers @info helmutbuhler 03/04/2025
937- // Some info about CRC:
938- // In each game, each peer periodically calculates a CRC from the local gamestate and sends that
939- // in a message to all peers (including itself) so that everyone can check that the crc is synchronous.
940- // In a network game, there is a delay between sending the CRC message and receiving it. This is
941- // necessary because if you were to wait each frame for all messages from all peers, things would go
942- // horribly slow.
943- // But this delay is not a problem for CRC checking because everyone receives the CRC in the same frame
944- // and every peer just makes sure all the received CRCs are equal.
945- // While playing replays, this is a problem however: The CRC messages in the replays appear on the frame
946- // they were received, which can be a few frames delayed if it was a network game. And if we were to
947- // compare those with the local gamestate, they wouldn't sync up.
948- // So, in order to fix this, we need to queue up our local CRCs,
949- // so that we can check it with the crc messages that come later.
950- // This class is basically that queue.
951- class CRCInfo
952- {
953- public:
954- CRCInfo (UnsignedInt localPlayer, Bool isMultiplayer);
955- void addCRC (UnsignedInt val);
956- UnsignedInt readCRC ();
957-
958- int GetQueueSize () const { return m_data.size (); }
959-
960- UnsignedInt getLocalPlayer () { return m_localPlayer; }
961-
962- void setSawCRCMismatch () { m_sawCRCMismatch = TRUE ; }
963- Bool sawCRCMismatch () const { return m_sawCRCMismatch; }
964-
965- protected:
966-
967- Bool m_sawCRCMismatch;
968- Bool m_skippedOne;
969- std::list<UnsignedInt> m_data;
970- UnsignedInt m_localPlayer;
971- };
972-
973- CRCInfo::CRCInfo (UnsignedInt localPlayer, Bool isMultiplayer)
974- {
975- m_localPlayer = localPlayer;
976- m_skippedOne = !isMultiplayer;
977- m_sawCRCMismatch = FALSE ;
978- }
979-
980- void CRCInfo::addCRC (UnsignedInt val)
981- {
982- // TheSuperHackers @fix helmutbuhler 03/04/2025
983- // In Multiplayer, the first MSG_LOGIC_CRC message somehow doesn't make it through the network.
984- // Perhaps this happens because the network is not yet set up on frame 0.
985- // So we also don't queue up the first local crc message, otherwise the crc
986- // messages wouldn't match up anymore and we'd desync immediately during playback.
987- if (!m_skippedOne)
988- {
989- m_skippedOne = TRUE ;
990- return ;
991- }
992-
993- m_data.push_back (val);
994- // DEBUG_LOG(("CRCInfo::addCRC() - crc %8.8X pushes list to %d entries (full=%d)", val, m_data.size(), !m_data.empty()));
995- }
996-
997- UnsignedInt CRCInfo::readCRC ()
998- {
999- if (m_data.empty ())
1000- {
1001- DEBUG_LOG ((" CRCInfo::readCRC() - bailing, full=0, size=%d" , m_data.size ()));
1002- return 0 ;
1003- }
1004-
1005- UnsignedInt val = m_data.front ();
1006- m_data.pop_front ();
1007- // DEBUG_LOG(("CRCInfo::readCRC() - returning %8.8X, full=%d, size=%d", val, !m_data.empty(), m_data.size()));
1008- return val;
1009- }
1010-
1011980Bool RecorderClass::sawCRCMismatch () const
1012981{
1013- return m_crcInfo-> sawCRCMismatch ();
982+ return m_crcInfo. sawCRCMismatch ();
1014983}
1015984
1016985void RecorderClass::handleCRCMessage (UnsignedInt newCRC, Int playerIndex, Bool fromPlayback)
1017986{
1018987 if (fromPlayback)
1019988 {
1020989 // DEBUG_LOG(("RecorderClass::handleCRCMessage() - Adding CRC of %X from %d to m_crcInfo", newCRC, playerIndex));
1021- m_crcInfo-> addCRC (newCRC);
990+ m_crcInfo. addCRC (newCRC);
1022991 return ;
1023992 }
1024993
1025- Int localPlayerIndex = m_crcInfo-> getLocalPlayer ();
994+ Int localPlayerIndex = m_crcInfo. getLocalPlayer ();
1026995 Bool samePlayer = FALSE ;
1027996 AsciiString playerName;
1028997 playerName.format (" player%d" , localPlayerIndex);
@@ -1031,10 +1000,10 @@ void RecorderClass::handleCRCMessage(UnsignedInt newCRC, Int playerIndex, Bool f
10311000 samePlayer = TRUE ;
10321001 if (samePlayer || (localPlayerIndex < 0 ))
10331002 {
1034- UnsignedInt playbackCRC = m_crcInfo-> readCRC ();
1003+ UnsignedInt playbackCRC = m_crcInfo. readCRC ();
10351004 // DEBUG_LOG(("RecorderClass::handleCRCMessage() - Comparing CRCs of InGame:%8.8X Replay:%8.8X Frame:%d from Player %d",
1036- // playbackCRC, newCRC, TheGameLogic->getFrame()-m_crcInfo-> GetQueueSize()-1, playerIndex));
1037- if (TheGameLogic->getFrame () > 0 && newCRC != playbackCRC && !m_crcInfo-> sawCRCMismatch ())
1005+ // playbackCRC, newCRC, TheGameLogic->getFrame()-m_crcInfo. GetQueueSize()-1, playerIndex));
1006+ if (TheGameLogic->getFrame () > 0 && newCRC != playbackCRC && !m_crcInfo. sawCRCMismatch ())
10381007 {
10391008 // Since we don't seem to have any *visible* desyncs when replaying games, but get this warning
10401009 // virtually every replay, the assumption is our CRC checking is faulty. Since we're at the
@@ -1048,7 +1017,7 @@ void RecorderClass::handleCRCMessage(UnsignedInt newCRC, Int playerIndex, Bool f
10481017 // TheSuperHackers @info helmutbuhler 03/04/2025
10491018 // Note: We subtract the queue size from the frame number. This way we calculate the correct frame
10501019 // the mismatch first happened in case the NetCRCInterval is set to 1 during the game.
1051- const UnsignedInt mismatchFrame = TheGameLogic->getFrame () - m_crcInfo-> GetQueueSize () - 1 ;
1020+ const UnsignedInt mismatchFrame = TheGameLogic->getFrame () - m_crcInfo. GetQueueSize () - 1 ;
10521021
10531022 // Now also prints a UI message for it.
10541023 const UnicodeString mismatchDetailsStr = TheGameText->FETCH_OR_SUBSTITUTE (" GUI:CRCMismatchDetails" , L" InGame:%8.8X Replay:%8.8X Frame:%d" );
@@ -1070,7 +1039,7 @@ void RecorderClass::handleCRCMessage(UnsignedInt newCRC, Int playerIndex, Bool f
10701039 TheGameLogic->setGamePaused (pause, pauseMusic, pauseInput);
10711040
10721041 // Mark this mismatch as seen when we had the chance to pause once.
1073- m_crcInfo-> setSawCRCMismatch ();
1042+ m_crcInfo. setSawCRCMismatch ();
10741043 }
10751044 }
10761045 return ;
@@ -1192,9 +1161,9 @@ Bool RecorderClass::playbackFile(AsciiString filename)
11921161#endif
11931162
11941163 Bool isMultiplayer = m_gameInfo.getSlot (header.localPlayerIndex )->getIP () != 0 ;
1195- m_crcInfo = NEW CRCInfo (header.localPlayerIndex , isMultiplayer);
1164+ m_crcInfo = CRCInfo (header.localPlayerIndex , isMultiplayer);
11961165 REPLAY_CRC_INTERVAL = m_gameInfo.getCRCInterval ();
1197- DEBUG_LOG ((" Player index is %d, replay CRC interval is %d" , m_crcInfo-> getLocalPlayer (), REPLAY_CRC_INTERVAL ));
1166+ DEBUG_LOG ((" Player index is %d, replay CRC interval is %d" , m_crcInfo. getLocalPlayer (), REPLAY_CRC_INTERVAL ));
11981167
11991168 Int difficulty = 0 ;
12001169 m_file->read (&difficulty, sizeof (difficulty));
0 commit comments