274 lines
6.8 KiB
C++
274 lines
6.8 KiB
C++
![]() |
/*
|
||
|
** 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
|