Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.

This commit is contained in:
LFeenanEA 2025-02-27 17:34:39 +00:00
parent 2e338c00cb
commit 3d0ee53a05
No known key found for this signature in database
GPG key ID: C6EBE8C2EA08F7E0
6072 changed files with 2283311 additions and 0 deletions

View file

@ -0,0 +1,521 @@
/*
** 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 O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : WWDebug *
* *
* $Archive:: /Commando/Code/wwdebug/wwdebug.cpp $*
* *
* $Author:: Greg_h $*
* *
* $Modtime:: 1/13/02 1:46p $*
* *
* $Revision:: 16 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* WWDebug_Install_Message_Handler -- install function for handling the debug messages *
* WWDebug_Install_Assert_Handler -- Install a function for handling the assert messages *
* WWDebug_Install_Trigger_Handler -- install a trigger handler function *
* WWDebug_Printf -- Internal function for passing messages to installed handler *
* WWDebug_Assert_Fail -- Internal function for passing assert messages to installed handler *
* WWDebug_Assert_Fail_Print -- Internal function, passes assert message to handler *
* WWDebug_Check_Trigger -- calls the user-installed debug trigger handler *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "wwdebug.h"
#include <windows.h>
//#include "win.h" can use this if allowed to see wwlib
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <signal.h>
#include "except.h"
static PrintFunc _CurMessageHandler = NULL;
static AssertPrintFunc _CurAssertHandler = NULL;
static TriggerFunc _CurTriggerHandler = NULL;
static ProfileFunc _CurProfileStartHandler = NULL;
static ProfileFunc _CurProfileStopHandler = NULL;
// Convert the latest system error into a string and return a pointer to
// a static buffer containing the error string.
void Convert_System_Error_To_String(int id, char* buffer, int buf_len)
{
#ifndef _UNIX
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
id,
0,
buffer,
buf_len,
NULL);
#endif
}
int Get_Last_System_Error()
{
return GetLastError();
}
/***********************************************************************************************
* WWDebug_Install_Message_Handler -- install function for handling the debug messages *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/19/98 GTH : Created. *
*=============================================================================================*/
PrintFunc WWDebug_Install_Message_Handler(PrintFunc func)
{
PrintFunc tmp = _CurMessageHandler;
_CurMessageHandler = func;
return tmp;
}
/***********************************************************************************************
* WWDebug_Install_Assert_Handler -- Install a function for handling the assert messages *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/19/98 GTH : Created. *
*=============================================================================================*/
AssertPrintFunc WWDebug_Install_Assert_Handler(AssertPrintFunc func)
{
AssertPrintFunc tmp = _CurAssertHandler;
_CurAssertHandler = func;
return tmp;
}
/***********************************************************************************************
* WWDebug_Install_Trigger_Handler -- install a trigger handler function *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/24/98 GTH : Created. *
*=============================================================================================*/
TriggerFunc WWDebug_Install_Trigger_Handler(TriggerFunc func)
{
TriggerFunc tmp = _CurTriggerHandler;
_CurTriggerHandler = func;
return tmp;
}
/***********************************************************************************************
* WWDebug_Install_Profile_Start_Handler -- install a profile handler function *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/24/98 GTH : Created. *
*=============================================================================================*/
ProfileFunc WWDebug_Install_Profile_Start_Handler(ProfileFunc func)
{
ProfileFunc tmp = _CurProfileStartHandler;
_CurProfileStartHandler = func;
return tmp;
}
/***********************************************************************************************
* WWDebug_Install_Profile_Stop_Handler -- install a profile handler function *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/24/98 GTH : Created. *
*=============================================================================================*/
ProfileFunc WWDebug_Install_Profile_Stop_Handler(ProfileFunc func)
{
ProfileFunc tmp = _CurProfileStopHandler;
_CurProfileStopHandler = func;
return tmp;
}
/***********************************************************************************************
* WWDebug_Printf -- Internal function for passing messages to installed handler *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/19/98 GTH : Created. *
*=============================================================================================*/
void WWDebug_Printf(const char * format,...)
{
if (_CurMessageHandler != NULL) {
va_list va;
char buffer[4096];
va_start(va, format);
vsprintf(buffer, format, va);
WWASSERT((strlen(buffer) < sizeof(buffer)));
_CurMessageHandler(WWDEBUG_TYPE_INFORMATION, buffer);
va_end(va);
}
}
/***********************************************************************************************
* WWDebug_Printf_Warning -- Internal function for passing messages to installed handler *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/19/98 GTH : Created. *
*=============================================================================================*/
void WWDebug_Printf_Warning(const char * format,...)
{
if (_CurMessageHandler != NULL) {
va_list va;
char buffer[4096];
va_start(va, format);
vsprintf(buffer, format, va);
WWASSERT((strlen(buffer) < sizeof(buffer)));
_CurMessageHandler(WWDEBUG_TYPE_WARNING, buffer);
va_end(va);
}
}
/***********************************************************************************************
* WWDebug_Printf_Error -- Internal function for passing messages to installed handler *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/19/98 GTH : Created. *
*=============================================================================================*/
void WWDebug_Printf_Error(const char * format,...)
{
if (_CurMessageHandler != NULL) {
va_list va;
char buffer[4096];
va_start(va, format);
vsprintf(buffer, format, va);
WWASSERT((strlen(buffer) < sizeof(buffer)));
_CurMessageHandler(WWDEBUG_TYPE_ERROR, buffer);
va_end(va);
}
}
/***********************************************************************************************
* WWDebug_Assert_Fail -- Internal function for passing assert messages to installed handler *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/19/98 GTH : Created. *
*=============================================================================================*/
#ifdef WWDEBUG
void WWDebug_Assert_Fail(const char * expr,const char * file, int line)
{
if (_CurAssertHandler != NULL) {
char buffer[4096];
sprintf(buffer,"%s (%d) Assert: %s\n",file,line,expr);
_CurAssertHandler(buffer);
} else {
/*
// If the exception handler is try to quit the game then don't show an assert.
*/
if (Is_Trying_To_Exit()) {
ExitProcess(0);
}
char assertbuf[4096];
sprintf(assertbuf, "Assert failed\n\n. File %s Line %d", file, line);
int code = MessageBoxA(NULL, assertbuf, "WWDebug_Assert_Fail", MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL);
if (code == IDABORT) {
raise(SIGABRT);
_exit(3);
}
if (code == IDRETRY) {
_asm int 3;
return;
}
}
}
#endif
/***********************************************************************************************
* _assert -- Catch all asserts by overriding lib function *
* *
* *
* *
* INPUT: Assert stuff *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 12/11/2001 3:56PM ST : Created *
*=============================================================================================*/
#if 0 //(gth) this is giving me link errors for some reason...
#ifndef W3D_MAX4
#ifdef WWDEBUG
void __cdecl _assert(void *expr, void *filename, unsigned lineno)
{
WWDebug_Assert_Fail((const char*)expr, (const char*)filename, lineno);
}
#endif //WWDEBUG
#endif
#endif
/***********************************************************************************************
* WWDebug_Assert_Fail_Print -- Internal function, passes assert message to handler *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/19/98 GTH : Created. *
*=============================================================================================*/
#ifdef WWDEBUG
void WWDebug_Assert_Fail_Print(const char * expr,const char * file, int line,const char * string)
{
if (_CurAssertHandler != NULL) {
char buffer[4096];
sprintf(buffer,"%s (%d) Assert: %s %s\n",file,line,expr, string);
_CurAssertHandler(buffer);
} else {
assert(0);
}
}
#endif
/***********************************************************************************************
* WWDebug_Check_Trigger -- calls the user-installed debug trigger handler *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/24/98 GTH : Created. *
*=============================================================================================*/
bool WWDebug_Check_Trigger(int trigger_num)
{
if (_CurTriggerHandler != NULL) {
return _CurTriggerHandler(trigger_num);
} else {
return false;
}
}
/***********************************************************************************************
* WWDebug_Profile_Start -- calls the user-installed profile start handler *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/24/98 GTH : Created. *
*=============================================================================================*/
void WWDebug_Profile_Start( const char * title)
{
if (_CurProfileStartHandler != NULL) {
_CurProfileStartHandler( title );
}
}
/***********************************************************************************************
* WWDebug_Profile_Stop -- calls the user-installed profile start handler *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/24/98 GTH : Created. *
*=============================================================================================*/
void WWDebug_Profile_Stop( const char * title)
{
if (_CurProfileStopHandler != NULL) {
_CurProfileStopHandler( title );
}
}
#ifdef WWDEBUG
/***********************************************************************************************
* WWDebug_DBWin32_Message_Handler -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 10/30/98 BMG : Created. *
*=============================================================================================*/
void WWDebug_DBWin32_Message_Handler( const char * str )
{
HANDLE heventDBWIN; /* DBWIN32 synchronization object */
HANDLE heventData; /* data passing synch object */
HANDLE hSharedFile; /* memory mapped file shared data */
LPSTR lpszSharedMem;
/* make sure DBWIN is open and waiting */
heventDBWIN = OpenEvent(EVENT_MODIFY_STATE, FALSE, "DBWIN_BUFFER_READY");
if ( !heventDBWIN )
{
//MessageBox(NULL, "DBWIN_BUFFER_READY nonexistent", NULL, MB_OK);
return;
}
/* get a handle to the data synch object */
heventData = OpenEvent(EVENT_MODIFY_STATE, FALSE, "DBWIN_DATA_READY");
if ( !heventData )
{
// MessageBox(NULL, "DBWIN_DATA_READY nonexistent", NULL, MB_OK);
CloseHandle(heventDBWIN);
return;
}
hSharedFile = CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE, 0, 4096, "DBWIN_BUFFER");
if (!hSharedFile)
{
//MessageBox(NULL, "DebugTrace: Unable to create file mapping object DBWIN_BUFFER", "Error", MB_OK);
CloseHandle(heventDBWIN);
CloseHandle(heventData);
return;
}
lpszSharedMem = (LPSTR)MapViewOfFile(hSharedFile, FILE_MAP_WRITE, 0, 0, 512);
if (!lpszSharedMem)
{
//MessageBox(NULL, "DebugTrace: Unable to map shared memory", "Error", MB_OK);
CloseHandle(heventDBWIN);
CloseHandle(heventData);
return;
}
/* wait for buffer event */
WaitForSingleObject(heventDBWIN, INFINITE);
/* write it to the shared memory */
*((LPDWORD)lpszSharedMem) = 0;
wsprintf(lpszSharedMem + sizeof(DWORD), "%s", str);
/* signal data ready event */
SetEvent(heventData);
/* clean up handles */
CloseHandle(hSharedFile);
CloseHandle(heventData);
CloseHandle(heventDBWIN);
return;
}
#endif // WWDEBUG

