Skip to content

Commit 34107c5

Browse files
authored
[ZH] Improve CRC Logging Debug Functionality (TheSuperHackers#544)
1 parent c47c202 commit 34107c5

9 files changed

Lines changed: 237 additions & 95 deletions

File tree

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@
6868
void dumpReal(Real r, AsciiString name, AsciiString fname, Int line);
6969

7070
void outputCRCDebugLines( void );
71+
void CRCDebugStartNewGame( void );
7172
void outputCRCDumpLines( void );
7273

7374
void addCRCDebugLine(const char *fmt, ...);
75+
void addCRCDebugLineNoCounter(const char *fmt, ...);
7476
void addCRCDumpLine(const char *fmt, ...);
7577
void addCRCGenLine(const char *fmt, ...);
7678
#define CRCDEBUG_LOG(x) addCRCDebugLine x
@@ -97,7 +99,9 @@
9799
extern Bool g_crcModuleDataFromLogic;
98100

99101
extern Bool g_keepCRCSaves;
100-
102+
extern Bool g_saveDebugCRCPerFrame;
103+
extern AsciiString g_saveDebugCRCPerFrameDir;
104+
101105
extern Bool g_logObjectCRCs;
102106

103107
#else // DEBUG_CRC

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@
2727
// Desc: The Xfer system is capable of setting up operations to work with blocks of data
2828
// from other subsystems. It can work things such as file reading, file writing,
2929
// CRC computations etc
30+
//
31+
// TheSuperHackers @info helmutbuhler 04/09/2025
32+
// The baseclass Xfer has 3 implementations:
33+
// - XferLoad: Load gamestate
34+
// - XferSave: Save gamestate
35+
// - XferCRC: Calculate gamestate CRC
36+
// - XferDeepCRC: This derives from XferCRC and also writes the gamestate data relevant
37+
// to crc calculation to a file (only used in developer builds)
3038
///////////////////////////////////////////////////////////////////////////////////////////////////
3139

3240
#pragma once

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

Lines changed: 109 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "Common/CRCDebug.h"
2929
#include "Common/Debug.h"
3030
#include "Common/PerfTimer.h"
31+
#include "Common/LocalFileSystem.h"
3132
#include "GameClient/InGameUI.h"
3233
#include "GameNetwork/IPEnumeration.h"
3334
#include <cstdarg>
@@ -41,11 +42,12 @@
4142
#ifdef DEBUG_CRC
4243

4344
static const Int MaxStrings = 64000;
45+
static const Int MaxStringLen = 1024;
4446

45-
static char DebugStrings[MaxStrings][1024];
47+
static char DebugStrings[MaxStrings][MaxStringLen];
4648
static Int nextDebugString = 0;
4749
static Int numDebugStrings = 0;
48-
//static char DumpStrings[MaxStrings][1024];
50+
//static char DumpStrings[MaxStrings][MaxStringLen];
4951
//static Int nextDumpString = 0;
5052
//static Int numDumpStrings = 0;
5153

@@ -91,12 +93,8 @@ CRCVerification::~CRCVerification()
9193
#endif
9294
}
9395

94-
static Bool dumped = FALSE;
9596
void outputCRCDebugLines( void )
9697
{
97-
if (dumped)
98-
return;
99-
dumped = TRUE;
10098
IPEnumeration ips;
10199
AsciiString fname;
102100
fname.format("crcDebug%s.txt", ips.getMachineName().str());
@@ -116,6 +114,60 @@ void outputCRCDebugLines( void )
116114
if (fp) fclose(fp);
117115
}
118116

