Skip to content

Commit 795269b

Browse files
committed
feat(crc): Write deep CRC snapshots to disk when game mismatches
1 parent 637dbba commit 795269b

File tree

12 files changed

+309
-3
lines changed

12 files changed

+309
-3
lines changed

Core/GameEngine/Include/Common/GameDefines.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@
112112
#endif
113113
#endif
114114

115+
#if (!defined(DEEP_CRC_TO_MEMORY) && !defined(DEBUG_CRC))
116+
#define DEEP_CRC_TO_MEMORY 1
117+
#endif
118+
115119
#define MIN_DISPLAY_BIT_DEPTH 16
116120
#define DEFAULT_DISPLAY_BIT_DEPTH 32
117121
#define DEFAULT_DISPLAY_WIDTH 800 // The standard resolution this game was designed for

Core/GameEngine/Include/Common/RandomValue.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,8 @@ extern void InitRandom( UnsignedInt seed );
3535
extern UnsignedInt GetGameLogicRandomSeed(); ///< Get the seed (used for replays)
3636
extern UnsignedInt GetGameLogicRandomSeedCRC();///< Get the seed (used for CRCs)
3737

38+
#if DEEP_CRC_TO_MEMORY
39+
AsciiString GetGameLogicalRandomSeeds();
40+
#endif
41+
3842
//--------------------------------------------------------------------------------------------------------------

Core/GameEngine/Include/Common/Xfer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ class Xfer
178178
virtual void xferMatrix3D( Matrix3D* mtx );
179179
virtual void xferMapName( AsciiString *mapNameData );
180180

181+
#if DEEP_CRC_TO_MEMORY
182+
virtual void xferLogString(const AsciiString& str) {}
183+
#endif
184+
181185
protected:
182186

183187
// this is the actual xfer implementation that each derived class should implement

Core/GameEngine/Include/Common/XferDeepCRC.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
// USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
3333
#include "Common/Xfer.h"
3434
#include "Common/XferCRC.h"
35+
#if DEEP_CRC_TO_MEMORY
36+
#include <vector>
37+
#endif
3538

3639
// FORWARD REFERENCES /////////////////////////////////////////////////////////////////////////////
3740
class Snapshot;
@@ -55,9 +58,19 @@ class XferDeepCRC : public XferCRC
5558
virtual void xferAsciiString( AsciiString *asciiStringData ) override; ///< xfer ascii string (need our own)
5659
virtual void xferUnicodeString( UnicodeString *unicodeStringData ) override; ///< xfer unicode string (need our own);
5760

61+
#if DEEP_CRC_TO_MEMORY
62+
virtual void xferLogString(const AsciiString& str) override;
63+
void changeXferMode(XferMode xferMode);
64+
#endif
65+
5866
protected:
5967

6068
virtual void xferImplementation( void *data, Int dataSize ) override;
6169

70+
#if DEEP_CRC_TO_MEMORY
71+
std::vector<UnsignedByte>* m_buffer; ///< pointer to buffer
72+
size_t m_bufferIndex; ///< current index in buffer
73+
#else
6274
FILE * m_fileFP; ///< pointer to file
75+
#endif
6376
};

Core/GameEngine/Source/Common/RandomValue.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,22 @@ UnsignedInt GetGameLogicRandomSeedCRC()
7676
return c.get();
7777
}
7878