View file

@ -0,0 +1,196 @@
# Microsoft Developer Studio Project File - Name="wwdebug" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=wwdebug - Win32 DebugW3D
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "wwdebug.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "wwdebug.mak" CFG="wwdebug - Win32 DebugW3D"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "wwdebug - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "wwdebug - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE "wwdebug - Win32 Profile" (based on "Win32 (x86) Static Library")
!MESSAGE "wwdebug - Win32 Internal" (based on "Win32 (x86) Static Library")
!MESSAGE "wwdebug - Win32 DebugW3D" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/Commando/Code/wwdebug", OPNAAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "wwdebug - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /G6 /MD /W3 /WX /Gi /GX /O2 /Ob2 /I "..\wwlib" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "NDEBUG" /D "WIN32" /D "IG_DEBUG_STACKTRACE" /YX /FD /c
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"..\..\..\Lib\WWDebug.lib"
!ELSEIF "$(CFG)" == "wwdebug - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /G6 /MDd /W3 /WX /Gi /Zi /Od /Ob2 /I "..\wwlib" /D "_DEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /D "WWDEBUG" /YX /FD /c
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"..\..\..\Lib\WWDebugDebug.lib"
!ELSEIF "$(CFG)" == "wwdebug - Win32 Profile"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "wwdebug_"
# PROP BASE Intermediate_Dir "wwdebug_"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Profile"
# PROP Intermediate_Dir "Profile"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /WX /GX /Zi /O2 /Op /Ob2 /I "..\wwlib" /I "$(ProjDir)/DXSDK\INCLUDE" /I "../STLPORT" /I "../DXSDK/INCLUDE" /D "NDEBUG" /D "WWDEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /D "_PROFILE" /YX /FD /Gh /c
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo /out:"..\Libs\release\wwdebug.lib"
# ADD LIB32 /nologo /out:"..\..\..\Lib\WWDebugProfile.lib"
!ELSEIF "$(CFG)" == "wwdebug - Win32 Internal"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Internal"
# PROP BASE Intermediate_Dir "Internal"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Internal"
# PROP Intermediate_Dir "Internal"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MD /W3 /Gi /GX /O2 /Ob2 /I "..\wwlib" /D "NDEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /YX /FD /c
# SUBTRACT BASE CPP /Fr
# ADD CPP /nologo /G6 /MD /W3 /WX /Gi /GX /Zi /O2 /I "..\wwlib" /D "NDEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /D "_INTERNAL" /D "WWDEBUG" /Fr /YX /FD /c
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo /out:"..\..\..\Lib\WWDebug.lib"
# ADD LIB32 /nologo /out:"..\..\..\Lib\WWDebugInternal.lib"
!ELSEIF "$(CFG)" == "wwdebug - Win32 DebugW3D"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Max4Release"
# PROP BASE Intermediate_Dir "Max4Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "DebugW3D"
# PROP Intermediate_Dir "DebugW3D"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MDd /W3 /WX /Gm /Gi /GR /GX /ZI /Od /I "..\wwlib" /D "_DEBUG" /D "WWDEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /Fr /YX /FD /c
# ADD CPP /nologo /G6 /MDd /W3 /WX /Gi /GX /Zi /O2 /I "..\wwlib" /D "_DEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /D "WWDEBUG" /YX /FD /c
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo /out:"..\Libs\Max4Release\wwdebug.lib"
# ADD LIB32 /nologo /out:"..\..\..\Lib\WWDebugDebugW3D.lib"
!ENDIF
# Begin Target
# Name "wwdebug - Win32 Release"
# Name "wwdebug - Win32 Debug"
# Name "wwdebug - Win32 Profile"
# Name "wwdebug - Win32 Internal"
# Name "wwdebug - Win32 DebugW3D"
# Begin Group "Source"
# PROP Default_Filter "cpp;c"
# Begin Source File
SOURCE=.\wwdebug.cpp
# End Source File
# Begin Source File
SOURCE=.\wwmemlog.cpp
# End Source File
# Begin Source File
SOURCE=.\wwprofile.cpp
# End Source File
# End Group
# Begin Group "Headers"
# PROP Default_Filter "h"
# Begin Source File
SOURCE=.\wwdebug.h
# End Source File
# Begin Source File
SOURCE=.\wwhack.h
# End Source File
# Begin Source File
SOURCE=.\wwmemlog.h
# End Source File
# Begin Source File
SOURCE=.\wwprofile.h
# End Source File
# End Group
# End Target
# End Project