117+
Int lastCRCDebugFrame = 0;
118+
Int lastCRCDebugIndex = 0;
119+
extern Bool inCRCGen;
120+
121+
void CRCDebugStartNewGame()
122+
{
123+
if (g_saveDebugCRCPerFrame)
124+
{
125+
// Create folder for frame data, if it doesn't exist yet.
126+
CreateDirectory(g_saveDebugCRCPerFrameDir.str(), NULL);
127+
128+
// Delete existing files
129+
FilenameList files;
130+
AsciiString dir = g_saveDebugCRCPerFrameDir;
131+
dir.concat("/");
132+
TheLocalFileSystem->getFileListInDirectory(dir.str(), "", "DebugFrame_*.txt", files, FALSE);
133+
FilenameList::iterator it;
134+
for (it = files.begin(); it != files.end(); ++it)
135+
{
136+
DeleteFile(it->str());
137+
}
138+
}
139+
nextDebugString = 0;
140+
numDebugStrings = 0;
141+
lastCRCDebugFrame = 0;
142+
lastCRCDebugIndex = 0;
143+
}
144+
145+
static void outputCRCDebugLinesPerFrame()
146+
{
147+
if (!g_saveDebugCRCPerFrame || numDebugStrings == 0)
148+
return;
149+
AsciiString fname;
150+
fname.format("%s/DebugFrame_%06d.txt", g_saveDebugCRCPerFrameDir.str(), lastCRCDebugFrame);
151+
FILE *fp = fopen(fname.str(), "wt");
152+
int start = 0;
153+
int end = nextDebugString;
154+
if (numDebugStrings >= MaxStrings)
155+
start = nextDebugString - MaxStrings;
156+
nextDebugString = 0;
157+
numDebugStrings = 0;
158+
if (!fp)
159+
return;
160+
161+
for (Int i=start; i<end; ++i)
162+
{
163+
const char *line = DebugStrings[ (i + MaxStrings) % MaxStrings ];
164+
//DEBUG_LOG(("%s\n", line));
165+
fprintf(fp, "%s\n", line);
166+
}
167+
168+
fclose(fp);
169+
}
170+
119171
void outputCRCDumpLines( void )
120172
{
121173
/*
@@ -137,64 +189,76 @@ static AsciiString getFname(AsciiString path)
137189
return path.reverseFind('\\') + 1;
138190
}
139191

140-
Int lastCRCDebugFrame = 0;
141-
Int lastCRCDebugIndex = 0;
142-
extern Bool inCRCGen;
143-
void addCRCDebugLine(const char *fmt, ...)
192+
static void addCRCDebugLineInternal(bool count, const char *fmt, va_list args)
144193
{
145-
if (dumped)// || inCRCGen /*|| !TheGameLogic->isInGameLogicUpdate()*/)
194+
if (TheGameLogic == NULL || !(IS_FRAME_OK_TO_LOG))
146195
return;
147196

148-
if (IS_FRAME_OK_TO_LOG)
197+
if (lastCRCDebugFrame != TheGameLogic->getFrame())
149198
{
199+
outputCRCDebugLinesPerFrame();
200+
lastCRCDebugFrame = TheGameLogic->getFrame();
201+
lastCRCDebugIndex = 0;
202+
}
150203

151-
if (lastCRCDebugFrame != TheGameLogic->getFrame())
152-
{
153-
lastCRCDebugFrame = TheGameLogic->getFrame();
154-
lastCRCDebugIndex = 0;
155-
}
156-
157-
sprintf(DebugStrings[nextDebugString], "%d:%d ", TheGameLogic->getFrame(), lastCRCDebugIndex++);
158-
//DebugStrings[nextDebugString][0] = 0;
159-
Int len = strlen(DebugStrings[nextDebugString]);
204+
if (count)
205+
sprintf(DebugStrings[nextDebugString], "%d:%05d ", TheGameLogic->getFrame(), lastCRCDebugIndex++);
206+
else
207+
DebugStrings[nextDebugString][0] = 0;
208+
Int len = strlen(DebugStrings[nextDebugString]);
160209

161-
va_list va;
162-
va_start( va, fmt );
163-
_vsnprintf(DebugStrings[nextDebugString]+len, 1024-len, fmt, va );
164-
DebugStrings[nextDebugString][1023] = 0;
165-
va_end( va );
210+
_vsnprintf(DebugStrings[nextDebugString]+len, MaxStringLen-len, fmt, args);
211+
DebugStrings[nextDebugString][MaxStringLen-1] = 0;
166212

167-
char *tmp = DebugStrings[nextDebugString];
168-
while (tmp && *tmp)
213+
char *tmp = DebugStrings[nextDebugString];
214+
while (tmp && *tmp)
215+
{
216+
if (*tmp == '\r' || *tmp == '\n')
169217
{
170-
if (*tmp == '\r' || *tmp == '\n')
171-
{
172-
*tmp = ' ';
173-
}
174-
++tmp;
218+
*tmp = ' ';
175219
}
220+
++tmp;
221+
}
176222

