GameResSend.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /******************************************************************************
  19. *
  20. * FILE
  21. * $Archive: /Commando/Code/Commando/GameResSend.cpp $
  22. *
  23. * DESCRIPTION
  24. *
  25. * PROGRAMMER
  26. * $Author: Denzil_l $
  27. *
  28. * VERSION INFO
  29. * $Revision: 25 $
  30. * $Modtime: 1/14/02 10:40a $
  31. *
  32. ******************************************************************************/
  33. #include "GameResSend.h"
  34. #include "GameData.h"
  35. #include "Player.h"
  36. #include "consolemode.h"
  37. #include <Combat\PlayerType.h>
  38. #include <WWOnline\GameResPacket.h>
  39. #include <WWOnline\WOLSession.h>
  40. #include <WWOnline\WOLProduct.h>
  41. #include <WWOnline\WOLUser.h>
  42. #include <WWLib\CPUDetect.h>
  43. #include <WWLib\VerChk.h>
  44. #include <WWLib\CPUDetect.h>
  45. #include <WWLib\global.h>
  46. #include <WWLib\md5.h>
  47. #include <WW3D2\DX8Wrapper.h>
  48. #include <windows.h>
  49. using namespace WWOnline;
  50. static void AddPlayerStats(GameResPacket& stats, cPlayer* player, WOL::Locale locale,
  51. int winnerID, bool teamGame);
  52. /******************************************************************************
  53. *
  54. * NAME
  55. * SendGameResults
  56. *
  57. * DESCRIPTION
  58. * Send game results for ladder ranking.
  59. *
  60. * INPUTS
  61. * TheGame - The game played.
  62. * Players - List of players.
  63. *
  64. * RESULT
  65. * NONE
  66. *
  67. ******************************************************************************/
  68. void SendGameResults(unsigned long gameID, cGameData* theGame, SList<cPlayer>* playerList)
  69. {
  70. RefPtr<WWOnline::Session> session = WWOnline::Session::GetInstance(false);
  71. if (!session.IsValid())
  72. {
  73. assert(session.IsValid() && "SendGameResults() WOLSession not instantiated.");
  74. WWDEBUG_SAY(("ERROR: SendGameResults() WOLSession not instantiated.\n"));
  75. return;
  76. }
  77. //---------------------------------------------------------------------------
  78. // Gather game information
  79. //---------------------------------------------------------------------------
  80. GameResPacket stats;
  81. // Unique identifier for this game session.
  82. stats.Add_Field("IDNO", gameID);
  83. // Product SKU
  84. RefPtr<Product> product = Product::Current();
  85. unsigned long gameSKU = product->GetSKU();
  86. stats.Add_Field("GSKU", gameSKU);
  87. // Version of executable.
  88. char filename[MAX_PATH];
  89. GetModuleFileName(NULL, filename, sizeof(filename));
  90. VS_FIXEDFILEINFO version;
  91. GetVersionInfo(filename, &version);
  92. stats.Add_Field("VERS", version.dwFileVersionMS);
  93. // Executable build date
  94. FILETIME createTime;
  95. GetFileCreationTime(filename, &createTime);
  96. SYSTEMTIME time;
  97. FileTimeToSystemTime(&createTime, &time);
  98. char buildDate[20];
  99. sprintf(buildDate, "%02d/%02d/%04d %02d:%02d:%02d",
  100. time.wMonth, time.wDay, time.wYear, time.wHour, time.wMinute, time.wSecond);
  101. stats.Add_Field("DATE", buildDate);
  102. // Proocessor information
  103. stats.Add_Field("PROC", (char*)CPUDetectClass::Get_Processor_String());
  104. stats.Add_Field("PSPD", (unsigned long)CPUDetectClass::Get_Processor_Speed());
  105. // Amount of system memory on server
  106. MEMORYSTATUS memStatus;
  107. GlobalMemoryStatus(&memStatus);
  108. stats.Add_Field("SMEM", (unsigned long)memStatus.dwTotalPhys);
  109. // Video card information
  110. DWORD cardInfo[4];
  111. if (ConsoleBox.Is_Exclusive()) {
  112. strcpy((char*)&cardInfo[0], "ConsoleMode");
  113. } else {
  114. const D3DADAPTER_IDENTIFIER8& adapter = DX8Wrapper::Get_Current_Adapter_Identifier();
  115. cardInfo[0] = adapter.VendorId;
  116. cardInfo[1] = adapter.DeviceId;
  117. cardInfo[2] = adapter.SubSysId;
  118. cardInfo[3] = adapter.Revision;
  119. }
  120. stats.Add_Field("SVID", (void*)cardInfo, sizeof(cardInfo));
  121. // WOL Name of server
  122. const WideStringClass& owner = theGame->Get_Owner();
  123. StringClass serverName(true);
  124. owner.Convert_To(serverName);
  125. stats.Add_Field("SNAM", (char*)serverName.Peek_Buffer());
  126. // Type of game played (Deathmatch, Capture the flag, CNC...)
  127. // char* gameMode = (char*)theGame->Get_Game_Type_Name();
  128. stats.Add_Field("MODE", "CNC");
  129. // Name of the map used.
  130. char *map_name = (char*)(theGame->Get_Map_Name().Peek_Buffer());
  131. stats.Add_Field("GMAP", map_name);
  132. // Was this a dedicated server?
  133. bool dedicatedServer = theGame->IsDedicated.Get();
  134. stats.Add_Field("DSVR", (char)dedicatedServer);
  135. // Time game started
  136. LPSYSTEMTIME gameTime = theGame->Get_Game_Start_Time();
  137. char startTime[20];
  138. sprintf(startTime, "%02d/%02d/%04d %02d:%02d:%02d",
  139. gameTime->wMonth, gameTime->wDay, gameTime->wYear, gameTime->wHour, gameTime->wMinute, gameTime->wSecond);
  140. stats.Add_Field("TIME", startTime);
  141. // Duration of game
  142. unsigned long duration = theGame->Get_Duration_Seconds();
  143. stats.Add_Field("DURA", duration);
  144. // Average FPS
  145. unsigned long fps = theGame->Get_Frame_Count();
  146. if (duration > 1)
  147. {
  148. fps = (fps / duration);
  149. }
  150. stats.Add_Field("AFPS", fps);
  151. // Type of tournament
  152. /*
  153. char gameType = 'I';
  154. if (theGame->Is_Team_Game())
  155. {
  156. gameType = 'T';
  157. }
  158. */
  159. char gameType = 'T';
  160. if (theGame->IsClanGame.Is_True())
  161. {
  162. gameType = 'C';
  163. }
  164. char ranked = (theGame->IsLaddered.Is_True() == true) ? 'Y' : 'N';
  165. char tournament[5];
  166. sprintf(tournament, "%c%c ", gameType, ranked);
  167. stats.Add_Field("TRNY", tournament);
  168. // Include clan information
  169. if (theGame->IsClanGame.Is_True())
  170. {
  171. unsigned long winningClan = 0;
  172. unsigned long losingClan = 0;
  173. int winner = theGame->Get_Winner_ID();
  174. SLNode<cPlayer>* playerNode = playerList->Head();
  175. for (int index = 0; index < playerList->Get_Count(); index++)
  176. {
  177. cPlayer* player = playerNode->Data();
  178. if (player->Is_Human())
  179. {
  180. RefPtr<UserData> user = session->FindUser(player->Get_Name());
  181. if (user.IsValid() && (user->GetSquadID() != 0))
  182. {
  183. int playerType = player->Get_Player_Type();
  184. if ((playerType == winner) && (winningClan == 0))
  185. {
  186. winningClan = user->GetSquadID();
  187. }
  188. else if (losingClan == 0)
  189. {
  190. losingClan = user->GetSquadID();
  191. }
  192. else
  193. {
  194. break;
  195. }
  196. }
  197. }
  198. }
  199. stats.Add_Field("CLN1", winningClan);
  200. stats.Add_Field("CLN2", losingClan);
  201. }
  202. //---------------------------------------------------------------------------
  203. // Player information
  204. //---------------------------------------------------------------------------
  205. // Determine the number of players in the game
  206. unsigned long numPlayers = 0;
  207. SLNode<cPlayer>* playerNode = playerList->Head();
  208. for (int index = 0; index < playerList->Get_Count(); index++)
  209. {
  210. cPlayer* player = playerNode->Data();
  211. if (player->Is_Human())
  212. {
  213. numPlayers++;
  214. }
  215. }
  216. stats.Add_Field("PLRS", numPlayers);
  217. // Gather per-player information
  218. int winnerID = theGame->Get_Winner_ID();
  219. playerNode = playerList->Head();
  220. for (index = 0; index < playerList->Get_Count(); index++)
  221. {
  222. cPlayer* player = playerNode->Data();
  223. if (player)
  224. {
  225. const WideStringClass& playerName = player->Get_Name();
  226. // Player Location
  227. WOL::Locale locale = WOL::LOC_UNKNOWN;
  228. RefPtr<UserData> user = session->FindUser((const WCHAR*)playerName);
  229. if (user.IsValid())
  230. {
  231. locale = user->GetLocale();
  232. }
  233. AddPlayerStats(stats, player, locale, winnerID, true);
  234. }
  235. playerNode = playerNode->Next();
  236. }
  237. unsigned long packetSize = 0;
  238. unsigned long sig_offset = 0;
  239. unsigned char* packet = stats.Create_Comms_Packet(packetSize, NULL, sig_offset);
  240. WWDEBUG_SAY(("Sending game results packet. Size = %lu\n", packetSize));
  241. #if(0)
  242. #ifdef _DEBUG
  243. HANDLE file = CreateFile("GameRes.dat", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  244. FILE_ATTRIBUTE_NORMAL, NULL);
  245. if (INVALID_HANDLE_VALUE != file)
  246. {
  247. // Write generic contents
  248. DWORD written;
  249. WriteFile(file, packet, packetSize, &written, NULL);
  250. CloseHandle(file);
  251. }
  252. else
  253. {
  254. WWDEBUG_SAY(("Failed to create GameRes.dat file."));
  255. }
  256. #endif
  257. #endif
  258. session->SendGameResults(packet, packetSize);
  259. }
  260. /******************************************************************************
  261. *
  262. * NAME
  263. * AddPlayerStats
  264. *
  265. * DESCRIPTION
  266. *
  267. * INPUTS
  268. * Stats - Game result packet to add player stats to.
  269. * Player - Player to add stats for.
  270. *
  271. * RESULT
  272. * NONE
  273. *
  274. ******************************************************************************/
  275. void AddPlayerStats(GameResPacket& stats, cPlayer* player, WOL::Locale locale,
  276. int winnerID, bool isTeamed)
  277. {
  278. if (player->Is_Human())
  279. {
  280. // Players WOL name
  281. const WideStringClass& playerName = player->Get_Name();
  282. char name[10];
  283. int len = wcstombs(name, (const WCHAR*)playerName, 10);
  284. name[len] = 0;
  285. stats.Add_Field("PNAM", name);
  286. stats.Add_Field("PLOC", (unsigned long)locale);
  287. int playerType = player->Get_Player_Type();
  288. // Team (bit 31:win/lose, bits 7-0:team (0 = none, 1 = GDI, 2= NOD)
  289. unsigned long team = 0;
  290. if (isTeamed)
  291. {
  292. if (playerType == PLAYERTYPE_GDI)
  293. {
  294. team = 1;
  295. }
  296. else if (playerType == PLAYERTYPE_NOD)
  297. {
  298. team = 2;
  299. }
  300. }
  301. if ((isTeamed && playerType == winnerID) || (!isTeamed && player->Get_Id() == winnerID))
  302. {
  303. team |= 0x80000000;
  304. }
  305. stats.Add_Field("TEAM", team);
  306. // Score and other information
  307. unsigned long score = (unsigned long)max<int>(player->Get_Score(), 0);
  308. stats.Add_Field("PSCR", score);
  309. stats.Add_Field("PPTS", (long)player->Get_Ladder_Points());
  310. stats.Add_Field("PTIM", (unsigned long)player->Get_Game_Time());
  311. stats.Add_Field("PHLT", (unsigned long)player->Get_Final_Health());
  312. stats.Add_Field("PKIL", (unsigned long)player->Get_Deaths());
  313. stats.Add_Field("EKIL", (unsigned long)player->Get_Enemies_Killed());
  314. stats.Add_Field("AKIL", (unsigned long)player->Get_Allies_Killed());
  315. stats.Add_Field("SHOT", (unsigned long)player->Get_Shots_Fired());
  316. stats.Add_Field("HEDF", (unsigned long)player->Get_Head_Shots());
  317. stats.Add_Field("TORF", (unsigned long)player->Get_Torso_Shots());
  318. stats.Add_Field("ARMF", (unsigned long)player->Get_Arm_Shots());
  319. stats.Add_Field("LEGF", (unsigned long)player->Get_Leg_Shots());
  320. stats.Add_Field("CRTF", (unsigned long)player->Get_Crotch_Shots());
  321. stats.Add_Field("PUPS", (unsigned long)player->Get_Powerups_Collected());
  322. stats.Add_Field("VKIL", (unsigned long)player->Get_Vehiclies_Destroyed());
  323. stats.Add_Field("VTIM", (unsigned long)player->Get_Vehicle_Time());
  324. stats.Add_Field("NKFV", (unsigned long)player->Get_Kills_From_Vehicle());
  325. stats.Add_Field("SQUI", (unsigned long)player->Get_Squishes());
  326. stats.Add_Field("PCRD", (unsigned long)player->Get_Credit_Grant());
  327. stats.Add_Field("BKIL", (unsigned long)player->Get_Building_Destroyed());
  328. stats.Add_Field("HEDR", (unsigned long)player->Get_Head_Hit());
  329. stats.Add_Field("TORR", (unsigned long)player->Get_Torso_Hit());
  330. stats.Add_Field("ARMR", (unsigned long)player->Get_Arm_Hit());
  331. stats.Add_Field("LEGR", (unsigned long)player->Get_Leg_Hit());
  332. stats.Add_Field("CRTR", (unsigned long)player->Get_Crotch_Hit());
  333. stats.Add_Field("FLGC", (unsigned long)0);//no more CTF! (unsigned long)player->Get_Flag_Caps());
  334. // Weapon usage
  335. int numWeapons = min<int>(255, player->Get_Weapon_Fired_Count());
  336. for (int wepIndex = 0; wepIndex < numWeapons; wepIndex++)
  337. {
  338. unsigned long weaponInfo[2] = {0,0};
  339. player->Get_Weapon_Fired(wepIndex, weaponInfo[0], weaponInfo[1]);
  340. char token[5];
  341. sprintf(token, "WP%02X", wepIndex);
  342. stats.Add_Field(token, (void*)weaponInfo, sizeof(weaponInfo));
  343. }
  344. }
  345. }