View file

@ -0,0 +1,176 @@
/*
** 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 O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : WWDebug *
* *
* $Archive:: /Commando/Code/wwdebug/wwdebug.h $*
* *
* $Author:: Jani_p $*
* *
* $Modtime:: 5/04/01 7:43p $*
* *
* $Revision:: 18 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#ifndef WWDEBUG_H
#define WWDEBUG_H
// The macro MESSAGE allows user to put:
// #pragma MESSAGE("Hello world")
// anywhere in a source file. The message:
// sourcefname.cpp (123) : Hello world
// would be printed if put in sourcefname.cpp on line 123 in compile window like an error.
// You can then use next/prev error hot keys to see where comment is. It is not an error and
// will be printed everytime it is compiled. Very useful to put comments in code that cannot
// be forgoten.
#define STRING_IT(a) #a
#define TOKEN_IT(a) STRING_IT(,##a)
#define MESSAGE(a) message (__FILE__ "(" TOKEN_IT(__LINE__) ") : " a)
void Convert_System_Error_To_String(int error_id, char* buffer, int buf_len);
int Get_Last_System_Error();
/*
** If 'WWDEBUG' is turned off, all WWDEBUG_xxx macros will
** be discarded.
*/
typedef enum {
WWDEBUG_TYPE_INFORMATION,
WWDEBUG_TYPE_WARNING,
WWDEBUG_TYPE_ERROR,
WWDEBUG_TYPE_USER
} DebugType;
typedef void (*PrintFunc)(DebugType type, const char * message);
typedef void (*AssertPrintFunc)(const char * message);
typedef bool (*TriggerFunc)(int trigger_num);
typedef void (*ProfileFunc)(const char * title);
PrintFunc WWDebug_Install_Message_Handler(PrintFunc func);
AssertPrintFunc WWDebug_Install_Assert_Handler(AssertPrintFunc func);
TriggerFunc WWDebug_Install_Trigger_Handler(TriggerFunc func);
ProfileFunc WWDebug_Install_Profile_Start_Handler(ProfileFunc func);
ProfileFunc WWDebug_Install_Profile_Stop_Handler(ProfileFunc func);
/*
** Users should not call the following three functions directly! Use the macros below instead...
*/
void WWDebug_Printf(const char * format,...);
void WWDebug_Printf_Warning(const char * format,...);
void WWDebug_Printf_Error(const char * format,...);
#ifdef WWDEBUG
void WWDebug_Assert_Fail(const char * expr,const char * file, int line);
void WWDebug_Assert_Fail_Print(const char * expr,const char * file, int line,const char * string);
bool WWDebug_Check_Trigger(int trigger_num);
void WWDebug_Profile_Start( const char * title);
void WWDebug_Profile_Stop( const char * title);
/*
** A message handler to display to DBWIN32
*/
void WWDebug_DBWin32_Message_Handler( const char * message);
#endif
/*
** Use the following #define so that all of the debugging messages
** and strings go away when the release version is built.
** WWDEBUG_SAY(("dir = %f\n",dir));
*/
#include "..\..\..\..\gameengine\include\common\debug.h"
#ifdef DEBUG_LOGGING
#define WWDEBUG_SAY(x) DEBUG_LOG(x)
#define WWDEBUG_WARNING(x) DEBUG_LOG(x)
#else
#define WWDEBUG_SAY(x)
#define WWDEBUG_WARNING(x)
#endif
// WW3d is compiled at warning level 4, causes DEBUG_ASSERTCRASH to generate
// the 4127 warning (constant conditional expression)
#pragma warning(disable:4127)
#define WWRELEASE_SAY(x) WWDebug_Printf x
#define WWRELEASE_WARNING(x) WWDebug_Printf_Warning x
#define WWRELEASE_ERROR(x) WWDebug_Printf_Error x
/*
** The WWASSERT and WWASSERT_PRINT macros will send messages to your
** assert handler.
*/
#ifdef DEBUG_CRASHING
#define WWASSERT(expr) DEBUG_ASSERTCRASH(expr, ("%s, %s, %d", #expr,__FILE__,__LINE__))
#define WWASSERT_PRINT( expr, string ) DEBUG_ASSERTCRASH(expr, ("%s, %s, %d - %s", #expr,__FILE__,__LINE__,string))
#define W3D_DIE DEBUG_CRASH(("DIE!, %s, %d", __FILE__,__LINE__))
#define WWDEBUG_ERROR(x) DEBUG_CRASH(x)
#else
#define WWASSERT( expr )
#define WWASSERT_PRINT( expr, string )
#define W3D_DIE
#define WWDEBUG_ERROR(x)
#endif
/*
** The WWDEBUG_BREAK macro will cause the application to break into
** the debugger...
*/
#ifdef WWDEBUG
#define WWDEBUG_BREAK _asm int 0x03
#else
#define WWDEBUG_BREAK _asm int 0x03
#endif
/*
** The WWDEBUG_TRIGGER macro can be used to ask the application if
** a debug trigger is set. We define a couple of generic triggers
** for casual use.
*/
#define WWDEBUG_TRIGGER_GENERIC0 0
#define WWDEBUG_TRIGGER_GENERIC1 1
#ifdef WWDEBUG
#define WWDEBUG_TRIGGER(x) WWDebug_Check_Trigger(x)
#else
#define WWDEBUG_TRIGGER(x) (0)
#endif
/*
** The WWDEBUG_PROFILE macros can be used to time blocks of code
*/
#ifdef WWDEBUG
#define WWDEBUG_PROFILE_START(x) WWDebug_Profile_Start(x)
#define WWDEBUG_PROFILE_STOP(x) WWDebug_Profile_Stop(x)
#else
#define WWDEBUG_PROFILE_START(x)
#define WWDEBUG_PROFILE_STOP(x)
#endif
#endif

View file

@ -0,0 +1,50 @@
/*
** 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 O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : WWDebug *
* *
* $Archive:: /Commando/Code/wwdebug/wwhack.h $*
* *
* $Author:: Byon_g $*
* *
* $Modtime:: 10/06/99 1:09p $*
* *
* $Revision:: 2 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#ifndef WWHACK_H
#define WWHACK_H
/*
** FORCE_LINK is a hack to force a module in a lib to be linked into the EXE.
*/
#define FORCE_LINK( module ) void _Force_Link_ ## module( void ); _Force_Link_ ## module()
#define DECLARE_FORCE_LINK( module ) void _Force_Link_ ## module( void ) {}
#endif