79+
#if DEEP_CRC_TO_MEMORY
80+
AsciiString GetGameLogicalRandomSeeds()
81+
{
82+
AsciiString str;
83+
str.format("%8.8X, %8.8X, %8.8X, %8.8X, %8.8X, %8.8X",
84+
theGameLogicSeed[0],
85+
theGameLogicSeed[1],
86+
theGameLogicSeed[2],
87+
theGameLogicSeed[3],
88+
theGameLogicSeed[4],
89+
theGameLogicSeed[5]);
90+
91+
return str;
92+
}
93+
#endif
94+
7995
static void seedRandom(UnsignedInt SEED, UnsignedInt (&seed)[6])
8096
{
8197
UnsignedInt ax;

Core/GameEngine/Source/Common/System/XferCRC.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
#include "Common/Snapshot.h"
3737
#include "Utility/endian_compat.h"
3838

39+
#if DEEP_CRC_TO_MEMORY
40+
#include "GameLogic/GameLogic.h"
41+
#endif
42+
3943
//-------------------------------------------------------------------------------------------------
4044
//-------------------------------------------------------------------------------------------------
4145
XferCRC::XferCRC()
@@ -175,8 +179,14 @@ UnsignedInt XferCRC::getCRC()
175179
XferDeepCRC::XferDeepCRC()
176180
{
177181

182+
#if DEEP_CRC_TO_MEMORY
183+
m_xferMode = XFER_CRC;
184+
m_buffer = nullptr;
185+
m_bufferIndex = 0;
186+
#else
178187
m_xferMode = XFER_SAVE;
179188
m_fileFP = nullptr;
189+
#endif
180190

181191
}
182192

@@ -185,6 +195,7 @@ XferDeepCRC::XferDeepCRC()
185195
XferDeepCRC::~XferDeepCRC()
186196
{
187197

198+
#if !DEEP_CRC_TO_MEMORY
188199
// warn the user if a file was left open
189200
if( m_fileFP != nullptr )
190201
{
@@ -193,6 +204,7 @@ XferDeepCRC::~XferDeepCRC()
193204
close();
194205

195206
}
207+
#endif
196208

197209
}
198210

@@ -202,8 +214,13 @@ XferDeepCRC::~XferDeepCRC()
202214
void XferDeepCRC::open( AsciiString identifier )
203215
{
204216

217+
#if DEEP_CRC_TO_MEMORY
218+
m_xferMode = XFER_CRC;
219+
#else
205220
m_xferMode = XFER_SAVE;
221+
#endif
206222

223+
#if !DEEP_CRC_TO_MEMORY
207224
// sanity, check to see if we're already open
208225
if( m_fileFP != nullptr )
209226
{
@@ -213,10 +230,26 @@ void XferDeepCRC::open( AsciiString identifier )
213230
throw XFER_FILE_ALREADY_OPEN;
214231

215232
}
233+
#endif
216234

217235
// call base class
218236
Xfer::open( identifier );
219237

238+
#if DEEP_CRC_TO_MEMORY
239+
m_buffer = &TheGameLogic->getCRCBuffer();
240+
241+
AsciiString str;
242+
str.format("[ START OF DEEP CRC FRAME %d ]", TheGameLogic->getFrame());
243+
const UnsignedInt length = str.getLength();
244+
245+
while (m_bufferIndex + length >= m_buffer->size())
246+
{
247+
m_buffer->resize(m_buffer->size() * 2);
248+
}
249+
250+
memcpy(&(*m_buffer)[m_bufferIndex], str.str(), length);
251+
m_bufferIndex += length;
252+
#else
220253
// open the file
221254
m_fileFP = fopen( identifier.str(), "w+b" );
222255
if( m_fileFP == nullptr )
@@ -226,6 +259,7 @@ void XferDeepCRC::open( AsciiString identifier )
226259
throw XFER_FILE_NOT_FOUND;
227260

228261
}
262+
#endif
229263

230264
// initialize CRC to brand new one at zero
231265
m_crc = 0;
@@ -238,6 +272,21 @@ void XferDeepCRC::open( AsciiString identifier )
238272
void XferDeepCRC::close()
239273
{
240274

275+
#if DEEP_CRC_TO_MEMORY
276+
AsciiString str;
277+
str.format("[ END OF DEEP CRC FRAME %d ]", TheGameLogic->getFrame());
278+
const UnsignedInt length = str.getLength();
279+
280+
while (m_bufferIndex + length >= m_buffer->size())
281+
{
282+
m_buffer->resize(m_buffer->size() * 2);
283+
}
284+
285+
memcpy(&(*m_buffer)[m_bufferIndex], str.str(), length);
286+
m_bufferIndex += length;
287+
288+
TheGameLogic->storeCRCBuffer(m_bufferIndex);
289+
#else
241290
// sanity, if we don't have an open file we can do nothing
242291
if( m_fileFP == nullptr )
243292
{
@@ -246,10 +295,15 @@ void XferDeepCRC::close()
246295
throw XFER_FILE_NOT_OPEN;
247296

248297
}
298+
#endif
249299

300+
#if DEEP_CRC_TO_MEMORY
301+
m_buffer = nullptr;
302+
#else
250303
// close the file
251304
fclose( m_fileFP );
252305
m_fileFP = nullptr;
306+
#endif
253307

254308
// erase the filename
255309
m_identifier.clear();
@@ -267,6 +321,15 @@ void XferDeepCRC::xferImplementation( void *data, Int dataSize )
267321
return;
268322
}
269323

324+
#if DEEP_CRC_TO_MEMORY
325+
while (m_bufferIndex + dataSize >= m_buffer->size())
326+
{
327+
m_buffer->resize(m_buffer->size() * 2);
328+
}
329+
330+
memcpy(&(*m_buffer)[m_bufferIndex], data, dataSize);
331+
m_bufferIndex += dataSize;
332+
#else
270333
// sanity
271334
DEBUG_ASSERTCRASH( m_fileFP != nullptr, ("XferSave - file pointer for '%s' is null",
272335
m_identifier.str()) );
@@ -279,6 +342,7 @@ void XferDeepCRC::xferImplementation( void *data, Int dataSize )
279342
throw XFER_WRITE_ERROR;
280343

281344
}
345+
#endif
282346

