GameSpyGameInfo.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. /*
  2. ** Command & Conquer Generals(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. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: GameSpyGameInfo.cpp //////////////////////////////////////////////////////
  24. // GameSpy game setup state info
  25. // Author: Matthew D. Campbell, December 2001
  26. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  27. #include "Common/GameEngine.h"
  28. #include "Common/Player.h"
  29. #include "Common/PlayerList.h"
  30. #include "Common/RandomValue.h"
  31. #include "Common/Scorekeeper.h"
  32. #include "GameClient/Shell.h"
  33. #include "GameClient/GameText.h"
  34. #include "GameNetwork/GameSpy/PeerDefs.h"
  35. #include "GameNetwork/GameSpyGameInfo.h"
  36. #include "GameNetwork/NetworkInterface.h"
  37. #include "GameNetwork/NetworkUtil.h"
  38. #include "GameNetwork/NetworkDefs.h"
  39. #include "GameNetwork/NAT.h"
  40. #include "GameLogic/GameLogic.h"
  41. #include "GameLogic/VictoryConditions.h"
  42. // Singleton ------------------------------------------
  43. GameSpyGameInfo *TheGameSpyGame = NULL;
  44. // Helper Functions ----------------------------------------
  45. GameSpyGameSlot::GameSpyGameSlot()
  46. {
  47. GameSlot();
  48. m_gameSpyLogin.clear();
  49. m_gameSpyLocale.clear();
  50. m_profileID = 0;
  51. }
  52. // Helper Functions ----------------------------------------
  53. /*
  54. ** Function definitions for the MIB-II entry points.
  55. */
  56. BOOL (__stdcall *SnmpExtensionInitPtr)(IN DWORD dwUpTimeReference, OUT HANDLE *phSubagentTrapEvent, OUT AsnObjectIdentifier *pFirstSupportedRegion);
  57. BOOL (__stdcall *SnmpExtensionQueryPtr)(IN BYTE bPduType, IN OUT RFC1157VarBindList *pVarBindList, OUT AsnInteger32 *pErrorStatus, OUT AsnInteger32 *pErrorIndex);
  58. LPVOID (__stdcall *SnmpUtilMemAllocPtr)(IN DWORD bytes);
  59. VOID (__stdcall *SnmpUtilMemFreePtr)(IN LPVOID pMem);
  60. typedef struct tConnInfoStruct {
  61. unsigned int State;
  62. unsigned long LocalIP;
  63. unsigned short LocalPort;
  64. unsigned long RemoteIP;
  65. unsigned short RemotePort;
  66. } ConnInfoStruct;
  67. #ifndef ARRAY_SIZE
  68. #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
  69. #endif
  70. /***********************************************************************************************
  71. * Get_Local_Chat_Connection_Address -- Which address are we using to talk to the chat server? *
  72. * *
  73. * *
  74. * *
  75. * INPUT: Ptr to address to return local address * *
  76. * *
  77. * OUTPUT: True if success *
  78. * *
  79. * WARNINGS: None *
  80. * *
  81. * HISTORY: *
  82. * 10/27/00 3:24PM ST : Created *
  83. *=============================================================================================*/
  84. Bool GetLocalChatConnectionAddress(AsciiString serverName, UnsignedShort serverPort, UnsignedInt& localIP)
  85. {
  86. //return false;
  87. /*
  88. ** Local defines.
  89. */
  90. enum {
  91. CLOSED = 1,
  92. LISTENING,
  93. SYN_SENT,
  94. SEN_RECEIVED,
  95. ESTABLISHED,
  96. FIN_WAIT,
  97. FIN_WAIT2,
  98. CLOSE_WAIT,
  99. LAST_ACK,
  100. CLOSING,
  101. TIME_WAIT,
  102. DELETE_TCB
  103. };
  104. enum {
  105. tcpConnState = 1,
  106. tcpConnLocalAddress,
  107. tcpConnLocalPort,
  108. tcpConnRemAddress,
  109. tcpConnRemPort
  110. };
  111. /*
  112. ** Locals.
  113. */
  114. unsigned char serverAddress[4];
  115. unsigned char remoteAddress[4];
  116. HANDLE trap_handle;
  117. AsnObjectIdentifier first_supported_region;
  118. std::vector<ConnInfoStruct> connectionVector;
  119. int last_field;
  120. int index;
  121. AsnInteger error_status;
  122. AsnInteger error_index;
  123. int conn_entry_type_index;
  124. int conn_entry_type;
  125. Bool found;
  126. /*
  127. ** Statics.
  128. */
  129. static char _conn_state[][32] = {
  130. "?",
  131. "CLOSED",
  132. "LISTENING",
  133. "SYN_SENT",
  134. "SEN_RECEIVED",
  135. "ESTABLISHED",
  136. "FIN_WAIT",
  137. "FIN_WAIT2",
  138. "CLOSE_WAIT",
  139. "LAST_ACK",
  140. "CLOSING",
  141. "TIME_WAIT",
  142. "DELETE_TCB"
  143. };
  144. DEBUG_LOG(("Finding local address used to talk to the chat server\n"));
  145. DEBUG_LOG(("Current chat server name is %s\n", serverName.str()));
  146. DEBUG_LOG(("Chat server port is %d\n", serverPort));
  147. /*
  148. ** Get the address of the chat server.
  149. */
  150. DEBUG_LOG( ("About to call gethostbyname\n"));
  151. struct hostent *host_info = gethostbyname(serverName.str());
  152. if (!host_info) {
  153. DEBUG_LOG( ("gethostbyname failed! Error code %d\n", WSAGetLastError()));
  154. return(false);
  155. }
  156. memcpy(serverAddress, &host_info->h_addr_list[0][0], 4);
  157. unsigned long temp = *((unsigned long*)(&serverAddress[0]));
  158. temp = ntohl(temp);
  159. *((unsigned long*)(&serverAddress[0])) = temp;
  160. DEBUG_LOG(("Host address is %d.%d.%d.%d\n", serverAddress[3], serverAddress[2], serverAddress[1], serverAddress[0]));
  161. /*
  162. ** Load the MIB-II SNMP DLL.
  163. */
  164. DEBUG_LOG(("About to load INETMIB1.DLL\n"));
  165. HINSTANCE mib_ii_dll = LoadLibrary("inetmib1.dll");
  166. if (mib_ii_dll == NULL) {
  167. DEBUG_LOG(("Failed to load INETMIB1.DLL\n"));
  168. return(false);
  169. }
  170. DEBUG_LOG(("About to load SNMPAPI.DLL\n"));
  171. HINSTANCE snmpapi_dll = LoadLibrary("snmpapi.dll");
  172. if (snmpapi_dll == NULL) {
  173. DEBUG_LOG(("Failed to load SNMPAPI.DLL\n"));
  174. FreeLibrary(mib_ii_dll);
  175. return(false);
  176. }
  177. /*
  178. ** Get the function pointers into the .dll
  179. */
  180. SnmpExtensionInitPtr = (int (__stdcall *)(unsigned long,void ** ,AsnObjectIdentifier *)) GetProcAddress(mib_ii_dll, "SnmpExtensionInit");
  181. SnmpExtensionQueryPtr = (int (__stdcall *)(unsigned char,SnmpVarBindList *,long *,long *)) GetProcAddress(mib_ii_dll, "SnmpExtensionQuery");
  182. SnmpUtilMemAllocPtr = (void *(__stdcall *)(unsigned long)) GetProcAddress(snmpapi_dll, "SnmpUtilMemAlloc");
  183. SnmpUtilMemFreePtr = (void (__stdcall *)(void *)) GetProcAddress(snmpapi_dll, "SnmpUtilMemFree");
  184. if (SnmpExtensionInitPtr == NULL || SnmpExtensionQueryPtr == NULL || SnmpUtilMemAllocPtr == NULL || SnmpUtilMemFreePtr == NULL) {
  185. DEBUG_LOG(("Failed to get proc addresses for linked functions\n"));
  186. FreeLibrary(snmpapi_dll);
  187. FreeLibrary(mib_ii_dll);
  188. return(false);
  189. }
  190. RFC1157VarBindList *bind_list_ptr = (RFC1157VarBindList *) SnmpUtilMemAllocPtr(sizeof(RFC1157VarBindList));
  191. RFC1157VarBind *bind_ptr = (RFC1157VarBind *) SnmpUtilMemAllocPtr(sizeof(RFC1157VarBind));
  192. /*
  193. ** OK, here we go. Try to initialise the .dll
  194. */
  195. DEBUG_LOG(("About to init INETMIB1.DLL\n"));
  196. int ok = SnmpExtensionInitPtr(GetCurrentTime(), &trap_handle, &first_supported_region);
  197. if (!ok) {
  198. /*
  199. ** Aw crap.
  200. */
  201. DEBUG_LOG(("Failed to init the .dll\n"));
  202. SnmpUtilMemFreePtr(bind_list_ptr);
  203. SnmpUtilMemFreePtr(bind_ptr);
  204. FreeLibrary(snmpapi_dll);
  205. FreeLibrary(mib_ii_dll);
  206. return(false);
  207. }
  208. /*
  209. ** Name of mib_ii object we want to query. See RFC 1213.
  210. **
  211. ** iso.org.dod.internet.mgmt.mib-2.tcp.tcpConnTable.TcpConnEntry.tcpConnState
  212. ** 1 3 6 1 2 1 6 13 1 1
  213. */
  214. unsigned int mib_ii_name[] = {1,3,6,1,2,1,6,13,1,1};
  215. unsigned int *mib_ii_name_ptr = (unsigned int *) SnmpUtilMemAllocPtr(sizeof(mib_ii_name));
  216. memcpy(mib_ii_name_ptr, mib_ii_name, sizeof(mib_ii_name));
  217. /*
  218. ** Get the index of the conn entry data.
  219. */
  220. conn_entry_type_index = ARRAY_SIZE(mib_ii_name) - 1;
  221. /*
  222. ** Set up the bind list.
  223. */
  224. bind_ptr->name.idLength = ARRAY_SIZE(mib_ii_name);
  225. bind_ptr->name.ids = mib_ii_name;
  226. bind_list_ptr->list = bind_ptr;
  227. bind_list_ptr->len = 1;
  228. /*
  229. ** We start with the tcpConnLocalAddress field.
  230. */
  231. last_field = 1;
  232. /*
  233. ** First connection.
  234. */
  235. index = 0;
  236. /*
  237. ** Suck out that tcp connection info....
  238. */
  239. while (true) {
  240. if (!SnmpExtensionQueryPtr(SNMP_PDU_GETNEXT, bind_list_ptr, &error_status, &error_index)) {
  241. //if (!SnmpExtensionQueryPtr(ASN_RFC1157_GETNEXTREQUEST, bind_list_ptr, &error_status, &error_index)) {
  242. DEBUG_LOG(("SnmpExtensionQuery returned false\n"));
  243. SnmpUtilMemFreePtr(bind_list_ptr);
  244. SnmpUtilMemFreePtr(bind_ptr);
  245. FreeLibrary(snmpapi_dll);
  246. FreeLibrary(mib_ii_dll);
  247. return(false);
  248. }
  249. /*
  250. ** If this is something new we aren't looking for then we are done.
  251. */
  252. if (bind_ptr->name.idLength < ARRAY_SIZE(mib_ii_name)) {
  253. break;
  254. }
  255. /*
  256. ** Get the type of info we are looking at. See RFC1213.
  257. **
  258. ** 1 = tcpConnState
  259. ** 2 = tcpConnLocalAddress
  260. ** 3 = tcpConnLocalPort
  261. ** 4 = tcpConnRemAddress
  262. ** 5 = tcpConnRemPort
  263. **
  264. ** tcpConnState is one of the following...
  265. **
  266. ** 1 closed
  267. ** 2 listen
  268. ** 3 synSent
  269. ** 4 synReceived
  270. ** 5 established
  271. ** 6 finWait1
  272. ** 7 finWait2
  273. ** 8 closeWait
  274. ** 9 lastAck
  275. ** 10 closing
  276. ** 11 timeWait
  277. ** 12 deleteTCB
  278. */
  279. conn_entry_type = bind_ptr->name.ids[conn_entry_type_index];
  280. if (last_field != conn_entry_type) {
  281. index = 0;
  282. last_field = conn_entry_type;
  283. }
  284. switch (conn_entry_type) {
  285. /*
  286. ** 1. First field in the entry. Need to create a new connection info struct
  287. ** here to store this connection in.
  288. */
  289. case tcpConnState:
  290. {
  291. ConnInfoStruct new_conn;
  292. new_conn.State = bind_ptr->value.asnValue.number;
  293. connectionVector.push_back(new_conn);
  294. break;
  295. }
  296. /*
  297. ** 2. Local address field.
  298. */
  299. case tcpConnLocalAddress:
  300. DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index"));
  301. connectionVector[index].LocalIP = *((unsigned long*)bind_ptr->value.asnValue.address.stream);
  302. index++;
  303. break;
  304. /*
  305. ** 3. Local port field.
  306. */
  307. case tcpConnLocalPort:
  308. DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index"));
  309. connectionVector[index].LocalPort = bind_ptr->value.asnValue.number;
  310. //connectionVector[index]->LocalPort = ntohs(connectionVector[index]->LocalPort);
  311. index++;
  312. break;
  313. /*
  314. ** 4. Remote address field.
  315. */
  316. case tcpConnRemAddress:
  317. DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index"));
  318. connectionVector[index].RemoteIP = *((unsigned long*)bind_ptr->value.asnValue.address.stream);
  319. index++;
  320. break;
  321. /*
  322. ** 5. Remote port field.
  323. */
  324. case tcpConnRemPort:
  325. DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index"));
  326. connectionVector[index].RemotePort = bind_ptr->value.asnValue.number;
  327. //connectionVector[index]->RemotePort = ntohs(connectionVector[index]->RemotePort);
  328. index++;
  329. break;
  330. }
  331. }
  332. SnmpUtilMemFreePtr(bind_list_ptr);
  333. SnmpUtilMemFreePtr(bind_ptr);
  334. SnmpUtilMemFreePtr(mib_ii_name_ptr);
  335. DEBUG_LOG(("Got %d connections in list, parsing...\n", connectionVector.size()));
  336. /*
  337. ** Right, we got the lot. Lets see if any of them have the same address as the chat
  338. ** server we think we are talking to.
  339. */
  340. found = false;
  341. for (Int i=0; i<connectionVector.size(); ++i) {
  342. ConnInfoStruct connection = connectionVector[i];
  343. temp = ntohl(connection.RemoteIP);
  344. memcpy(remoteAddress, (unsigned char*)&temp, 4);
  345. /*
  346. ** See if this connection has the same address as our server.
  347. */
  348. if (!found && memcmp(remoteAddress, serverAddress, 4) == 0) {
  349. DEBUG_LOG(("Found connection with same remote address as server\n"));
  350. if (serverPort == 0 || serverPort == (unsigned int)connection.RemotePort) {
  351. DEBUG_LOG(("Connection has same port\n"));
  352. /*
  353. ** Make sure the connection is current.
  354. */
  355. if (connection.State == ESTABLISHED) {
  356. DEBUG_LOG(("Connection is ESTABLISHED\n"));
  357. localIP = connection.LocalIP;
  358. found = true;
  359. } else {
  360. DEBUG_LOG(("Connection is not ESTABLISHED - skipping\n"));
  361. }
  362. } else {
  363. DEBUG_LOG(("Connection has different port. Port is %d, looking for %d\n", connection.RemotePort, serverPort));
  364. }
  365. }
  366. }
  367. if (found) {
  368. DEBUG_LOG(("Using address 0x%8.8X to talk to chat server\n", localIP));
  369. }
  370. FreeLibrary(snmpapi_dll);
  371. FreeLibrary(mib_ii_dll);
  372. return(found);
  373. }
  374. // GameSpyGameInfo ----------------------------------------
  375. GameSpyGameInfo::GameSpyGameInfo()
  376. {
  377. m_isQM = FALSE;
  378. m_hasBeenQueried = FALSE;
  379. for (Int i = 0; i< MAX_SLOTS; ++i)
  380. setSlotPointer(i, &m_GameSpySlot[i]);
  381. UnsignedInt localIP;
  382. if (GetLocalChatConnectionAddress("peerchat.gamespy.com", 6667, localIP))
  383. {
  384. localIP = ntohl(localIP); // The IP returned from GetLocalChatConnectionAddress is in network byte order.
  385. setLocalIP(localIP);
  386. }
  387. else
  388. {
  389. setLocalIP(0);
  390. }
  391. m_server = NULL;
  392. m_transport = NULL;
  393. }
  394. // Misc game-related functionality --------------------
  395. void GameSpyStartGame( void )
  396. {
  397. if (TheGameSpyGame)
  398. {
  399. int i;
  400. int numUsers = 0;
  401. for (i=0; i<MAX_SLOTS; ++i)
  402. {
  403. GameSlot *slot = TheGameSpyGame->getSlot(i);
  404. if (slot && slot->isOccupied())
  405. numUsers++;
  406. }
  407. if (numUsers < 2)
  408. {
  409. if (TheGameSpyGame->amIHost())
  410. {
  411. UnicodeString text;
  412. text.format(TheGameText->fetch("LAN:NeedMorePlayers"),numUsers);
  413. TheGameSpyInfo->addText(text, GSCOLOR_DEFAULT, NULL);
  414. }
  415. return;
  416. }
  417. TheGameSpyGame->startGame(0);
  418. }
  419. }
  420. void GameSpyLaunchGame( void )
  421. {
  422. if (TheGameSpyGame)
  423. {
  424. // Set up the game network
  425. AsciiString user;
  426. AsciiString userList;
  427. DEBUG_ASSERTCRASH(TheNetwork == NULL, ("For some reason TheNetwork isn't NULL at the start of this game. Better look into that."));
  428. if (TheNetwork != NULL) {
  429. delete TheNetwork;
  430. TheNetwork = NULL;
  431. }
  432. // Time to initialize TheNetwork for this game.
  433. TheNetwork = NetworkInterface::createNetwork();
  434. TheNetwork->init();
  435. /*
  436. if (!TheGameSpyGame->amIHost())
  437. TheNetwork->setLocalAddress((207<<24) | (138<<16) | (47<<8) | 15, 8088);
  438. else
  439. */
  440. TheNetwork->setLocalAddress(TheGameSpyGame->getLocalIP(), TheNAT->getSlotPort(TheGameSpyGame->getLocalSlotNum()));
  441. TheNetwork->attachTransport(TheNAT->getTransport());
  442. user = TheGameSpyInfo->getLocalName();
  443. for (Int i=0; i<MAX_SLOTS; ++i)
  444. {
  445. GameSlot *slot = TheGameSpyGame->getSlot(i);
  446. if (!slot)
  447. {
  448. DEBUG_CRASH(("No GameSlot[%d]!", i));
  449. delete TheNetwork;
  450. TheNetwork = NULL;
  451. return;
  452. }
  453. // UnsignedInt ip = htonl(slot->getIP());
  454. UnsignedInt ip = slot->getIP();
  455. AsciiString tmpUserName;
  456. tmpUserName.translate(slot->getName());
  457. if (ip)
  458. {
  459. /*
  460. if (i == 1)
  461. {
  462. user.format(",%[email protected]:8088", tmpUserName.str());
  463. }
  464. else
  465. */
  466. {
  467. user.format(",%s@%d.%d.%d.%d:%d", tmpUserName.str(),
  468. ((ip & 0xff000000) >> 24),
  469. ((ip & 0xff0000) >> 16),
  470. ((ip & 0xff00) >> 8),
  471. ((ip & 0xff)),
  472. TheNAT->getSlotPort(i)
  473. );
  474. }
  475. userList.concat(user);
  476. }
  477. }
  478. userList.trim();
  479. TheNetwork->parseUserList(TheGameSpyGame);
  480. // shutdown the top, but do not pop it off the stack
  481. // TheShell->hideShell();
  482. // setup the Global Data with the Map and Seed
  483. TheGlobalData->m_pendingFile = TheGameSpyGame->getMap();
  484. if (TheGameLogic->isInGame()) {
  485. TheGameLogic->clearGameData();
  486. }
  487. // send a message to the logic for a new game
  488. GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_NEW_GAME );
  489. msg->appendIntegerArgument(GAME_INTERNET);
  490. TheGlobalData->m_useFpsLimit = false;
  491. // Set the random seed
  492. InitGameLogicRandom( TheGameSpyGame->getSeed() );
  493. DEBUG_LOG(("InitGameLogicRandom( %d )\n", TheGameSpyGame->getSeed()));
  494. if (TheNAT != NULL) {
  495. delete TheNAT;
  496. TheNAT = NULL;
  497. }
  498. }
  499. }
  500. void GameSpyGameInfo::init( void )
  501. {
  502. GameInfo::init();
  503. m_hasBeenQueried = false;
  504. }
  505. void GameSpyGameInfo::resetAccepted( void )
  506. {
  507. GameInfo::resetAccepted();
  508. if (m_hasBeenQueried && amIHost())
  509. {
  510. // ANCIENTMUNKEE peerStateChanged(TheGameSpyChat->getPeer());
  511. m_hasBeenQueried = false;
  512. DEBUG_LOG(("resetAccepted() called peerStateChange()\n"));
  513. }
  514. }
  515. Int GameSpyGameInfo::getLocalSlotNum( void ) const
  516. {
  517. DEBUG_ASSERTCRASH(m_inGame, ("Looking for local game slot while not in game"));
  518. if (!m_inGame)
  519. return -1;
  520. AsciiString localName = TheGameSpyInfo->getLocalName();
  521. for (Int i=0; i<MAX_SLOTS; ++i)
  522. {
  523. const GameSlot *slot = getConstSlot(i);
  524. if (slot == NULL) {
  525. continue;
  526. }
  527. if (slot->isPlayer(localName))
  528. return i;
  529. }
  530. return -1;
  531. }
  532. void GameSpyGameInfo::gotGOACall( void )
  533. {
  534. DEBUG_LOG(("gotGOACall()\n"));
  535. m_hasBeenQueried = true;
  536. }
  537. void GameSpyGameInfo::startGame(Int gameID)
  538. {
  539. DEBUG_LOG(("GameSpyGameInfo::startGame - game id = %d\n", gameID));
  540. DEBUG_ASSERTCRASH(m_transport == NULL, ("m_transport is not NULL when it should be"));
  541. DEBUG_ASSERTCRASH(TheNAT == NULL, ("TheNAT is not NULL when it should be"));
  542. // fill in GS-specific info
  543. for (Int i=0; i<MAX_SLOTS; ++i)
  544. {
  545. if (m_GameSpySlot[i].isHuman())
  546. {
  547. AsciiString gsName;
  548. gsName.translate( m_GameSpySlot[i].getName() );
  549. m_GameSpySlot[i].setLoginName( gsName );
  550. PlayerInfoMap *pInfoMap = TheGameSpyInfo->getPlayerInfoMap();
  551. PlayerInfoMap::iterator it = pInfoMap->find(gsName);
  552. if (it != pInfoMap->end())
  553. {
  554. m_GameSpySlot[i].setProfileID(it->second.m_profileID);
  555. m_GameSpySlot[i].setLocale(it->second.m_locale);
  556. }
  557. else
  558. {
  559. DEBUG_CRASH(("No player info for %s", gsName.str()));
  560. }
  561. }
  562. }
  563. if (TheNAT != NULL) {
  564. delete TheNAT;
  565. TheNAT = NULL;
  566. }
  567. TheNAT = NEW NAT();
  568. TheNAT->attachSlotList(m_slot, getLocalSlotNum(), m_localIP);
  569. TheNAT->establishConnectionPaths();
  570. }
  571. AsciiString GameSpyGameInfo::generateGameResultsPacket( void )
  572. {
  573. Int i;
  574. Int endFrame = TheVictoryConditions->getEndFrame();
  575. Int localSlotNum = getLocalSlotNum();
  576. //GameSlot *localSlot = getSlot(localSlotNum);
  577. Bool sawGameEnd = (endFrame > 0);// && localSlot->lastFrameInGame() <= endFrame);
  578. Int winningTeam = -1;
  579. Int numPlayers = 0;
  580. Int numTeamsAtGameEnd = 0;
  581. Int lastTeamAtGameEnd = -1;
  582. for (i=0; i<MAX_SLOTS; ++i)
  583. {
  584. AsciiString playerName;
  585. playerName.format("player%d", i);
  586. Player *p = ThePlayerList->findPlayerWithNameKey(NAMEKEY(playerName));
  587. if (p)
  588. {
  589. ++numPlayers;
  590. if (TheVictoryConditions->hasAchievedVictory(p))
  591. {
  592. winningTeam = getSlot(i)->getTeamNumber();
  593. }
  594. // check if he lasted
  595. GameSlot *slot = getSlot(i);
  596. if (!slot->disconnected())
  597. {
  598. if (slot->getTeamNumber() != lastTeamAtGameEnd || numTeamsAtGameEnd == 0)
  599. {
  600. lastTeamAtGameEnd = slot->getTeamNumber();
  601. ++numTeamsAtGameEnd;
  602. }
  603. }
  604. }
  605. }
  606. AsciiString results;
  607. results.format("seed=%d,slotNum=%d,sawDesync=%d,sawGameEnd=%d,winningTeam=%d,disconEnd=%d,duration=%d,numPlayers=%d,isQM=%d",
  608. getSeed(), localSlotNum, TheNetwork->sawCRCMismatch(), sawGameEnd, winningTeam, (numTeamsAtGameEnd != 0),
  609. endFrame, numPlayers, m_isQM);
  610. Int playerID = 0;
  611. for (i=0; i<MAX_SLOTS; ++i)
  612. {
  613. AsciiString playerName;
  614. playerName.format("player%d", i);
  615. Player *p = ThePlayerList->findPlayerWithNameKey(NAMEKEY(playerName));
  616. if (p)
  617. {
  618. GameSpyGameSlot *slot = &(m_GameSpySlot[i]);
  619. ScoreKeeper *keeper = p->getScoreKeeper();
  620. AsciiString playerName = slot->getLoginName();
  621. Int gsPlayerID = slot->getProfileID();
  622. AsciiString locale = slot->getLocale();
  623. Int fps = TheNetwork->getAverageFPS();
  624. Int unitsKilled = keeper->getTotalUnitsDestroyed();
  625. Int unitsLost = keeper->getTotalUnitsLost();
  626. Int unitsBuilt = keeper->getTotalUnitsBuilt();
  627. Int buildingsKilled = keeper->getTotalBuildingsDestroyed();
  628. Int buildingsLost = keeper->getTotalBuildingsLost();
  629. Int buildingsBuilt = keeper->getTotalBuildingsBuilt();
  630. Int earnings = keeper->getTotalMoneyEarned();
  631. Int techCaptured = keeper->getTotalTechBuildingsCaptured();
  632. Bool disconnected = slot->disconnected();
  633. AsciiString playerStr;
  634. playerStr.format(",player%d=%s,playerID%d=%d,locale%d=%s",
  635. playerID, playerName.str(), playerID, gsPlayerID, playerID, locale.str());
  636. results.concat(playerStr);
  637. playerStr.format(",unitsKilled%d=%d,unitsLost%d=%d,unitsBuilt%d=%d",
  638. playerID, unitsKilled, playerID, unitsLost, playerID, unitsBuilt);
  639. results.concat(playerStr);
  640. playerStr.format(",buildingsKilled%d=%d,buildingsLost%d=%d,buildingsBuilt%d=%d",
  641. playerID, buildingsKilled, playerID, buildingsLost, playerID, buildingsBuilt);
  642. results.concat(playerStr);
  643. playerStr.format(",fps%d=%d,cash%d=%d,capturedTech%d=%d,discon%d=%d",
  644. playerID, fps, playerID, earnings, playerID, techCaptured, playerID, disconnected);
  645. results.concat(playerStr);
  646. ++playerID;
  647. }
  648. }
  649. // Add a trailing size value (so the server can ensure it got the entire packet)
  650. int resultsLen = results.getLength()+10;
  651. AsciiString tail;
  652. tail.format("%10.10d", resultsLen);
  653. results.concat(tail);
  654. return results;
  655. }