View file

@ -0,0 +1,763 @@
/*
** 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 O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : WWDebug *
* *
* $Archive:: /Commando/Code/wwdebug/wwmemlog.cpp $*
* *
* Original Author:: Greg Hjelstrom *
* *
* $Author:: Jani_p $*
* *
* $Modtime:: 11/21/01 2:03p $*
* *
* $Revision:: 27 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* WWMemoryLogClass::Allocate_Memory -- allocates memory *
* WWMemoryLogClass::Release_Memory -- frees memory *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "always.h"
#include "wwmemlog.h"
#include "wwdebug.h"
#include "vector.h"
#include "fastallocator.h"
#include <windows.h>
#define USE_FAST_ALLOCATOR
#ifdef STEVES_NEW_CATCHER
#define DISABLE_MEMLOG 1
#else //STEVES_NEW_CATCHER
#ifdef PARAM_EDITING_ON
#define DISABLE_MEMLOG 1
#else //PARAM_EDITING_ON
#define DISABLE_MEMLOG 1
#endif //PARAM_EDITING_ON
#endif //STEVES_NEW_CATCHER*/
#ifdef USE_FAST_ALLOCATOR
#define ALLOC_MEMORY(n) FastAllocatorGeneral::Get_Allocator()->Alloc(n)
#define FREE_MEMORY(p) FastAllocatorGeneral::Get_Allocator()->Free(p)
#else
#define ALLOC_MEMORY(n) ::malloc(n)
#define FREE_MEMORY(p) ::free(p)
#endif
/*
** Enable one of the following #defines to specify which thread-sychronization
** method to use.
*/
#ifndef _UNIX
#define MEMLOG_USE_MUTEX 0
#define MEMLOG_USE_CRITICALSECTION 1
#define MEMLOG_USE_FASTCRITICALSECTION 0
#else
#undef DISABLE_MEMLOG
#define DISABLE_MEMLOG 1
#define MEMLOG_USE_MUTEX 0
#define MEMLOG_USE_CRITICALSECTION 0
#define MEMLOG_USE_FASTCRITICALSECTION 0
#endif
#if (DISABLE_MEMLOG == 0)
bool WWMemoryLogClass::IsMemoryLogEnabled=true;
#else
bool WWMemoryLogClass::IsMemoryLogEnabled=false;
#endif
static unsigned AllocateCount;
static unsigned FreeCount;
/*
** Name for each memory category. I'm padding the array with some "undefined" strings in case
** someone forgets to set the name when adding a new category.
*/
static char * _MemoryCategoryNames[] =
{
"UNKNOWN",
"Geometry",
"Animation",
"Texture",
"Pathfind",
"Vis",
"Sound",
"CullingData",
"Strings",
"GameData",
"PhysicsData",
"W3dData",
"StaticAllocations",
"GameInit",
"Renderer",
"Network",
"BINK",
"<undefined>",
"<undefined>",
"<undefined>",
"<undefined>",
};
/**
** MemoryCounterClass
** This object will store statistics for each memory category. It can provide things like
** the current amount of allocated memory and the peak amount of allocated memory.
*/
class MemoryCounterClass
{
public:
MemoryCounterClass(void) : CurrentAllocation(0), PeakAllocation(0) { }
void Memory_Allocated(int size) { CurrentAllocation+=size; PeakAllocation = max(PeakAllocation,CurrentAllocation); }
void Memory_Released(int size) { CurrentAllocation-=size; }
int Get_Current_Allocated_Memory(void) { return CurrentAllocation; }
int Get_Peak_Allocated_Memory(void) { return PeakAllocation; }
protected:
int CurrentAllocation;
int PeakAllocation;
};
/**
** ActiveCategoryStackClass
** This object is used to keep track of the "active memory category". Whenever memory is allocated
** it will be charged to the current active memory category. To be thread-safe, there will be
** one ActiveCategoryStack per thread that is encountered in the program.
*/
const int MAX_CATEGORY_STACK_DEPTH = 1024;
class ActiveCategoryStackClass : public VectorClass<int>
{
public:
ActiveCategoryStackClass(void) :
VectorClass<int>(MAX_CATEGORY_STACK_DEPTH),
ThreadID(-1),
Count(0)
{ }
// If object was created but not Init'd, ThreadID will be -1 and Count == 0
// If object was created and Init'd, ThreadID will not be -1. We expect Count to return to 1 after all Pop's
~ActiveCategoryStackClass(void) { WWASSERT((ThreadID == -1 && Count == 0) || (ThreadID != -1 && Count == 1)); }
ActiveCategoryStackClass & operator = (const ActiveCategoryStackClass & that);
bool operator == (const ActiveCategoryStackClass &) { return false; }
bool operator != (const ActiveCategoryStackClass &) { return true; }
void Init(int thread_id) { ThreadID = thread_id; Count = 0; Push(MEM_UNKNOWN); }
void Set_Thread_ID(int id) { WWASSERT(ThreadID != -1); ThreadID = id; }
int Get_Thread_ID(void) { return ThreadID; }
void Push(int active_category) { WWASSERT(ThreadID != -1); (*this)[Count] = active_category; Count++; }
void Pop(void) { WWASSERT(ThreadID != -1) ; Count--; }
int Current(void) { WWASSERT(ThreadID != -1); return (*this)[Count-1]; }
protected:
int ThreadID;
int Count;
};
/**
** ActiveCategoryClass
** This is a dynamic vector of ActiveCategoryStackClasses which adds a new stack each time
** a new thread is encountered. It also is able to return to you the active category for
** the currently active thread automatically.
*/
const int MAX_CATEGORY_STACKS = 256; // maximum number of threads we expect to encounter...
class ActiveCategoryClass : public VectorClass<ActiveCategoryStackClass>
{
public:
ActiveCategoryClass(void) : VectorClass<ActiveCategoryStackClass>(MAX_CATEGORY_STACKS), Count(0) { Get_Active_Stack().Push(MEM_STATICALLOCATION); }
void Push(int active_category) { Get_Active_Stack().Push(active_category); }
void Pop(void) { Get_Active_Stack().Pop(); }
int Current(void) { return Get_Active_Stack().Current(); }
protected:
ActiveCategoryStackClass & Get_Active_Stack(void);
int Count;
};
/**
** MemLogClass
** This class ties all of the logging datastructures together into a single object
** which can be created on demand when the first 'new' call is encountered.
*/
class MemLogClass
{
public:
int Get_Current_Allocated_Memory(int category);
int Get_Peak_Allocated_Memory(int category);
/*
** Interface for recording allocations and de-allocations
*/
int Register_Memory_Allocated(int size);
void Register_Memory_Released(int category,int size);
void Push_Active_Category(int category);
void Pop_Active_Category(void);
void Init();
private:
MemoryCounterClass _MemoryCounters[MEM_COUNT];
ActiveCategoryClass _ActiveCategoryTracker;
};
/**
** Static Variables
** _TheMemLog - object which encapsulates all logging. will be allocated on first use
** _MemLogMutex - handle to the mutex used to arbtirate access to the logging data structures
** _MemLogLockCounter - count of the active mutex locks.
*/
static MemLogClass * _TheMemLog = NULL;
static bool _MemLogAllocated = false;
#if MEMLOG_USE_MUTEX
static void * _MemLogMutex = NULL;
static int _MemLogLockCounter = 0;
#endif
#if MEMLOG_USE_CRITICALSECTION
static bool _MemLogCriticalSectionAllocated = false;
static char _MemLogCriticalSectionHandle[sizeof(CRITICAL_SECTION)];
#endif
#if MEMLOG_USE_FASTCRITICALSECTION
volatile unsigned _MemLogSemaphore = 0;
#endif
/*
** Use this code to get access to the mutex...
*/
WWINLINE void * Get_Mem_Log_Mutex(void)
{
#if MEMLOG_USE_MUTEX
if (_MemLogMutex == NULL) {
_MemLogMutex=CreateMutex(NULL,false,NULL);
WWASSERT(_MemLogMutex);
}
return _MemLogMutex;
#endif
#if MEMLOG_USE_CRITICALSECTION
if (_MemLogCriticalSectionAllocated == false) {
InitializeCriticalSection((CRITICAL_SECTION*)_MemLogCriticalSectionHandle);
_MemLogCriticalSectionAllocated = true;
}
return _MemLogCriticalSectionHandle;
#endif
}
WWINLINE void Lock_Mem_Log_Mutex(void)
{
#if MEMLOG_USE_MUTEX
void * mutex = Get_Mem_Log_Mutex();
#ifdef DEBUG_CRASHING
int res =
#endif
WaitForSingleObject(mutex,INFINITE);
WWASSERT(res==WAIT_OBJECT_0);
_MemLogLockCounter++;
#endif
#if MEMLOG_USE_CRITICALSECTION
Get_Mem_Log_Mutex();
EnterCriticalSection((CRITICAL_SECTION*)_MemLogCriticalSectionHandle);
#endif
#if MEMLOG_USE_FASTCRITICALSECTION
volatile unsigned& nFlag=_MemLogSemaphore;
#define ts_lock _emit 0xF0
assert(((unsigned)&nFlag % 4) == 0);
__asm mov ebx, [nFlag]
__asm ts_lock
__asm bts dword ptr [ebx], 0
__asm jc The_Bit_Was_Previously_Set_So_Try_Again
return;
The_Bit_Was_Previously_Set_So_Try_Again:
ThreadClass::Switch_Thread();
__asm mov ebx, [nFlag]
__asm ts_lock
__asm bts dword ptr [ebx], 0
__asm jc The_Bit_Was_Previously_Set_So_Try_Again
#endif
}
WWINLINE void Unlock_Mem_Log_Mutex(void)
{
#if MEMLOG_USE_MUTEX
void * mutex = Get_Mem_Log_Mutex();
_MemLogLockCounter--;
#ifdef DEBUG_CRASHING
int res=
#endif
ReleaseMutex(mutex);
WWASSERT(res);
#endif
#if MEMLOG_USE_CRITICALSECTION
Get_Mem_Log_Mutex();
LeaveCriticalSection((CRITICAL_SECTION*)_MemLogCriticalSectionHandle);
#endif
#if MEMLOG_USE_FASTCRITICALSECTION
_MemLogSemaphore = 0;
#endif
}
class MemLogMutexLockClass
{
public:
MemLogMutexLockClass(void) { Lock_Mem_Log_Mutex(); }
~MemLogMutexLockClass(void) { Unlock_Mem_Log_Mutex(); }
};
/***************************************************************************************************
**
** ActiveCategoryStackClass Implementation
**
***************************************************************************************************/
ActiveCategoryStackClass &
ActiveCategoryStackClass::operator = (const ActiveCategoryStackClass & that)
{
if (this != &that) {
VectorClass<int>::operator == (that);
ThreadID = that.ThreadID;
Count = that.Count;
}
return *this;
}
/***************************************************************************************************
**
** ActiveCategoryClass Implementation
**
***************************************************************************************************/
ActiveCategoryStackClass & ActiveCategoryClass::Get_Active_Stack(void)
{
int current_thread = ::GetCurrentThreadId();
/*
** If we already have an allocated category stack for the current thread,
** just return its active category.
*/
for (int i=0; i<Count; i++) {
ActiveCategoryStackClass & cat_stack = (*this)[i];
if (cat_stack.Get_Thread_ID() == current_thread) {
return cat_stack;
}
}
/*
** If we fall through to here, we need to allocate a new category stack
** for this thread.
*/
(*this)[Count].Init(current_thread);
Count++;
return (*this)[Count-1];
}
/***************************************************************************************************
**
** MemLogClass Implementation
**
***************************************************************************************************/
int MemLogClass::Get_Current_Allocated_Memory(int category)
{
MemLogMutexLockClass lock;
return _MemoryCounters[category].Get_Current_Allocated_Memory();
}
int MemLogClass::Get_Peak_Allocated_Memory(int category)
{
MemLogMutexLockClass lock;
return _MemoryCounters[category].Get_Peak_Allocated_Memory();
}
void MemLogClass::Init()
{
{
MemLogMutexLockClass lock;
WWASSERT(_ActiveCategoryTracker.Current()==MEM_STATICALLOCATION);
}
Pop_Active_Category(); // Remove staticallocation state forever
}
int MemLogClass::Register_Memory_Allocated(int size)
{
MemLogMutexLockClass lock;
int active_category = _ActiveCategoryTracker.Current();
WWASSERT((active_category >= 0) && (active_category < MEM_COUNT));
_MemoryCounters[active_category].Memory_Allocated(size);
return active_category;
}
void MemLogClass::Register_Memory_Released(int category,int size)
{
MemLogMutexLockClass lock;
_MemoryCounters[category].Memory_Released(size);
}
void MemLogClass::Push_Active_Category(int category)
{
MemLogMutexLockClass lock;
WWASSERT((category >= 0) && (category < MEM_COUNT));
_ActiveCategoryTracker.Push(category);
}
void MemLogClass::Pop_Active_Category(void)
{
MemLogMutexLockClass lock;
_ActiveCategoryTracker.Pop();
}
/***************************************************************************************************
**
** WWMemoryLogClass Implementation
**
***************************************************************************************************/
int WWMemoryLogClass::Get_Category_Count(void)
{
return MEM_COUNT;
}
const char * WWMemoryLogClass::Get_Category_Name(int category)
{
return _MemoryCategoryNames[category];
}
int WWMemoryLogClass::Get_Current_Allocated_Memory(int category)
{
return Get_Log()->Get_Current_Allocated_Memory(category);
}
int WWMemoryLogClass::Get_Peak_Allocated_Memory(int category)
{
return Get_Log()->Get_Peak_Allocated_Memory(category);
}
void WWMemoryLogClass::Push_Active_Category(int category)
{
#if (DISABLE_MEMLOG == 0)
Get_Log()->Push_Active_Category(category);
#endif //(DISABLE_MEMLOG == 0)
}
void WWMemoryLogClass::Pop_Active_Category(void)
{
#if (DISABLE_MEMLOG == 0)
Get_Log()->Pop_Active_Category();
#endif //(DISABLE_MEMLOG == 0)
}
int WWMemoryLogClass::Register_Memory_Allocated(int size)
{
return Get_Log()->Register_Memory_Allocated(size);
}
void WWMemoryLogClass::Register_Memory_Released(int category,int size)
{
Get_Log()->Register_Memory_Released(category,size);
}
static void _MemLogCleanup(void)
{
delete _TheMemLog;
}
MemLogClass * WWMemoryLogClass::Get_Log(void)
{
MemLogMutexLockClass lock;
if (_TheMemLog == NULL) {
//assert(!_MemLogAllocated);
_TheMemLog = W3DNEW MemLogClass;
#ifdef STEVES_NEW_CATCHER
/*
** This was me trying to be clever and fix the memory leak in the memlog. Unfortunately, the Get_Log member can be called
** during the process of exiting the process (IYSWIM) and you get it trying to re-allocate the MemLogClass I just freed.
** Solution is just to disable memlog when I'm trying to find memory leaks. ST - 6/18/2001 9:51PM
*/
if (!_MemLogAllocated) {
atexit(&Release_Log);
}
_MemLogAllocated = true;
#endif //STEVES_NEW_CATCHER
}
return _TheMemLog;
}
/***********************************************************************************************
* WWMemoryLogClass::Release_Log -- Free the memory used by WWMemoryLogClass so it doesn't leak*
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: Called as part of _onexit processing *
* *
* It's messy, but I assume there's a reason it's not statically allocated... *
* OK, now I get it *
* *
* HISTORY: *
* 6/13/2001 8:55PM ST : Created *
*=============================================================================================*/
void WWMemoryLogClass::Release_Log(void)
{
MemLogMutexLockClass lock;
if (_TheMemLog) {
delete _TheMemLog;
_TheMemLog = NULL;
}
}
/***************************************************************************************************
**
** Allocating and Freeing memory
**
** PLEASE NOTE: The user is expected to implement global new and delete functions in his own
** code which call WWMemoryLogClass::Allocate_Memory and WWMemoryLogClass::Release_Memory.
** This was the only solution I could come up given that some APPS have their own new and delete
** functions or enable the CRT ones. It was also not an option to move this entire system into
** the APP because I wanted all of our LIBs to participate in the memory usage logging...
**
***************************************************************************************************/
const int WWMEMLOG_KEY0 = (unsigned('G')<<24) | (unsigned('g')<<16) | (unsigned('0')<<8) | unsigned('l');
const int WWMEMLOG_KEY1 = (unsigned('~')<<24) | (unsigned('_')<<16) | (unsigned('d')<<8) | unsigned('3');
/**
** MemoryLogStruct
** This structure is added to the beginning of each memory allocation to facilitate
** tracking which category the memory belongs to when it is freed. The size of
** this struct is also 16 bytes so that we wont be seriously affecting the alignment
** of allocated memory...
*/
struct MemoryLogStruct
{
MemoryLogStruct(int category,int size) :
Key0(WWMEMLOG_KEY0),
Key1(WWMEMLOG_KEY1),
Category(category),
Size(size)
{}
bool Is_Valid_Memory_Log(void) { return ((Key0 == WWMEMLOG_KEY0) && (Key1 == WWMEMLOG_KEY1)); }
int Key0; // if this is not equal to WWMEMLOG_KEY0 then we don't have a valid log
int Key1; // should be equal to WWMEMLOG_KEY1
int Category; // category this memory belongs to
int Size; // size of the allocation
};
/***********************************************************************************************
* WWMemoryLogClass::Allocate_Memory -- allocates memory *
* *
* This function adds a header to the memory allocated so that when the memory is freed *
* the proper memory category size can be decremented. The application using this logging *
* system should call this function from inside its overloaded 'new' operator. *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 5/29/2001 gth : Created. *
*=============================================================================================*/
void * WWMemoryLogClass::Allocate_Memory(size_t size)
{
AllocateCount++;
#if DISABLE_MEMLOG
return ALLOC_MEMORY(size);
#else
__declspec( thread ) static bool reentrancy_test = false;
MemLogMutexLockClass lock;
if (reentrancy_test) {
return ALLOC_MEMORY(size);
} else {
reentrancy_test = true;
/*
** Allocate space for the requested buffer + our logging structure
*/
void * ptr = ALLOC_MEMORY(size + sizeof(MemoryLogStruct));
if (ptr != NULL) {
/*
** Record this allocation
*/
int active_category = WWMemoryLogClass::Register_Memory_Allocated(size);
/*
** Write our logging structure into the beginning of the buffer. I'm using
** placement new syntax to initialize the log structure right in the memory buffer
*/
new(ptr) MemoryLogStruct(active_category,size);
/*
** Return the allocated memory to the user, skipping past our log structure.
*/
reentrancy_test = false;
return (void*)(((char *)ptr) + sizeof(MemoryLogStruct));
} else {
reentrancy_test = false;
return ptr;
}
}
#endif //DISABLE_MEMLOG
}
/***********************************************************************************************
* WWMemoryLogClass::Release_Memory -- frees memory *
* *
* This function checks for a wwmemlog header and decrements the relevant memory category. *
* It should be called in the application's custom delete operator. *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 5/29/2001 gth : Created. *
*=============================================================================================*/
void WWMemoryLogClass::Release_Memory(void *ptr)
{
FreeCount++;
#if DISABLE_MEMLOG
FREE_MEMORY(ptr);
#else
MemLogMutexLockClass lock;
if (ptr) {
/*
** Check if this memory is preceeded by a valid MemoryLogStruct
*/
MemoryLogStruct * memlog = (MemoryLogStruct*)((char*)ptr - sizeof(MemoryLogStruct));
if (memlog->Is_Valid_Memory_Log()) {
/*
** Valid MemoryLogStruct found, track the de-allocation and pass on
** to the built-in free function.
*/
WWMemoryLogClass::Register_Memory_Released(memlog->Category,memlog->Size);
FREE_MEMORY((void*)memlog);
} else {
/*
** No valid MemoryLogStruct found, just call free on the memory.
*/
FREE_MEMORY(ptr);
}
}
#endif //DISABLE_MEMLOG
}
// Reset allocate and free counters
void WWMemoryLogClass::Reset_Counters()
{
AllocateCount=0;
FreeCount=0;
}
// Return allocate count since last reset
int WWMemoryLogClass::Get_Allocate_Count()
{
return AllocateCount;
}
// Return allocate count since last reset
int WWMemoryLogClass::Get_Free_Count()
{
return FreeCount;
}
void WWMemoryLogClass::Init()
{
Get_Log()->Init();
}