283347
XferCRC::xferImplementation( data, dataSize );
284348

@@ -290,6 +354,11 @@ void XferDeepCRC::xferImplementation( void *data, Int dataSize )
290354
void XferDeepCRC::xferMarkerLabel( AsciiString asciiStringData )
291355
{
292356

357+
#if DEEP_CRC_TO_MEMORY
358+
XferCRC::xferMarkerLabel(asciiStringData);
359+
return;
360+
#endif
361+
293362
}
294363

295364
// ------------------------------------------------------------------------------------------------
@@ -298,6 +367,11 @@ void XferDeepCRC::xferMarkerLabel( AsciiString asciiStringData )
298367
void XferDeepCRC::xferAsciiString( AsciiString *asciiStringData )
299368
{
300369

370+
#if DEEP_CRC_TO_MEMORY
371+
XferCRC::xferAsciiString(asciiStringData);
372+
return;
373+
#endif
374+
301375
// sanity
302376
if( asciiStringData->getLength() > 16385 )
303377
{
@@ -323,6 +397,11 @@ void XferDeepCRC::xferAsciiString( AsciiString *asciiStringData )
323397
void XferDeepCRC::xferUnicodeString( UnicodeString *unicodeStringData )
324398
{
325399

400+
#if DEEP_CRC_TO_MEMORY
401+
XferCRC::xferUnicodeString(unicodeStringData);
402+
return;
403+
#endif
404+
326405
// sanity
327406
if( unicodeStringData->getLength() > 255 )
328407
{
@@ -341,3 +420,23 @@ void XferDeepCRC::xferUnicodeString( UnicodeString *unicodeStringData )
341420
xferUser( (void *)unicodeStringData->str(), sizeof( WideChar ) * len );
342421

343422
}
423+
424+
#if DEEP_CRC_TO_MEMORY
425+
void XferDeepCRC::xferLogString(const AsciiString& str)
426+
{
427+
const UnsignedInt length = str.getLength();
428+
429+
while (m_bufferIndex + length >= m_buffer->size())
430+
{
431+
m_buffer->resize(m_buffer->size() * 2);
432+
}
433+
434+
memcpy(&(*m_buffer)[m_bufferIndex], str.str(), length);
435+
m_bufferIndex += length;
436+
}
437+
438+
void XferDeepCRC::changeXferMode(XferMode xferMode)
439+
{
440+
m_xferMode = xferMode;
441+
}
442+
#endif

Core/GameEngine/Source/GameClient/ClientInstance.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ UnsignedInt ClientInstance::s_instanceIndex = 0;
2727

2828
#if defined(RTS_MULTI_INSTANCE)
2929
Bool ClientInstance::s_isMultiInstance = true;
30+
#elif DEEP_CRC_TO_MEMORY
31+
Bool ClientInstance::s_isMultiInstance = true;
3032
#else
3133
Bool ClientInstance::s_isMultiInstance = false;
3234
#endif

Core/GameEngine/Source/GameNetwork/Network.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555

5656
#if defined(DEBUG_CRC)
5757
Int NET_CRC_INTERVAL = 1;
58+
#elif DEEP_CRC_TO_MEMORY
59+
Int NET_CRC_INTERVAL = 1;
5860
#else
5961
Int NET_CRC_INTERVAL = 100;
6062
#endif

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,16 @@ class GameLogic : public SubsystemInterface, public Snapshot
405405
void xferObjectTOC( Xfer *xfer ); ///< save/load object TOC for current state of map
406406
void prepareLogicForObjectLoad(); ///< prepare engine for object data from game file
407407

408+
#if DEEP_CRC_TO_MEMORY
409+
UnsignedInt m_crcBufferIndex;
410+
std::vector<UnsignedByte> m_crcWriteBuffer;
411+
std::vector<UnsignedByte> m_crcBuffers[64];
412+
413+
public:
414+
std::vector<UnsignedByte>& getCRCBuffer();
415+
void storeCRCBuffer(size_t size);
416+
void writeCRCBuffersToDisk(UnsignedInt frame) const;
417+
#endif
408418
};
409419

410420
// INLINE /////////////////////////////////////////////////////////////////////////////////////////

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,10 @@ class Object : public Thing, public Snapshot
818818
Bool m_singleUseCommandUsed;
819819
Bool m_isReceivingDifficultyBonus;
820820

821+
#if DEEP_CRC_TO_MEMORY
822+
public:
823+
const UpgradeMaskType& getUpgrades() const { return m_objectUpgradesCompleted; }
824+
#endif
821825
};
822826

823827
// deleteInstance is not meant to be used with Object in order to require the use of TheGameLogic->destroyObject()

0 commit comments

Comments
 (0)