/* ** Command & Conquer Renegade(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 . */ #include "systeminfolog.h" #include "registry.h" #include "timemgr.h" #include "debug.h" #include "playerdata.h" #include "combat.h" #include "cheatmgr.h" #include "objectives.h" #include "ffactory.h" #include "savegame.h" //#pragma warning (disable : 4201) // nonstandard extension - nameless struct //#include "systimer.h" #include "systimer.h" #include "specialbuilds.h" const unsigned NUM_GAMES_LOGGED=10; //#define COMBAT_SUB_KEY_NAME_DEBUG "Software\\Westwood\\Renegade\\Debug" #if defined(FREEDEDICATEDSERVER) #define COMBAT_SUB_KEY_NAME_DEBUG "Software\\Westwood\\RenegadeFDS\\Debug" #elif defined(MULTIPLAYERDEMO) #define COMBAT_SUB_KEY_NAME_DEBUG "Software\\Westwood\\RenegadeMPDemo\\Debug" #elif defined(BETACLIENT) #define COMBAT_SUB_KEY_NAME_DEBUG "Software\\Westwood\\RenegadeBeta\\Debug" #elif defined(BETASERVER) #define COMBAT_SUB_KEY_NAME_DEBUG "Software\\Westwood\\RenegadeBeta\\Debug" #else #define COMBAT_SUB_KEY_NAME_DEBUG "Software\\Westwood\\Renegade\\Debug" #endif #define SYSTEM_INFO_LOG_CURRENT_STATE "SystemInfoLog_CurrentState" #define SYSTEM_INFO_LOG_LATEST_GAME "SystemInfoLog_LatestGame" static int Team0TotalSizes; static int Team0SizeReported; static int Team1TotalSizes; static int Team1SizeReported; static unsigned AvgFPS; static unsigned MinFPS; static unsigned VeryMinFPS; static unsigned MaxFPS; static unsigned VeryMaxFPS; static unsigned CurrentTotalFPS; static unsigned CurrentFPSCount; static unsigned CurrentLoadingTime; static unsigned PlayingStartTime; static unsigned TotalPlayingTime; static StringClass CurrentLevel; static StringClass CurrentString; static void Get_Latest_Game_String(RegistryClass& reg, int i, StringClass& string) { StringClass keyname(0,true); keyname.Format("%s%d",SYSTEM_INFO_LOG_LATEST_GAME,i+1); reg.Get_String(keyname, string); } static void Set_Latest_Game_String(RegistryClass& reg, int i, const StringClass& string) { StringClass keyname(0,true); keyname.Format("%s%d",SYSTEM_INFO_LOG_LATEST_GAME,i+1); reg.Set_String(keyname, string); } void SystemInfoLog::Set_State_Loading() { VeryMinFPS=1000; MinFPS=1000; VeryMaxFPS=0; MaxFPS=0; CurrentTotalFPS=0; CurrentFPSCount=0; CurrentLoadingTime=0; RegistryClass registry( COMBAT_SUB_KEY_NAME_DEBUG ); if ( registry.Is_Valid() ) { registry.Set_Int( SYSTEM_INFO_LOG_CURRENT_STATE, 1 ); StringClass string(0,true); for (int i=NUM_GAMES_LOGGED-1;i>0;--i) { Get_Latest_Game_String(registry,i-1,string); Set_Latest_Game_String(registry,i,string); } Get_Final_String(CurrentString); CurrentString+="Crashed while loading"; Set_Latest_Game_String(registry, 0, CurrentString ); } } void SystemInfoLog::Set_Current_Level(const char* level_name) { CurrentLevel=level_name; RegistryClass registry( COMBAT_SUB_KEY_NAME_DEBUG ); if ( registry.Is_Valid() ) { Get_Final_String(CurrentString); CurrentString+="Crashed while loading"; Set_Latest_Game_String(registry,0,CurrentString ); } } void SystemInfoLog::Set_State_Playing() { RegistryClass registry( COMBAT_SUB_KEY_NAME_DEBUG ); if ( registry.Is_Valid() ) { registry.Set_Int( SYSTEM_INFO_LOG_CURRENT_STATE, 2 ); Get_Final_String(CurrentString); CurrentString+="Crashed while playing"; Set_Latest_Game_String(registry,0,CurrentString ); } PlayingStartTime=TIMEGETTIME(); } void SystemInfoLog::Get_Final_String(StringClass& string) { StringClass vnum(0,true); StringClass ptime(0,true); StringClass avgfps(0,true); vnum.Format("%d.%2.2d",DebugManager::Get_Version_Number()>>16,DebugManager::Get_Version_Number()&0xffff); ptime.Format("%2.2d:%2.2d",TotalPlayingTime/60,TotalPlayingTime%60); avgfps.Format("%d.%1.1d",AvgFPS/10,AvgFPS%10); string.Format( "%5s %16s %6s %6d %6d %6s %8d ", vnum, CurrentLevel, ptime, MinFPS!=1000 ? MinFPS : 0, MaxFPS, avgfps, CurrentLoadingTime); } void SystemInfoLog::Set_State_Exiting() { TotalPlayingTime=(TIMEGETTIME()-PlayingStartTime)/1000; AvgFPS=0; if (CurrentFPSCount) { AvgFPS=CurrentTotalFPS*10/CurrentFPSCount; } RegistryClass registry( COMBAT_SUB_KEY_NAME_DEBUG ); if ( registry.Is_Valid() ) { registry.Set_Int( SYSTEM_INFO_LOG_CURRENT_STATE, 3 ); Get_Final_String(CurrentString); CurrentString+="Crashed while exiting."; Set_Latest_Game_String(registry,0,CurrentString); } } void SystemInfoLog::Reset_State() { RegistryClass registry( COMBAT_SUB_KEY_NAME_DEBUG ); if ( registry.Is_Valid() ) { int old_state=registry.Get_Int( SYSTEM_INFO_LOG_CURRENT_STATE); registry.Set_Int( SYSTEM_INFO_LOG_CURRENT_STATE, 0 ); // If was exiting... if (old_state==3) { Get_Final_String(CurrentString); CurrentString+="OK"; Set_Latest_Game_String(registry,0,CurrentString); } } CurrentLevel=""; } void SystemInfoLog::Record_Loading_Time(unsigned loading_time) { CurrentLoadingTime=loading_time; } void SystemInfoLog::Record_Frame() { unsigned fps=TimeManager::Get_Average_Frame_Rate(); CurrentTotalFPS+=fps; CurrentFPSCount++; if (fpsVeryMaxFPS) { VeryMaxFPS=fps; } else if (fps>MaxFPS) { MaxFPS=fps; } } void SystemInfoLog::Get_Log(StringClass& string) { RegistryClass registry( COMBAT_SUB_KEY_NAME_DEBUG ); if ( registry.Is_Valid() ) { string.Format( "Ten latest levels played:\r\n" "%3s %5s %16s %6s %6s %6s %6s %8s %s\r\n", "#", "Build", "Level", "Length", "MinFPS", "MaxFPS", "AvgFPS", "LoadTime", "Status"); StringClass tmp_string(0,true); for (int i=0;iGet_Game_Time()==0.0f) return; #ifdef WWDEBUG StringClass tmp; StringClass work(0,true); ADD_HISTORY(("Map name: %s\r\n",CurrentMapName)); ADD_HISTORY(("Game time: %2.2f\r\n",data->Get_Game_Time())); ADD_HISTORY(("Session time: %2.2f\r\n",data->Get_Session_Time())); ADD_HISTORY(("Enemies killed: %d\r\n",data->Get_Enemies_Killed())); ADD_HISTORY(("Allies killed: %d\r\n",data->Get_Allies_Killed())); ADD_HISTORY(("Shots fired: %d\r\n",data->Get_Shots_Fired())); ADD_HISTORY(("Powerups collected: %d\r\n",data->Get_Powerups_Collected())); ADD_HISTORY(("Vehicles destroyed: %d\r\n",data->Get_Vehiclies_Destroyed())); ADD_HISTORY(("Buildings destroyed: %d\r\n",data->Get_Building_Destroyed())); ADD_HISTORY(("Time in vehicles: %d\r\n",data->Get_Vehicle_Time())); ADD_HISTORY(("Kills from vehicles: %d\r\n",data->Get_Kills_From_Vehicle())); ADD_HISTORY(("Squishes: %d\r\n",data->Get_Squishes())); ADD_HISTORY(("Credits granted: %d\r\n",data->Get_Credit_Grant())); ADD_HISTORY(("Times reloaded: %d\r\n",CombatManager::Get_Reload_Count())); ADD_HISTORY(("Cheats used: %s\r\n",CheatMgrClass::Get_Instance()->Was_Cheat_Used( CheatMgrClass::ALL_CHEATS ) ? "Yes" : "No")); ADD_HISTORY(("Secondary objectives completed: %d\r\n",ObjectiveManager::Get_Num_Completed_Objectives( ObjectiveManager::TYPE_SECONDARY ))); ADD_HISTORY(("Tertiary objectives completed: %d\r\n",ObjectiveManager::Get_Num_Completed_Objectives( ObjectiveManager::TYPE_TERTIARY ))); tmp+="\r\n"; DWORD written; HANDLE file = CreateFile("history.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != file) { SetFilePointer(file, 0, NULL, FILE_END); WriteFile(file, tmp, strlen(tmp), &written, NULL); CloseHandle(file); } #endif // WWDEBUG } void PlayerInfoLog::Get_Compact_Log(StringClass& string) { int team0size=0; int team1size=0; if (Team0SizeReported) { team0size=10*Team0TotalSizes/Team0SizeReported; } if (Team1SizeReported) { team1size=10*Team1TotalSizes/Team1SizeReported; } string.Format("%s\t%d.%d\t%d.%d\t",CurrentMapName,team0size/10,team0size%10,team1size/10,team1size%10); Team0SizeReported=0; Team1SizeReported=0; Team0TotalSizes=0; Team1TotalSizes=0; } void PlayerInfoLog::Report_Tally_Size(int type, int size) { if (type==0) { Team0TotalSizes+=size; Team0SizeReported++; } else if (type==1) { Team1TotalSizes+=size; Team1SizeReported++; } }