GameSpy_QnR.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  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. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Commando/GameSpy_QnR.cpp $*
  25. * *
  26. * $Author:: Greg_h $*
  27. * *
  28. * $Modtime:: 7/08/02 5:55p $*
  29. * *
  30. * $Revision:: 17 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include <Gamespy\gs_patch_usage.h>
  36. #include <Gamespy\gcdkeyserver.h>
  37. #include "specialbuilds.h"
  38. #include "dlgcncteaminfo.h"
  39. #include "resource.h"
  40. #include "listctrl.h"
  41. #include "imagectrl.h"
  42. #include "playertype.h"
  43. #include "combat.h"
  44. #include "teammanager.h"
  45. #include "playermanager.h"
  46. #include "player.h"
  47. #include "soldier.h"
  48. #include "gameinitmgr.h"
  49. #include "gamemode.h"
  50. #include "gamedata.h"
  51. #include "input.h"
  52. #include "healthbarctrl.h"
  53. #include "basecontroller.h"
  54. #include "building.h"
  55. #include "damage.h"
  56. #include "vehicle.h"
  57. #include "assets.h"
  58. #include "translatedb.h"
  59. #include "WOLGMode.h"
  60. #include <WWOnline\WOLUser.h>
  61. #include "string_ids.h"
  62. #include "mousemgr.h"
  63. #include "directinput.h"
  64. #include "GameSpy_QnR.h"
  65. #include "verchk.h"
  66. #include "buildnum.h"
  67. #include "serversettings.h"
  68. #include "consolemode.h"
  69. #include "useroptions.h"
  70. #include "gdcnc.h"
  71. #include "rawfile.h"
  72. #include "shellapi.h"
  73. #include "netutil.h"
  74. #include "gamespybanlist.h"
  75. CGameSpyQnR GameSpyQnR;
  76. #if defined(MULTIPLAYERDEMO)
  77. const char *CGameSpyQnR::gamename = "ccrenegadedemo";
  78. const char *CGameSpyQnR::bname = "Demo";
  79. const int CGameSpyQnR::prodid = 10063;
  80. const int CGameSpyQnR::cdkey_id = 0;
  81. #elif defined(FREEDEDICATEDSERVER)
  82. const char *CGameSpyQnR::bname = "FDS";
  83. const char *CGameSpyQnR::gamename = "ccrenegade";
  84. const int CGameSpyQnR::prodid = 10064;
  85. const int CGameSpyQnR::cdkey_id = 577;
  86. #elif defined(BETACLIENT)
  87. const char *CGameSpyQnR::bname = "Beta";
  88. const char *CGameSpyQnR::gamename = "ccrenegade";
  89. const int CGameSpyQnR::prodid = 10064;
  90. const int CGameSpyQnR::cdkey_id = 0;
  91. #else
  92. const char *CGameSpyQnR::bname = "Retail";
  93. const char *CGameSpyQnR::gamename = "ccrenegade";
  94. const int CGameSpyQnR::prodid = 10064;
  95. const int CGameSpyQnR::cdkey_id = 577;
  96. #endif
  97. const char *CGameSpyQnR::default_heartbeat_list = "master.gamespy.com:27900, master.udpsoft.com:27900";
  98. /*********
  99. These c-style callback stubs are used by the SDK. The current game object
  100. (passed in qr_init) is given in userdata, so we know what object to reference
  101. **********/
  102. void c_players_callback(char *outbuf, int maxlen, void *userdata)
  103. {
  104. ((CGameSpyQnR *)userdata)->players_callback(outbuf, maxlen);
  105. }
  106. void c_rules_callback(char *outbuf, int maxlen, void *userdata)
  107. {
  108. ((CGameSpyQnR *)userdata)->rules_callback(outbuf, maxlen);
  109. }
  110. void c_info_callback(char *outbuf, int maxlen, void *userdata)
  111. {
  112. ((CGameSpyQnR *)userdata)->info_callback(outbuf, maxlen);
  113. }
  114. void c_basic_callback(char *outbuf, int maxlen, void *userdata)
  115. {
  116. ((CGameSpyQnR *)userdata)->basic_callback(outbuf, maxlen);
  117. }
  118. /***********
  119. A simple game object. Consists of some data and a main loop function.
  120. ***********/
  121. CGameSpyQnR::CGameSpyQnR(void) : m_GSInit(FALSE), m_GSEnabled(FALSE)
  122. {
  123. // Secret keys removed per Security review requirements. LFeenanEA - 27th January 2025
  124. //set the secret key, in a semi-obfuscated manner
  125. // tY1S8q = FULL , LsEwS3 = DEMO
  126. #ifdef MULTIPLAYERDEMO
  127. secret_key[3] = 'R'; if (secret_key[3])
  128. secret_key[1] = 'E'; if (secret_key[1])
  129. secret_key[0] = 'M'; if (secret_key[0])
  130. secret_key[4] = 'O'; if (secret_key[4])
  131. secret_key[5] = 'V'; if (secret_key[5])
  132. secret_key[3] = 'E'; if (secret_key[3])
  133. secret_key[2] = 'D'; if (secret_key[2])
  134. secret_key[6] = '1'; if (secret_key[2])
  135. secret_key[5] = '2'; if (secret_key[5])
  136. secret_key[4] = '3';
  137. #else
  138. secret_key[5] = 'R'; if (secret_key[5])
  139. secret_key[4] = 'E'; if (secret_key[4])
  140. secret_key[6] = 'M'; if (secret_key[4])
  141. secret_key[1] = 'O'; if (secret_key[1])
  142. secret_key[5] = 'V'; if (secret_key[5])
  143. secret_key[2] = 'E'; if (secret_key[2])
  144. secret_key[3] = 'D'; if (secret_key[3])
  145. secret_key[6] = '1'; if (secret_key[3])
  146. secret_key[0] = '2'; if (secret_key[0])
  147. secret_key[3] = '3';
  148. #endif
  149. }
  150. CGameSpyQnR::~CGameSpyQnR()
  151. {
  152. Shutdown();
  153. }
  154. void CGameSpyQnR::LaunchArcade(void) {
  155. char *akey = "Software\\GameSpy\\GameSpy Arcade";
  156. BOOL launched = FALSE;
  157. HKEY key = NULL;
  158. int result = 0;
  159. result = RegOpenKeyEx(HKEY_CURRENT_USER, akey, 0, KEY_READ, &key);
  160. if (result == ERROR_SUCCESS) {
  161. StringClass value(true);
  162. //
  163. // Get the size of the entry
  164. //
  165. DWORD data_size = 0;
  166. DWORD type = 0;
  167. result = ::RegQueryValueEx ((HKEY)key, "InstDir", NULL, &type, NULL, &data_size);
  168. if (result == ERROR_SUCCESS && type == REG_SZ) {
  169. //
  170. // Read the entry from the registry
  171. //
  172. ::RegQueryValueEx ((HKEY)key, "InstDir", NULL, &type,
  173. (LPBYTE)value.Get_Buffer(data_size), &data_size);
  174. }
  175. if (!value.Is_Empty()) {
  176. if (value[value.Get_Length()-1] == '\\') {
  177. value += "Aphex.exe";
  178. } else {
  179. value += "\\Aphex.exe";
  180. }
  181. RawFileClass file(value);
  182. if (file.Is_Available()) {
  183. StringClass params("+svc ");
  184. params += gamename;
  185. if (((int)ShellExecute (NULL, "open", value, params, NULL, SW_SHOW)) > 32) {
  186. launched = TRUE;
  187. }
  188. }
  189. }
  190. }
  191. if (!launched) {
  192. char url[1000] = "";
  193. #ifdef MULTIPLAYERDEMO
  194. ::strcpy(url, "http://www.gamespyarcade.com/features/launch.asp?svcname=ccrenegadedemo&distID=432");
  195. #else
  196. ::strcpy(url, "http://www.gamespyarcade.com/features/launch.asp?svcname=ccrenegade&distID=391");
  197. #endif
  198. ShellExecute (NULL, "open", url, NULL, NULL, SW_SHOW);
  199. }
  200. }
  201. void CGameSpyQnR::Shutdown(void) {
  202. #ifndef BETACLIENT
  203. if (m_GSInit) {
  204. /*
  205. We don't really need to set the mode to exiting here, since we immediately
  206. send the statechanged heartbeat and kill off the query sockets
  207. gamemode = "exiting";*/
  208. ConsoleBox.Print("Shutting down GameSpy Q&R\n");
  209. qr_send_exiting(query_reporting_rec);
  210. qr_shutdown(query_reporting_rec);
  211. m_GSEnabled = m_GSInit = false;
  212. }
  213. #endif
  214. }
  215. void CGameSpyQnR::TrackUsage(void) {
  216. #ifndef WWDEBUG
  217. char filename[MAX_PATH];
  218. GetModuleFileName(NULL, filename, sizeof(filename));
  219. VS_FIXEDFILEINFO version;
  220. GetVersionInfo(filename, &version);
  221. int ver = version.dwFileVersionMS;
  222. StringClass b(true);
  223. b.Format("%s %s V%d.%3.3d(%s-%d)", "Win-X86", bname, (ver&0xffff0000)>>16, ver&0xffff,
  224. BuildInfoClass::Get_Builder_Initials(), BuildInfoClass::Get_Build_Number());
  225. // Send off usage Tracking info to GameSpy
  226. ptTrackUsage(0, prodid, b.Peek_Buffer(), (cUserOptions::Sku.Get()&0xff)+438, false);
  227. #endif // WWDEBUG
  228. }
  229. void CGameSpyQnR::Init(void) {
  230. #ifndef BETACLIENT
  231. if (m_GSEnabled && !m_GSInit && The_Game() && The_Game()->Get_Game_Type() == cGameData::GAME_TYPE_CNC) {
  232. ConsoleBox.Print("Initializing GameSpy Q&R\n");
  233. BOOL test = FALSE;
  234. // Init the GameSpy QnR engine
  235. extern ULONG g_ip_override;
  236. char ipstr[32];
  237. char *ip = ipstr;
  238. if (g_ip_override == INADDR_NONE) {
  239. if (cUserOptions::PreferredGameSpyNic.Get()) {
  240. strcpy(ip, cNetUtil::Address_To_String(cUserOptions::PreferredGameSpyNic.Get()));
  241. } else {
  242. ip = NULL;
  243. }
  244. } else {
  245. strcpy(ip, cNetUtil::Address_To_String(g_ip_override));
  246. }
  247. if (!get_master_count()) {
  248. GameSpyQnR.Parse_HeartBeat_List(Get_Default_HeartBeat_List());
  249. }
  250. test = qr_init(&query_reporting_rec, ip, cUserOptions::GameSpyQueryPort.Get(),
  251. gamename, secret_key, c_basic_callback, c_info_callback, c_rules_callback,
  252. c_players_callback, this);
  253. WWASSERT(!test);
  254. gcd_init_qr(query_reporting_rec, cdkey_id);
  255. StartTime = time(NULL);
  256. m_GSInit = TRUE;
  257. }
  258. #endif
  259. }
  260. /*******
  261. DoGameStuff
  262. Simulate whatever else a game server does
  263. ********/
  264. void CGameSpyQnR::DoGameStuff(void)
  265. {
  266. // Sleep(100);
  267. }
  268. #define BANLIST_RELOAD_TIME (1*60*1000)
  269. /*******************
  270. CGameSpyQnR::run
  271. Simulates a main game loop
  272. *****************/
  273. void CGameSpyQnR::Think()
  274. {
  275. static DWORD stime = (DWORD)(0 - BANLIST_RELOAD_TIME);
  276. static DWORD ttime = 0;
  277. if (TIMEGETTIME() - stime > BANLIST_RELOAD_TIME) {
  278. GameSpyBanList.LoadBans();
  279. stime = TIMEGETTIME();
  280. }
  281. // check twice a second
  282. if (TIMEGETTIME() - ttime > 500) {
  283. GameSpyBanList.Think();
  284. ttime = TIMEGETTIME();
  285. }
  286. #ifndef BETACLIENT
  287. // DoGameStuff();
  288. if (m_GSInit && m_GSEnabled && GameInitMgrClass::Is_LAN_Initialized() &&
  289. !CombatManager::Is_Loading_Level()) {
  290. qr_process_queries(query_reporting_rec);
  291. gcd_think();
  292. }
  293. #endif
  294. }
  295. /*************
  296. basic_callback
  297. sends a (sample) response to the basic query
  298. includes the following keys:
  299. \gamename\
  300. \gamever\
  301. \location\
  302. *************/
  303. void CGameSpyQnR::basic_callback(char *outbuf, int maxlen)
  304. {
  305. WWDEBUG_SAY(("-->GS_QnR -- Basic callback\n"));
  306. WWASSERT(!CombatManager::Is_Loading_Level());
  307. if (!maxlen || !outbuf) return;
  308. outbuf[0] = 0;
  309. StringClass b(true);
  310. b.Format("%d", BuildInfoClass::Get_Build_Number());
  311. sprintf(outbuf, "\\gamename\\%s\\gamever\\%s", gamename, b.Peek_Buffer());
  312. // sprintf(outbuf, "\\gamename\\%s\\gamever\\%s\\location\\%d", gamename, b.Peek_Buffer(), 1);
  313. #ifdef WWDEBUG
  314. StringClass tstr(true);
  315. tstr.Format("GS_QnR -- Basic callback, sent: %s\n",outbuf);
  316. OutputDebugString(tstr.Peek_Buffer());
  317. #endif
  318. WWDEBUG_SAY(("<--GS_QnR -- Basic callback\n"));
  319. // printf("Basic callback, sent: %s\n\n",outbuf);
  320. }
  321. /************
  322. info_callback
  323. Sends a (sample) response to the info query
  324. including the following keys:
  325. \hostname\
  326. \hostport\
  327. \mapname\
  328. \gametype\
  329. \numplayers\
  330. \maxplayers\
  331. \gamemode\
  332. ************/
  333. void CGameSpyQnR::info_callback(char *outbuf, int maxlen)
  334. {
  335. WWDEBUG_SAY(("-->GS_QnR -- Info callback\n"));
  336. WWASSERT(!CombatManager::Is_Loading_Level());
  337. if (!maxlen || !outbuf) return;
  338. outbuf[0] = 0;
  339. while(1) {
  340. StringClass value(true);
  341. WideStringClass(The_Game()->Get_Game_Title()).Convert_To(value);
  342. if (value.Get_Length() > 25) {
  343. value[25] = 0;
  344. }
  345. if (!Append_InfoKey_Pair(outbuf, maxlen, "hostname", value)) break;
  346. value.Format("%d", The_Game()->Get_Port());
  347. if (!Append_InfoKey_Pair(outbuf, maxlen, "hostport", value)) break;
  348. value = The_Game()->Get_Map_Name();
  349. char *s = value.Peek_Buffer();
  350. char *t = strrchr(s, '.');
  351. if (t) value.Erase(t-s, s+strlen(s)-t);
  352. if (!Append_InfoKey_Pair(outbuf, maxlen, "mapname", value)) break;
  353. value = The_Game()->Get_Mod_Name();
  354. if (!value.Is_Empty()) {
  355. s = value.Peek_Buffer();
  356. t = strrchr(s, '.');
  357. if (t) value.Erase(t-s, s+strlen(s)-t);
  358. if (!Append_InfoKey_Pair(outbuf, maxlen, "gametype", value)) break;
  359. } else {
  360. if (!Append_InfoKey_Pair(outbuf, maxlen, "gametype", "C&C")) break;
  361. }
  362. int pcount = 0;
  363. for (SLNode<cPlayer> *player_node = cPlayerManager::Get_Player_Object_List ()->Head ()
  364. ; player_node != NULL; player_node = player_node->Next ()) {
  365. cPlayer *player = player_node->Data ();
  366. WWASSERT (player != NULL);
  367. if (player->Get_Is_Active().Is_False()) {
  368. // if (player->Get_Is_Active().Is_False() || !player->Is_Human()) {
  369. continue;
  370. }
  371. pcount++;
  372. }
  373. value.Format("%d", pcount);
  374. if (!Append_InfoKey_Pair(outbuf, maxlen, "numplayers", value)) break;
  375. value.Format("%d", The_Game()->Get_Max_Players());
  376. if (!Append_InfoKey_Pair(outbuf, maxlen, "maxplayers", value)) break;
  377. // if (!Append_InfoKey_Pair(outbuf, maxlen, "gamemode", "openplaying")) break;
  378. break;
  379. }
  380. #ifdef WWDEBUG
  381. StringClass tstr(true);
  382. tstr.Format("GS_QnR -- Info callback, sent: %s\n",outbuf);
  383. OutputDebugString(tstr.Peek_Buffer());
  384. #endif
  385. WWDEBUG_SAY(("<--GS_QnR -- Info callback\n"));
  386. }
  387. /***************
  388. rules_callback
  389. Sends a response to the rules query. You may
  390. need to add custom fields for your game in here. Some are provided
  391. as an example
  392. The following rules are included:
  393. \timelimit\
  394. \fraglimit\
  395. \teamplay\
  396. \rankedserver\
  397. ****************/
  398. void CGameSpyQnR::rules_callback(char *outbuf, int maxlen)
  399. {
  400. static StringClass b;
  401. WWDEBUG_SAY(("-->GS_QnR -- Rules callback\n"));
  402. WWASSERT(!CombatManager::Is_Loading_Level());
  403. if (!maxlen || !outbuf) return;
  404. outbuf[0] = 0;
  405. while(1) {
  406. StringClass value(true);
  407. const char *zero = "0"; const char *one = "1";
  408. // WideStringClass timelimit;
  409. // The_Game()->Get_Time_Limit_Text(timelimit);
  410. // if (!Append_InfoKey_Pair(outbuf, maxlen, "timeleft", timelimit)) break;
  411. // value.Format("%d", The_Game()->Get_Time_Limit_Minutes());
  412. // if (!Append_InfoKey_Pair(outbuf, maxlen, "timelimit", value)) break;
  413. // if (b.Is_Empty()) {
  414. // char filename[MAX_PATH];
  415. // GetModuleFileName(NULL, filename, sizeof(filename));
  416. // VS_FIXEDFILEINFO version;
  417. // GetVersionInfo(filename, &version);
  418. // int ver = version.dwFileVersionMS;
  419. //
  420. // b.Format("%s %s V%d.%3.3d(%s-%d)", "Win-X86", bname, (ver&0xffff0000)>>16, ver&0xffff,
  421. // BuildInfoClass::Get_Builder_Initials(), BuildInfoClass::Get_Build_Number());
  422. // }
  423. // if (!Append_InfoKey_Pair(outbuf, maxlen, "Version", b)) break;
  424. // if (!Append_InfoKey_Pair(outbuf, maxlen, "ServerMOTD", WideStringClass(The_Game()->Get_Motd()))) break;
  425. // if (!Append_InfoKey_Pair(outbuf, maxlen, "OwnerName", The_Game()->Get_Owner())) break;
  426. value.Format("%d", (int)cUserOptions::BandwidthBps.Get());
  427. if (!Append_InfoKey_Pair(outbuf, maxlen, "BW", value)) break;
  428. // int utime = time(NULL) - StartTime;
  429. // value.Format("%d:%d:%d:%d", utime/60/60/24, (utime/60/60)%24, (utime/60)%60, utime%60);
  430. // if (!Append_InfoKey_Pair(outbuf, maxlen, "Uptime", value)) break;
  431. if (!Append_InfoKey_Pair(outbuf, maxlen, "CSVR", ConsoleBox.Is_Exclusive() ? one : zero)) break;
  432. if (!Append_InfoKey_Pair(outbuf, maxlen, "DED", The_Game()->IsDedicated.Get() ? one : zero)) break;
  433. if (!Append_InfoKey_Pair(outbuf, maxlen, "DG", The_Game()->DriverIsAlwaysGunner.Get() ? one : zero)) break;
  434. if (!Append_InfoKey_Pair(outbuf, maxlen, "password", The_Game()->IsPassworded.Get() ? one : zero)) break;
  435. if (!Append_InfoKey_Pair(outbuf, maxlen, "TC", The_Game()->IsTeamChangingAllowed.Get() ? one : zero)) break;
  436. // if (!Append_InfoKey_Pair(outbuf, maxlen, "WeaponSpawning", The_Game()->SpawnWeapons.Get() ? one : zero)) break;
  437. // if (!Append_InfoKey_Pair(outbuf, maxlen, "TeamRemix", The_Game()->RemixTeams.Get() ? one : zero)) break;
  438. // if (!Append_InfoKey_Pair(outbuf, maxlen, "BuildingRepair", The_Game()->CanRepairBuildings.Get() ? one : zero)) break;
  439. if (!Append_InfoKey_Pair(outbuf, maxlen, "FF", The_Game()->IsFriendlyFirePermitted.Get() ? one : zero)) break;
  440. // if (!Append_InfoKey_Pair(outbuf, maxlen, "BaseDestructionEndsGame", The_Game()->As_Cnc()->BaseDestructionEndsGame.Get() ? one : zero)) break;
  441. // if (!Append_InfoKey_Pair(outbuf, maxlen, "BeaconPlacementEndsGame", The_Game()->As_Cnc()->BeaconPlacementEndsGame.Get() ? one : zero)) break;
  442. // value.Format("%d", (int)The_Game()->Get_Radar_Mode());
  443. // if (!Append_InfoKey_Pair(outbuf, maxlen, "RadarMode", value)) break;
  444. value.Format("%d", The_Game()->As_Cnc()->Get_Starting_Credits());
  445. if (!Append_InfoKey_Pair(outbuf, maxlen, "SC", value)) break;
  446. // cTeam * p_team;
  447. // for (SLNode<cTeam> * objnode = cTeamManager::Get_Team_Object_List()->Head()
  448. // ; objnode != NULL; objnode = objnode->Next()) {
  449. //
  450. // p_team = objnode->Data();
  451. // WWASSERT(p_team != NULL);
  452. //
  453. // if (p_team->Get_Id() == PLAYERTYPE_GDI) {
  454. // value.Format("%.0f", p_team->Get_Score());
  455. // if (!Append_InfoKey_Pair(outbuf, maxlen, "GDI_Score", value)) break;
  456. // } else if (p_team->Get_Id() == PLAYERTYPE_NOD) {
  457. // value.Format("%.0f", p_team->Get_Score());
  458. // if (!Append_InfoKey_Pair(outbuf, maxlen, "NOD_Score", value)) break;
  459. // }
  460. // }
  461. // These don't apply to LAN/GameSpy Games
  462. // if (!Append_InfoKey_Pair(outbuf, maxlen, "ClanMatch", The_Game()->IsClanGame.Get() ? one : zero)) break;
  463. // if (!Append_InfoKey_Pair(outbuf, maxlen, "Laddered", The_Game()->IsLaddered.Get() ? one : zero)) break;
  464. // if (!Append_InfoKey_Pair(outbuf, maxlen, "QuickMatch", The_Game()->Is_QuickMatch_Server() ? one : zero)) break;
  465. break;
  466. }
  467. #ifdef WWDEBUG
  468. StringClass tstr(true);
  469. tstr.Format("GS_QnR -- Rules callback, sent: %s\n",outbuf);
  470. OutputDebugString(tstr.Peek_Buffer());
  471. #endif
  472. WWDEBUG_SAY(("<--GS_QnR -- Rules callback\n"));
  473. }
  474. BOOL CGameSpyQnR::Parse_HeartBeat_List(const char *list) {
  475. BOOL master_added = false;
  476. char *str = new char[strlen(list)+1];
  477. strcpy(str, list);
  478. char *t = str;
  479. clear_master_list();
  480. while (t) {
  481. WORD port = 27900;
  482. struct sockaddr_in taddr;
  483. memset(&taddr, 0, sizeof(taddr));
  484. taddr.sin_family = AF_INET;
  485. char *q = strchr(t, ',');
  486. if (q) *q++ = 0;
  487. char *s = strchr(t, ':');
  488. if (s) {
  489. // Parse off the port value
  490. *s++ = 0;
  491. char *p = s;
  492. if (atoi(p)) port = atoi(p);
  493. }
  494. // skip white space
  495. while (*t == ' ' || *t == '\t') t++;
  496. // process the address
  497. if (*t && get_sockaddrin(t, port, &taddr, NULL)) {
  498. add_master(&taddr);
  499. master_added = true;
  500. }
  501. t = q;
  502. }
  503. delete [] str;
  504. if (!master_added) {
  505. ConsoleBox.Print("Error processing HeartBeat List: <%s>\n", list);
  506. ConsoleBox.Print("Assigning default HeartBeat List\n");
  507. return false;
  508. }
  509. return true;
  510. }
  511. BOOL CGameSpyQnR::Append_InfoKey_Pair(char *outbuf, int maxlen, const char *key, const char *value) {
  512. WWASSERT(value);
  513. WWASSERT(outbuf);
  514. WWASSERT(key);
  515. int clen = strlen(outbuf);
  516. if (clen + strlen(key) + strlen(value) + 3 > (unsigned int)maxlen) return FALSE;
  517. char *s = new char[strlen(value)+1];
  518. strcpy(s, value);
  519. char *t = s;
  520. while (*t) {
  521. if (*t == '\\') *t = '/';
  522. t++;
  523. }
  524. t = strtrim(s);
  525. sprintf(&outbuf[clen], "\\%s\\%s", key, t);
  526. delete [] s;
  527. return TRUE;
  528. }
  529. BOOL CGameSpyQnR::Append_InfoKey_Pair(char *outbuf, int maxlen, const char *key, const WideStringClass &value) {
  530. static StringClass text;
  531. value.Convert_To(text);
  532. return Append_InfoKey_Pair(outbuf, maxlen, key, text.Peek_Buffer());
  533. }
  534. BOOL CGameSpyQnR::Append_InfoKey_Pair(char *outbuf, int maxlen, const char *key, const StringClass &value) {
  535. return Append_InfoKey_Pair(outbuf, maxlen, key, value.Peek_Buffer());
  536. }
  537. /***************
  538. players_callback
  539. sends the players and their information.
  540. Note that \ characters are not stripped out of player names. If
  541. your game allows players or team names with the \ character, you will need
  542. to strip or change it here.
  543. The following keys are included for each player:
  544. \player_N\
  545. \frags_N\
  546. \deaths_N\
  547. \skill_N\
  548. \ping_N\
  549. \team_N\
  550. ***************/
  551. void CGameSpyQnR::players_callback(char *outbuf, int maxlen)
  552. {
  553. // Send the minimum for now to reduce Bandwidth usage.
  554. outbuf[0] = 0;
  555. return;
  556. int pindex = 0;
  557. WWDEBUG_SAY(("-->GS_QnR -- Players callback\n"));
  558. WWASSERT(!CombatManager::Is_Loading_Level());
  559. if (!maxlen || !outbuf) return;
  560. outbuf[0] = 0;
  561. for (SLNode<cPlayer> *player_node = cPlayerManager::Get_Player_Object_List ()->Head ();
  562. player_node != NULL;
  563. player_node = player_node->Next ()) {
  564. cPlayer *player = player_node->Data ();
  565. WWASSERT (player != NULL);
  566. if (player->Get_Is_Active().Is_False()) {
  567. // if (player->Get_Is_Active().Is_False() || !player->Is_Human()) {
  568. continue;
  569. }
  570. StringClass keyval(true);
  571. StringClass value(true);
  572. // Set the Player's Name [Team]
  573. value = player->Get_Name();
  574. if (player->Get_Player_Type() == PLAYERTYPE_NOD) {
  575. value += " [NOD]";
  576. } else if (player->Get_Player_Type() == PLAYERTYPE_GDI) {
  577. value += " [GDI]";
  578. }
  579. keyval.Format("player_%d", pindex);
  580. if (!Append_InfoKey_Pair(outbuf, maxlen, keyval.Peek_Buffer(), value)) break;
  581. // Set the Player's Score
  582. keyval.Format("frags_%d", pindex);
  583. value.Format("%.0f", player->Get_Score());
  584. if (!Append_InfoKey_Pair(outbuf, maxlen, keyval.Peek_Buffer(), value)) break;
  585. // Set the Player's Credits
  586. // keyval.Format("credits_%d", pindex);
  587. // value.Format("%.0f", player->Get_Money());
  588. // if (!Append_InfoKey_Pair(outbuf, maxlen, keyval.Peek_Buffer(), value)) break;
  589. // Set the Player's Ping to Server
  590. keyval.Format("ping_%d", pindex);
  591. value.Format("%d", player->Get_Ping());
  592. if (!Append_InfoKey_Pair(outbuf, maxlen, keyval.Peek_Buffer(), value)) break;
  593. // Set the Player's Kills
  594. // keyval.Format("kills_%d", pindex);
  595. // value.Format("%d", player->Get_Kills());
  596. // if (!Append_InfoKey_Pair(outbuf, maxlen, keyval.Peek_Buffer(), value)) break;
  597. // Set the Player's Deaths
  598. // keyval.Format("deaths_%d", pindex);
  599. // value.Format("%d", player->Get_Deaths());
  600. // if (!Append_InfoKey_Pair(outbuf, maxlen, keyval.Peek_Buffer(), value)) break;
  601. /* SmartGameObj *game_obj = player->Get_GameObj ();
  602. if (game_obj != NULL && game_obj->As_SoldierGameObj () != NULL) {
  603. // Set the Player's Class (ie: Technician,Sakura,Havok)
  604. keyval.Format("class_%d", pindex);
  605. if (!Append_InfoKey_Pair(outbuf, maxlen, keyval.Peek_Buffer(),
  606. WideStringClass(TRANSLATE(game_obj->Get_Translated_Name_ID())) )) break;
  607. SoldierGameObj *soldier = game_obj->As_SoldierGameObj();
  608. VehicleGameObj *vehicle = soldier->Get_Vehicle ();
  609. // If they're in a vehicle set the vehicle name
  610. keyval.Format("vehicle_%d", pindex);
  611. if (vehicle != NULL) {
  612. if (!Append_InfoKey_Pair(outbuf, maxlen, keyval.Peek_Buffer(),
  613. WideStringClass(TRANSLATE(vehicle->Get_Translated_Name_ID())) )) break;
  614. } else {
  615. if (!Append_InfoKey_Pair(outbuf, maxlen, keyval.Peek_Buffer(), "None")) break;
  616. }
  617. } else {
  618. // If there's no gameobj then set vehicle/class to unknown
  619. keyval.Format("class_%d", pindex);
  620. if (!Append_InfoKey_Pair(outbuf, maxlen, keyval.Peek_Buffer(), "Unknown")) break;
  621. keyval.Format("vehicle_%d", pindex);
  622. if (!Append_InfoKey_Pair(outbuf, maxlen, keyval.Peek_Buffer(), "Unknown")) break;
  623. } */
  624. pindex++;
  625. }
  626. #ifdef WWDEBUG
  627. StringClass tstr(true);
  628. tstr.Format("GS_QnR -- Players callback, sent: %s\n",outbuf);
  629. OutputDebugString(tstr.Peek_Buffer());
  630. #endif
  631. WWDEBUG_SAY(("<--GS_QnR -- Players callback\n"));
  632. return;
  633. }
  634. /************
  635. We'll actually start up two completely seperate "game servers"
  636. Each one initializes the Query & Reporting SDK and calls processs on it during
  637. their main loop
  638. ************/
  639. /*
  640. int main(int argc, char* argv[])
  641. {
  642. CGameSpyQnR mygame1("Test Game Server 1"), mygame2("Test Game Server 2");
  643. srand( GetTickCount() );
  644. printf("Press any key to quit\n");
  645. while (!_kbhit())
  646. {
  647. mygame1.run();
  648. mygame2.run();
  649. }
  650. return 0;
  651. }
  652. */