177-
//DEBUG_LOG(("%s\n", DebugStrings[nextDebugString]));
223+
//DEBUG_LOG(("%s\n", DebugStrings[nextDebugString]));
178224

179-
++nextDebugString;
180-
++numDebugStrings;
181-
if (nextDebugString == MaxStrings)
182-
nextDebugString = 0;
225+
++nextDebugString;
226+
++numDebugStrings;
227+
if (nextDebugString == MaxStrings)
228+
nextDebugString = 0;
229+
}
183230

184-
}
231+
void addCRCDebugLine(const char *fmt, ...)
232+
{
233+
va_list args;
234+
va_start(args, fmt);
235+
addCRCDebugLineInternal(true, fmt, args);
236+
va_end(args);
237+
}
238+
239+
void addCRCDebugLineNoCounter(const char *fmt, ...)
240+
{
241+
// TheSuperHackers @feature helmutbuhler 04/09/2025
242+
// This version doesn't increase the lastCRCDebugIndex counter
243+
// and can be used for logging lines that don't necessarily match up on all peers.
244+
// (Otherwise the numbers would no longer match up and the diff would be very difficult to read)
245+
va_list args;
246+
va_start(args, fmt);
247+
addCRCDebugLineInternal(false, fmt, args);
248+
va_end(args);
185249
}
186250

187251
void addCRCGenLine(const char *fmt, ...)
188252
{
189-
if (dumped || !(IS_FRAME_OK_TO_LOG))
253+
if (!(IS_FRAME_OK_TO_LOG))
190254
return;
191255

192-
static char buf[1024];
256+
static char buf[MaxStringLen];
193257
va_list va;
194258
va_start( va, fmt );
195-
_vsnprintf(buf, 1024, fmt, va );
259+
_vsnprintf(buf, MaxStringLen, fmt, va );
196260
va_end( va );
197-
buf[1023] = 0;
261+
buf[MaxStringLen-1] = 0;
198262
addCRCDebugLine("%s", buf);
199263

200264
//DEBUG_LOG(("%s", buf));
@@ -205,8 +269,8 @@ void addCRCDumpLine(const char *fmt, ...)
205269
/*
206270
va_list va;
207271
va_start( va, fmt );
208-
_vsnprintf(DumpStrings[nextDumpString], 1024, fmt, va );
209-
DumpStrings[nextDumpString][1023] = 0;
272+
_vsnprintf(DumpStrings[nextDumpString], MaxStringLen, fmt, va );
273+
DumpStrings[nextDumpString][MaxStringLen-1] = 0;
210274
va_end( va );
211275
212276
++nextDumpString;
@@ -218,9 +282,6 @@ void addCRCDumpLine(const char *fmt, ...)
218282

219283
void dumpVector3(const Vector3 *v, AsciiString name, AsciiString fname, Int line)
220284
{
221-
if (dumped)
222-
return;
223-
224285
if (!(IS_FRAME_OK_TO_LOG)) return;
225286
fname.toLower();
226287
fname = getFname(fname);
@@ -231,9 +292,6 @@ void dumpVector3(const Vector3 *v, AsciiString name, AsciiString fname, Int line
231292

232293
void dumpCoord3D(const Coord3D *c, AsciiString name, AsciiString fname, Int line)
233294
{
234-
if (dumped)
235-
return;
236-
237295
if (!(IS_FRAME_OK_TO_LOG)) return;
238296
fname.toLower();
239297
fname = getFname(fname);
@@ -244,9 +302,6 @@ void dumpCoord3D(const Coord3D *c, AsciiString name, AsciiString fname, Int line
244302

245303
void dumpMatrix3D(const Matrix3D *m, AsciiString name, AsciiString fname, Int line)
246304
{
247-
if (dumped)
248-
return;
249-
250305
if (!(IS_FRAME_OK_TO_LOG)) return;
251306
fname.toLower();
252307
fname = getFname(fname);
@@ -260,9 +315,6 @@ void dumpMatrix3D(const Matrix3D *m, AsciiString name, AsciiString fname, Int li
260315

261316
void dumpReal(Real r, AsciiString name, AsciiString fname, Int line)
262317
{
263-
if (dumped)
264-
return;
265-
266318
if (!(IS_FRAME_OK_TO_LOG)) return;
267319
fname.toLower();
268320
fname = getFname(fname);

0 commit comments

Comments
 (0)