/* ** 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 . */ /****************************************************************************** * * FILE * $Archive: /Commando/Code/Commando/GameResSend.cpp $ * * DESCRIPTION * * PROGRAMMER * $Author: Denzil_l $ * * VERSION INFO * $Revision: 25 $ * $Modtime: 1/14/02 10:40a $ * ******************************************************************************/ #include "GameResSend.h" #include "GameData.h" #include "Player.h" #include "consolemode.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace WWOnline; static void AddPlayerStats(GameResPacket& stats, cPlayer* player, WOL::Locale locale, int winnerID, bool teamGame); /****************************************************************************** * * NAME * SendGameResults * * DESCRIPTION * Send game results for ladder ranking. * * INPUTS * TheGame - The game played. * Players - List of players. * * RESULT * NONE * ******************************************************************************/ void SendGameResults(unsigned long gameID, cGameData* theGame, SList* playerList) { RefPtr session = WWOnline::Session::GetInstance(false); if (!session.IsValid()) { assert(session.IsValid() && "SendGameResults() WOLSession not instantiated."); WWDEBUG_SAY(("ERROR: SendGameResults() WOLSession not instantiated.\n")); return; } //--------------------------------------------------------------------------- // Gather game information //--------------------------------------------------------------------------- GameResPacket stats; // Unique identifier for this game session. stats.Add_Field("IDNO", gameID); // Product SKU RefPtr product = Product::Current(); unsigned long gameSKU = product->GetSKU(); stats.Add_Field("GSKU", gameSKU); // Version of executable. char filename[MAX_PATH]; GetModuleFileName(NULL, filename, sizeof(filename)); VS_FIXEDFILEINFO version; GetVersionInfo(filename, &version); stats.Add_Field("VERS", version.dwFileVersionMS); // Executable build date FILETIME createTime; GetFileCreationTime(filename, &createTime); SYSTEMTIME time; FileTimeToSystemTime(&createTime, &time); char buildDate[20]; sprintf(buildDate, "%02d/%02d/%04d %02d:%02d:%02d", time.wMonth, time.wDay, time.wYear, time.wHour, time.wMinute, time.wSecond); stats.Add_Field("DATE", buildDate); // Proocessor information stats.Add_Field("PROC", (char*)CPUDetectClass::Get_Processor_String()); stats.Add_Field("PSPD", (unsigned long)CPUDetectClass::Get_Processor_Speed()); // Amount of system memory on server MEMORYSTATUS memStatus; GlobalMemoryStatus(&memStatus); stats.Add_Field("SMEM", (unsigned long)memStatus.dwTotalPhys); // Video card information DWORD cardInfo[4]; if (ConsoleBox.Is_Exclusive()) { strcpy((char*)&cardInfo[0], "ConsoleMode"); } else { const D3DADAPTER_IDENTIFIER8& adapter = DX8Wrapper::Get_Current_Adapter_Identifier(); cardInfo[0] = adapter.VendorId; cardInfo[1] = adapter.DeviceId; cardInfo[2] = adapter.SubSysId; cardInfo[3] = adapter.Revision; } stats.Add_Field("SVID", (void*)cardInfo, sizeof(cardInfo)); // WOL Name of server const WideStringClass& owner = theGame->Get_Owner(); StringClass serverName(true); owner.Convert_To(serverName); stats.Add_Field("SNAM", (char*)serverName.Peek_Buffer()); // Type of game played (Deathmatch, Capture the flag, CNC...) // char* gameMode = (char*)theGame->Get_Game_Type_Name(); stats.Add_Field("MODE", "CNC"); // Name of the map used. char *map_name = (char*)(theGame->Get_Map_Name().Peek_Buffer()); stats.Add_Field("GMAP", map_name); // Was this a dedicated server? bool dedicatedServer = theGame->IsDedicated.Get(); stats.Add_Field("DSVR", (char)dedicatedServer); // Time game started LPSYSTEMTIME gameTime = theGame->Get_Game_Start_Time(); char startTime[20]; sprintf(startTime, "%02d/%02d/%04d %02d:%02d:%02d", gameTime->wMonth, gameTime->wDay, gameTime->wYear, gameTime->wHour, gameTime->wMinute, gameTime->wSecond); stats.Add_Field("TIME", startTime); // Duration of game unsigned long duration = theGame->Get_Duration_Seconds(); stats.Add_Field("DURA", duration); // Average FPS unsigned long fps = theGame->Get_Frame_Count(); if (duration > 1) { fps = (fps / duration); } stats.Add_Field("AFPS", fps); // Type of tournament /* char gameType = 'I'; if (theGame->Is_Team_Game()) { gameType = 'T'; } */ char gameType = 'T'; if (theGame->IsClanGame.Is_True()) { gameType = 'C'; } char ranked = (theGame->IsLaddered.Is_True() == true) ? 'Y' : 'N'; char tournament[5]; sprintf(tournament, "%c%c ", gameType, ranked); stats.Add_Field("TRNY", tournament); // Include clan information if (theGame->IsClanGame.Is_True()) { unsigned long winningClan = 0; unsigned long losingClan = 0; int winner = theGame->Get_Winner_ID(); SLNode* playerNode = playerList->Head(); for (int index = 0; index < playerList->Get_Count(); index++) { cPlayer* player = playerNode->Data(); if (player->Is_Human()) { RefPtr user = session->FindUser(player->Get_Name()); if (user.IsValid() && (user->GetSquadID() != 0)) { int playerType = player->Get_Player_Type(); if ((playerType == winner) && (winningClan == 0)) { winningClan = user->GetSquadID(); } else if (losingClan == 0) { losingClan = user->GetSquadID(); } else { break; } } } } stats.Add_Field("CLN1", winningClan); stats.Add_Field("CLN2", losingClan); } //--------------------------------------------------------------------------- // Player information //--------------------------------------------------------------------------- // Determine the number of players in the game unsigned long numPlayers = 0; SLNode* playerNode = playerList->Head(); for (int index = 0; index < playerList->Get_Count(); index++) { cPlayer* player = playerNode->Data(); if (player->Is_Human()) { numPlayers++; } } stats.Add_Field("PLRS", numPlayers); // Gather per-player information int winnerID = theGame->Get_Winner_ID(); playerNode = playerList->Head(); for (index = 0; index < playerList->Get_Count(); index++) { cPlayer* player = playerNode->Data(); if (player) { const WideStringClass& playerName = player->Get_Name(); // Player Location WOL::Locale locale = WOL::LOC_UNKNOWN; RefPtr user = session->FindUser((const WCHAR*)playerName); if (user.IsValid()) { locale = user->GetLocale(); } AddPlayerStats(stats, player, locale, winnerID, true); } playerNode = playerNode->Next(); } unsigned long packetSize = 0; unsigned long sig_offset = 0; unsigned char* packet = stats.Create_Comms_Packet(packetSize, NULL, sig_offset); WWDEBUG_SAY(("Sending game results packet. Size = %lu\n", packetSize)); #if(0) #ifdef _DEBUG HANDLE file = CreateFile("GameRes.dat", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != file) { // Write generic contents DWORD written; WriteFile(file, packet, packetSize, &written, NULL); CloseHandle(file); } else { WWDEBUG_SAY(("Failed to create GameRes.dat file.")); } #endif #endif session->SendGameResults(packet, packetSize); } /****************************************************************************** * * NAME * AddPlayerStats * * DESCRIPTION * * INPUTS * Stats - Game result packet to add player stats to. * Player - Player to add stats for. * * RESULT * NONE * ******************************************************************************/ void AddPlayerStats(GameResPacket& stats, cPlayer* player, WOL::Locale locale, int winnerID, bool isTeamed) { if (player->Is_Human()) { // Players WOL name const WideStringClass& playerName = player->Get_Name(); char name[10]; int len = wcstombs(name, (const WCHAR*)playerName, 10); name[len] = 0; stats.Add_Field("PNAM", name); stats.Add_Field("PLOC", (unsigned long)locale); int playerType = player->Get_Player_Type(); // Team (bit 31:win/lose, bits 7-0:team (0 = none, 1 = GDI, 2= NOD) unsigned long team = 0; if (isTeamed) { if (playerType == PLAYERTYPE_GDI) { team = 1; } else if (playerType == PLAYERTYPE_NOD) { team = 2; } } if ((isTeamed && playerType == winnerID) || (!isTeamed && player->Get_Id() == winnerID)) { team |= 0x80000000; } stats.Add_Field("TEAM", team); // Score and other information unsigned long score = (unsigned long)max(player->Get_Score(), 0); stats.Add_Field("PSCR", score); stats.Add_Field("PPTS", (long)player->Get_Ladder_Points()); stats.Add_Field("PTIM", (unsigned long)player->Get_Game_Time()); stats.Add_Field("PHLT", (unsigned long)player->Get_Final_Health()); stats.Add_Field("PKIL", (unsigned long)player->Get_Deaths()); stats.Add_Field("EKIL", (unsigned long)player->Get_Enemies_Killed()); stats.Add_Field("AKIL", (unsigned long)player->Get_Allies_Killed()); stats.Add_Field("SHOT", (unsigned long)player->Get_Shots_Fired()); stats.Add_Field("HEDF", (unsigned long)player->Get_Head_Shots()); stats.Add_Field("TORF", (unsigned long)player->Get_Torso_Shots()); stats.Add_Field("ARMF", (unsigned long)player->Get_Arm_Shots()); stats.Add_Field("LEGF", (unsigned long)player->Get_Leg_Shots()); stats.Add_Field("CRTF", (unsigned long)player->Get_Crotch_Shots()); stats.Add_Field("PUPS", (unsigned long)player->Get_Powerups_Collected()); stats.Add_Field("VKIL", (unsigned long)player->Get_Vehiclies_Destroyed()); stats.Add_Field("VTIM", (unsigned long)player->Get_Vehicle_Time()); stats.Add_Field("NKFV", (unsigned long)player->Get_Kills_From_Vehicle()); stats.Add_Field("SQUI", (unsigned long)player->Get_Squishes()); stats.Add_Field("PCRD", (unsigned long)player->Get_Credit_Grant()); stats.Add_Field("BKIL", (unsigned long)player->Get_Building_Destroyed()); stats.Add_Field("HEDR", (unsigned long)player->Get_Head_Hit()); stats.Add_Field("TORR", (unsigned long)player->Get_Torso_Hit()); stats.Add_Field("ARMR", (unsigned long)player->Get_Arm_Hit()); stats.Add_Field("LEGR", (unsigned long)player->Get_Leg_Hit()); stats.Add_Field("CRTR", (unsigned long)player->Get_Crotch_Hit()); stats.Add_Field("FLGC", (unsigned long)0);//no more CTF! (unsigned long)player->Get_Flag_Caps()); // Weapon usage int numWeapons = min(255, player->Get_Weapon_Fired_Count()); for (int wepIndex = 0; wepIndex < numWeapons; wepIndex++) { unsigned long weaponInfo[2] = {0,0}; player->Get_Weapon_Fired(wepIndex, weaponInfo[0], weaponInfo[1]); char token[5]; sprintf(token, "WP%02X", wepIndex); stats.Add_Field(token, (void*)weaponInfo, sizeof(weaponInfo)); } } }