274 lines
6.8 KiB
C++
Raw Permalink Normal View History

/*
** Command & Conquer Generals Zero Hour(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/CRCDebug.h"
#include "Common/Debug.h"
#include "Common/PerfTimer.h"
#include "GameClient/InGameUI.h"
#include "GameNetwork/IPEnumeration.h"
#include <cstdarg>
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
#ifdef DEBUG_CRC
static const Int MaxStrings = 64000;
static char DebugStrings[MaxStrings][1024];
static Int nextDebugString = 0;
static Int numDebugStrings = 0;
//static char DumpStrings[MaxStrings][1024];
//static Int nextDumpString = 0;
//static Int numDumpStrings = 0;
#define IS_FRAME_OK_TO_LOG TheGameLogic->isInGame() && !TheGameLogic->isInShellGame() && !TheDebugIgnoreSyncErrors && \
TheCRCFirstFrameToLog >= 0 && TheCRCFirstFrameToLog <= TheGameLogic->getFrame() \
&& TheGameLogic->getFrame() <= TheCRCLastFrameToLog
CRCVerification::CRCVerification()
{
#ifdef DEBUG_LOGGING
/**/
if (g_verifyClientCRC && (IS_FRAME_OK_TO_LOG))
{
m_startCRC = TheGameLogic->getCRC(CRC_RECALC, (g_clientDeepCRC)?"clientPre.crc":"");
}
else
{
m_startCRC = 0;
}
/**/
#endif
}
CRCVerification::~CRCVerification()
{
#ifdef DEBUG_LOGGING
/**/
UnsignedInt endCRC = 0;
if (g_verifyClientCRC && (IS_FRAME_OK_TO_LOG))
{
endCRC = TheGameLogic->getCRC(CRC_RECALC, (g_clientDeepCRC)?"clientPost.crc":"");
}
DEBUG_ASSERTCRASH(!TheGameLogic->isInGame() || m_startCRC == endCRC, ("GameLogic changed outside of GameLogic::update() on frame %d!", TheGameLogic->getFrame()));
if (TheGameLogic->isInMultiplayerGame() && m_startCRC != endCRC)
{
if (TheInGameUI)
{
TheInGameUI->message(UnicodeString(L"GameLogic changed outside of GameLogic::update() - call Matt (x36804)!"));
}
CRCDEBUG_LOG(("GameLogic changed outside of GameLogic::update()!!!\n"));
}
/**/
#endif
}
static Bool dumped = FALSE;
void outputCRCDebugLines( void )
{
if (dumped)
return;
dumped = TRUE;
IPEnumeration ips;
AsciiString fname;
fname.format("crcDebug%s.txt", ips.getMachineName().str());
FILE *fp = fopen(fname.str(), "wt");
int start = 0;
int end = nextDebugString;
if (numDebugStrings >= MaxStrings)
start = nextDebugString - MaxStrings;
for (Int i=start; i<end; ++i)
{
const char *line = DebugStrings[ (i + MaxStrings) % MaxStrings ];
DEBUG_LOG(("%s\n", line));
if (fp) fprintf(fp, "%s\n", line);
}
if (fp) fclose(fp);
}
void outputCRCDumpLines( void )
{
/*
int start = 0;
int end = nextDumpString;
if (numDumpStrings >= MaxStrings)
start = nextDumpString - MaxStrings;
for (Int i=start; i<end; ++i)
{
const char *line = DumpStrings[ (i + MaxStrings) % MaxStrings ];
DEBUG_LOG(("%s", line));
}
*/
}
static AsciiString getFname(AsciiString path)
{
return path.reverseFind('\\') + 1;
}
Int lastCRCDebugFrame = 0;
Int lastCRCDebugIndex = 0;
extern Bool inCRCGen;
void addCRCDebugLine(const char *fmt, ...)
{
if (dumped)// || inCRCGen /*|| !TheGameLogic->isInGameLogicUpdate()*/)
return;
if (IS_FRAME_OK_TO_LOG)
{
if (lastCRCDebugFrame != TheGameLogic->getFrame())
{
lastCRCDebugFrame = TheGameLogic->getFrame();
lastCRCDebugIndex = 0;
}
sprintf(DebugStrings[nextDebugString], "%d:%d ", TheGameLogic->getFrame(), lastCRCDebugIndex++);
//DebugStrings[nextDebugString][0] = 0;
Int len = strlen(DebugStrings[nextDebugString]);
va_list va;
va_start( va, fmt );
_vsnprintf(DebugStrings[nextDebugString]+len, 1024-len, fmt, va );
DebugStrings[nextDebugString][1023] = 0;
va_end( va );
char *tmp = DebugStrings[nextDebugString];
while (tmp && *tmp)
{
if (*tmp == '\r' || *tmp == '\n')
{
*tmp = ' ';
}
++tmp;
}
//DEBUG_LOG(("%s\n", DebugStrings[nextDebugString]));
++nextDebugString;
++numDebugStrings;
if (nextDebugString == MaxStrings)
nextDebugString = 0;
}
}
void addCRCGenLine(const char *fmt, ...)
{
if (dumped || !(IS_FRAME_OK_TO_LOG))
return;
static char buf[1024];
va_list va;
va_start( va, fmt );
_vsnprintf(buf, 1024, fmt, va );
va_end( va );
buf[1023] = 0;
addCRCDebugLine("%s", buf);
//DEBUG_LOG(("%s", buf));
}
void addCRCDumpLine(const char *fmt, ...)
{
/*
va_list va;
va_start( va, fmt );
_vsnprintf(DumpStrings[nextDumpString], 1024, fmt, va );
DumpStrings[nextDumpString][1023] = 0;
va_end( va );
++nextDumpString;
++numDumpStrings;
if (nextDumpString == MaxStrings)
nextDumpString = 0;
*/
}
void dumpVector3(const Vector3 *v, AsciiString name, AsciiString fname, Int line)
{
if (dumped)
return;
if (!(IS_FRAME_OK_TO_LOG)) return;
fname.toLower();
fname = getFname(fname);
addCRCDebugLine("dumpVector3() %s:%d %s %8.8X %8.8X %8.8X\n",
fname.str(), line, name.str(),
AS_INT(v->X), AS_INT(v->Y), AS_INT(v->Z));
}
void dumpCoord3D(const Coord3D *c, AsciiString name, AsciiString fname, Int line)
{
if (dumped)
return;
if (!(IS_FRAME_OK_TO_LOG)) return;
fname.toLower();
fname = getFname(fname);
addCRCDebugLine("dumpCoord3D() %s:%d %s %8.8X %8.8X %8.8X\n",
fname.str(), line, name.str(),
AS_INT(c->x), AS_INT(c->y), AS_INT(c->z));
}
void dumpMatrix3D(const Matrix3D *m, AsciiString name, AsciiString fname, Int line)
{
if (dumped)
return;
if (!(IS_FRAME_OK_TO_LOG)) return;
fname.toLower();
fname = getFname(fname);
const Real *matrix = (const Real *)m;
addCRCDebugLine("dumpMatrix3D() %s:%d %s\n",
fname.str(), line, name.str());
for (Int i=0; i<3; ++i)
addCRCDebugLine(" 0x%08X 0x%08X 0x%08X 0x%08X\n",
AS_INT(matrix[(i<<2)+0]), AS_INT(matrix[(i<<2)+1]), AS_INT(matrix[(i<<2)+2]), AS_INT(matrix[(i<<2)+3]));
}
void dumpReal(Real r, AsciiString name, AsciiString fname, Int line)
{
if (dumped)
return;
if (!(IS_FRAME_OK_TO_LOG)) return;
fname.toLower();
fname = getFname(fname);
addCRCDebugLine("dumpReal() %s:%d %s %8.8X (%f)\n",
fname.str(), line, name.str(), AS_INT(r), r);
}
#endif // DEBUG_CRC