View file

@ -0,0 +1,191 @@
/*
** 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 O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : WWDebug *
* *
* $Archive:: /Commando/Code/wwdebug/wwmemlog.h $*
* *
* Original Author:: Greg Hjelstrom *
* *
* $Author:: Jani_p $*
* *
* $Modtime:: 11/09/01 6:51p $*
* *
* $Revision:: 8 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if _MSC_VER >= 1000
#pragma once
#endif
#ifndef WWMEMLOG_H
#define WWMEMLOG_H
#define LOG_MEMORY // Comment this out to disable memlog compiling in
class MemLogClass;
/**
** Memory Log Categories
** You can cause memory allocations to be "counted" against any of the following categories.
** NOTE: if you add a new category here, be sure to add its name to the array in the .cpp file...
*/
enum
{
MEM_UNKNOWN = 0,
MEM_GEOMETRY, // memory used by geometry data
MEM_ANIMATION, // memory used by animation data
MEM_TEXTURE, // memory used by textures
MEM_PATHFIND, // memory used by the pathfind system
MEM_VIS, // memory used by the vis system
MEM_SOUND, // memory used by the sound system
MEM_CULLINGDATA, // culling systems
MEM_STRINGS, // string data
MEM_GAMEDATA, // game engine datastructures
MEM_PHYSICSDATA, // physics engine datastructures
MEM_W3DDATA, // w3d datastructures (not including ones more applicable to above categories)
MEM_STATICALLOCATION,// all the allocations that happen before the memlog Init() function call are from statically allocated objects
MEM_GAMEINIT, // game init time allocations
MEM_RENDERER, // dx8 renderer
MEM_NETWORK,
MEM_BINK,
MEM_COUNT
};
/**
** WWMemoryLogClass
** This interface can provide information on how much memory has been allocated to each
** memory category. In order to enable this logging, you will need to implement global
** new and delete functions which call the Allocate_Memory and Release_Memory functions
** in this class. For example:
**
** void * ::operator new (size_t size)
** {
** return WWMemoryLogClass::Allocate_Memory(size);
** }
**
** void ::operator delete (void *ptr)
** {
** WWMemoryLogClass::Release_Memory(ptr);
** }
*/
class WWMemoryLogClass
{
public:
static void Enable_Memory_Log(bool enable) { IsMemoryLogEnabled=enable; }
static bool Is_Memory_Log_Enabled() { return IsMemoryLogEnabled; }
/*
** Accessors to the current memory map
*/
static int Get_Category_Count(void);
static const char * Get_Category_Name(int category);
static int Get_Current_Allocated_Memory(int category);
static int Get_Peak_Allocated_Memory(int category);
/*
** Interface for the debug version of new and delete
*/
static int Register_Memory_Allocated(int size);
static void Register_Memory_Released(int category,int size);
/*
** New and Delete functions. If you want to use this logging system,
** implement global new and delete functions which call into these
** functions.
*/
static void * Allocate_Memory(size_t size);
static void Release_Memory(void * mem);
static void Reset_Counters(); // Reset allocate and free counters
static int Get_Allocate_Count(); // Return allocate count since last reset
static int Get_Free_Count(); // Return allocate count since last reset
static void Init();
protected:
/*
** Interface for WWMemorySampleClass to set the active category
*/
static void Push_Active_Category(int category);
static void Pop_Active_Category(void);
static MemLogClass * Get_Log(void);
static void Release_Log(void);
static bool IsMemoryLogEnabled;
friend class WWMemorySampleClass;
};
/**
** WWMemorySampleClass
** This class is meant to be created and destroyed on the stack to automatically push
** and pop the desired memory category. NOTE: this class should not be used directly,
** instead, use the WWMEMLOG macros!
*/
class WWMemorySampleClass
{
bool category_push;
public:
WWMemorySampleClass(int category) : category_push(WWMemoryLogClass::Is_Memory_Log_Enabled())
{
if (category_push) {
WWMemoryLogClass::Push_Active_Category(category);
}
}
~WWMemorySampleClass(void)
{
if (category_push) {
WWMemoryLogClass::Pop_Active_Category();
}
}
};
/*
** Use the WWMEMLOG macro to track all memory allocations within the current scope.
** If WWDEBUG is not enabled, memory usage logging will be disabled.
*/
#ifdef USE_MEMLOG
#define WWMEMLOG( category ) WWMemorySampleClass _memsample( category )
#else
#define WWMEMLOG( category )
#endif
#endif //WWMEMLOG_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,342 @@
/*
** 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 O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : WWDebug *
* *
* $Archive:: /Commando/Code/wwdebug/wwprofile.h $*
* *
* $Author:: Jani_p $*
* *
* $Modtime:: 3/25/02 2:05p $*
* *
* $Revision:: 14 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
//#define ENABLE_TIME_AND_MEMORY_LOG
#ifndef WWPROFILE_H
#define WWPROFILE_H
#include "wwstring.h"
#ifdef _UNIX
typedef signed long long __int64;
typedef signed long long _int64;
#endif
// enable profiling by default in debug mode.
#ifdef WWDEBUG
#define ENABLE_WWPROFILE
#endif
extern unsigned WWProfile_Get_System_Time(); // timeGetTime() wrapper
class FileClass;
/*
** A node in the WWProfile Hierarchy Tree
*/
class WWProfileHierachyNodeClass {
public:
WWProfileHierachyNodeClass( const char * name, WWProfileHierachyNodeClass * parent );
WWProfileHierachyNodeClass( unsigned id, WWProfileHierachyNodeClass * parent );
~WWProfileHierachyNodeClass( void );
WWProfileHierachyNodeClass * Get_Sub_Node( const char * name );
WWProfileHierachyNodeClass * Get_Parent( void ) { return Parent; }
WWProfileHierachyNodeClass * Get_Sibling( void ) { return Sibling; }
WWProfileHierachyNodeClass * Get_Child( void ) { return Child; }
void Set_Parent( WWProfileHierachyNodeClass *node ) { Parent=node; }
void Set_Sibling( WWProfileHierachyNodeClass *node ) { Sibling=node; }
void Set_Child( WWProfileHierachyNodeClass *node ) { Child=node; }
void Reset( void );
void Call( void );
bool Return( void );
const char * Get_Name( void ) { return Name; }
int Get_Total_Calls( void ) { return TotalCalls; }
float Get_Total_Time( void ) { return TotalTime; }
void Set_Total_Calls(int calls) { TotalCalls=calls; }
void Set_Total_Time(float time) { TotalTime=time; }
WWProfileHierachyNodeClass* Clone_Hierarchy(WWProfileHierachyNodeClass* parent);
void Write_To_File(FileClass* file,int recursion);
void Add_To_String_Compact(StringClass& string,int recursion);
protected:
const char * Name;
int TotalCalls;
float TotalTime;
__int64 StartTime;
int RecursionCounter;
unsigned ProfileStringID;
WWProfileHierachyNodeClass * Parent;
WWProfileHierachyNodeClass * Child;
WWProfileHierachyNodeClass * Sibling;
};
class WWProfileHierachyInfoClass {
public:
WWProfileHierachyInfoClass( const char * name, WWProfileHierachyInfoClass * parent );
~WWProfileHierachyInfoClass( void );
WWProfileHierachyInfoClass * Get_Parent( void ) { return Parent; }
WWProfileHierachyInfoClass * Get_Sibling( void ) { return Sibling; }
WWProfileHierachyInfoClass * Get_Child( void ) { return Child; }
void Set_Parent( WWProfileHierachyInfoClass *node ) { Parent=node; }
void Set_Sibling( WWProfileHierachyInfoClass *node ) { Sibling=node; }
void Set_Child( WWProfileHierachyInfoClass *node ) { Child=node; }
const char * Get_Name( void ) { return Name; }
void Set_Name( const char* name ) { Name=name; }
int Get_Total_Calls( void ) { return TotalCalls; }
float Get_Total_Time( void ) { return TotalTime; }
void Set_Total_Calls(int calls) { TotalCalls=calls; }
void Set_Total_Time(float time) { TotalTime=time; }
protected:
StringClass Name;
int TotalCalls;
float TotalTime;
WWProfileHierachyInfoClass * Parent;
WWProfileHierachyInfoClass * Child;
WWProfileHierachyInfoClass * Sibling;
};
/*
** An iterator to navigate through the tree
*/
class WWProfileIterator
{
public:
// Access all the children of the current parent
void First(void);
void Next(void);
bool Is_Done(void);
void Enter_Child( void ); // Make the current child the new parent
void Enter_Child( int index ); // Make the given child the new parent
void Enter_Parent( void ); // Make the current parent's parent the new parent
// Access the current child
const char * Get_Current_Name( void ) { return CurrentChild->Get_Name(); }
int Get_Current_Total_Calls( void ) { return CurrentChild->Get_Total_Calls(); }
float Get_Current_Total_Time( void ) { return CurrentChild->Get_Total_Time(); }
// Access the current parent
const char * Get_Current_Parent_Name( void ) { return CurrentParent->Get_Name(); }
int Get_Current_Parent_Total_Calls( void ) { return CurrentParent->Get_Total_Calls(); }
float Get_Current_Parent_Total_Time( void ) { return CurrentParent->Get_Total_Time(); }
protected:
WWProfileHierachyNodeClass * CurrentParent;
WWProfileHierachyNodeClass * CurrentChild;
WWProfileIterator( WWProfileHierachyNodeClass * start );
friend class WWProfileManager;
};
/*
** An iterator to walk through the tree in depth first order
*/
class WWProfileInOrderIterator
{
public:
void First(void);
void Next(void);
bool Is_Done(void);
// Access the current node
const char * Get_Current_Name( void ) { return CurrentNode->Get_Name(); }
int Get_Current_Total_Calls( void ) { return CurrentNode->Get_Total_Calls(); }
float Get_Current_Total_Time( void ) { return CurrentNode->Get_Total_Time(); }
protected:
WWProfileHierachyNodeClass * CurrentNode;
WWProfileInOrderIterator( void );
friend class WWProfileManager;
};
/*
** The Manager for the WWProfile system
*/
class WWProfileManager {
public:
WWINLINE static void Enable_Profile(bool enable) { IsProfileEnabled=enable; }
WWINLINE static bool Is_Profile_Enabled() { return IsProfileEnabled; }
static void Start_Profile( const char * name );
static void Stop_Profile( void );
static void Start_Root_Profile( const char * name );
static void Stop_Root_Profile( void );
static void Reset( void );
static void Increment_Frame_Counter( void );
static int Get_Frame_Count_Since_Reset( void ) { return FrameCounter; }
static float Get_Time_Since_Reset( void );
static WWProfileIterator * Get_Iterator( void );
static void Release_Iterator( WWProfileIterator * iterator );
static WWProfileInOrderIterator * Get_In_Order_Iterator( void );
static void Release_In_Order_Iterator( WWProfileInOrderIterator * iterator );
static WWProfileHierachyNodeClass * Get_Root( void ) { return &Root; }
static void Begin_Collecting();
static void End_Collecting(const char* filename);
static void Load_Profile_Log(const char* filename, WWProfileHierachyInfoClass**& array, unsigned& count);
private:
static WWProfileHierachyNodeClass Root;
static WWProfileHierachyNodeClass * CurrentNode;
static WWProfileHierachyNodeClass * CurrentRootNode;
static int FrameCounter;
static __int64 ResetTime;
static bool IsProfileEnabled;
friend class WWProfileInOrderIterator;
};
/*
** WWProfileSampleClass is a simple way to profile a function's scope
** Use the WWPROFILE macro at the start of scope to time
*/
class WWProfileSampleClass {
bool IsRoot;
bool Enabled;
public:
WWProfileSampleClass( const char * name, bool is_root ) : IsRoot(is_root), Enabled(WWProfileManager::Is_Profile_Enabled())
{
if (Enabled) {
if (IsRoot) WWProfileManager::Start_Root_Profile( name );
else WWProfileManager::Start_Profile( name );
}
}
~WWProfileSampleClass( void )
{
if (Enabled) {
if (IsRoot) WWProfileManager::Stop_Root_Profile();
else WWProfileManager::Stop_Profile();
}
}
};
#ifdef ENABLE_WWPROFILE
#define WWPROFILE( name ) WWProfileSampleClass _wwprofile( name, false )
#define WWROOTPROFILE( name ) WWProfileSampleClass _wwprofile( name, true )
#else
#define WWPROFILE( name )
#define WWROOTPROFILE( name )
#endif
/*
** WWTimeIt is like WWProfile, but it doesn't save anything, it just times one routine, regardless of thread
*/
class WWTimeItClass {
public:
WWTimeItClass( const char * name );
~WWTimeItClass( void );
private:
const char * Name;
__int64 Time;
};
#ifdef ENABLE_WWPROFILE
#define WWTIMEIT( name ) WWTimeItClass _wwtimeit( name )
#else
#define WWTIMEIT( name )
#endif
/*
** WWMeasureItClass is like WWTimeItClass, but it pokes the result into the given float,
** and can be used in the release build.
*/
class WWMeasureItClass {
public:
WWMeasureItClass( float * p_result );
~WWMeasureItClass( void );
private:
__int64 Time;
float * PResult;
};
// ----------------------------------------------------------------------------
//
// Use the first macro to log time and memory usage within the stack segment.
// Use the second macro to log intermediate values. The intermediate values are
// calculated from the previous intermediate log, so you can log how much each
// item takes by placing the macro after each of the
//
// ----------------------------------------------------------------------------
#ifdef ENABLE_TIME_AND_MEMORY_LOG
#define WWLOG_PREPARE_TIME_AND_MEMORY(t) WWMemoryAndTimeLog memory_and_time_log(t)
#define WWLOG_INTERMEDIATE(t) memory_and_time_log.Log_Intermediate(t)
#else
#define WWLOG_PREPARE_TIME_AND_MEMORY(t)
#define WWLOG_INTERMEDIATE(t)
#endif
struct WWMemoryAndTimeLog
{
unsigned TimeStart;
unsigned IntermediateTimeStart;
int AllocCountStart;
int IntermediateAllocCountStart;
int AllocSizeStart;
int IntermediateAllocSizeStart;
StringClass Name;
static unsigned TabCount;
WWMemoryAndTimeLog(const char* name);
~WWMemoryAndTimeLog();
void Log_Intermediate(const char* text);
};
#endif // WWPROFILE_H