GameSpy.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417
  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: GameSpy.cpp //////////////////////////////////////////////////////
  24. // GameSpy callbacks, etc
  25. // Author: Matthew D. Campbell, February 2002
  26. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  27. #include "GameSpy/GP/GP.h"
  28. #include "GameSpy/gstats/gpersist.h"
  29. #include "GameNetwork/FirewallHelper.h"
  30. #include "GameNetwork/GameSpy.h"
  31. #include "GameNetwork/GameSpyChat.h"
  32. #include "GameNetwork/GameSpyGameInfo.h"
  33. #include "GameNetwork/GameSpyOverlay.h"
  34. #include "GameNetwork/GameSpyGP.h"
  35. #include "GameNetwork/GameSpyPersistentStorage.h"
  36. #include "GameNetwork/GameSpyThread.h"
  37. #include "GameNetwork/NAT.h"
  38. #include "GameClient/Shell.h"
  39. #include "GameClient/MessageBox.h"
  40. #include "GameClient/GameText.h"
  41. #include "GameClient/MapUtil.h"
  42. #include "Common/Version.h"
  43. #include "Common/MultiplayerSettings.h"
  44. #include "Common/PlayerTemplate.h"
  45. #include "Common/RandomValue.h"
  46. #include "Common/GlobalData.h"
  47. #include "Common/UserPreferences.h"
  48. #include "GameLogic/ScriptEngine.h"
  49. MutexClass TheGameSpyMutex;
  50. static UnsignedInt mainThreadID = 0;
  51. static Bool inThread = false;
  52. #define ISMAINTHREAD ( ThreadClass::_Get_Current_Thread_ID() == mainThreadID )
  53. GameSpyThreadClass *TheGameSpyThread = NULL;
  54. /// polling/update thread function
  55. void GameSpyThreadClass::Thread_Function()
  56. {
  57. //poll network and update GameSpy object
  58. while (running)
  59. {
  60. inThread = true;
  61. if (m_doLogin)
  62. {
  63. m_doLogin = false;
  64. TheGameSpyChat->login(m_nick, m_pass, m_email);
  65. }
  66. if (m_readStats)
  67. {
  68. m_readStats = false;
  69. TheGameSpyPlayerInfo->threadReadFromServer();
  70. }
  71. if (m_updateLocale)
  72. {
  73. m_updateLocale = false;
  74. TheGameSpyPlayerInfo->threadSetLocale(m_locale);
  75. }
  76. if (m_updateWins)
  77. {
  78. m_updateWins = false;
  79. TheGameSpyPlayerInfo->threadSetLocale(m_wins);
  80. }
  81. if (m_updateLosses)
  82. {
  83. m_updateLosses = false;
  84. TheGameSpyPlayerInfo->threadSetLocale(m_losses);
  85. }
  86. inThread = false;
  87. Switch_Thread();
  88. }
  89. }
  90. AsciiString GameSpyThreadClass::getNextShellScreen( void )
  91. {
  92. MutexClass::LockClass m(TheGameSpyMutex, 0);
  93. if (m.Failed())
  94. return AsciiString::TheEmptyString;
  95. return m_nextShellScreen;
  96. }
  97. Bool GameSpyThreadClass::showLocaleSelect( void )
  98. {
  99. MutexClass::LockClass m(TheGameSpyMutex, 0);
  100. if (m.Failed())
  101. return false;
  102. return m_showLocaleSelect;
  103. }
  104. void GameSpyThreadClass::setNextShellScreen( AsciiString nextShellScreen )
  105. {
  106. MutexClass::LockClass m(TheGameSpyMutex);
  107. m_nextShellScreen = nextShellScreen;
  108. }
  109. void GameSpyThreadClass::setShowLocaleSelect( Bool val )
  110. {
  111. MutexClass::LockClass m(TheGameSpyMutex);
  112. m_showLocaleSelect = val;
  113. }
  114. void createRoomCallback(PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void *param);
  115. class GameSpyChat : public GameSpyChatInterface
  116. {
  117. public:
  118. GameSpyChat();
  119. virtual ~GameSpyChat();
  120. virtual void init( void );
  121. virtual void reset( void );
  122. virtual void update( void );
  123. virtual Bool isConnected( void );
  124. virtual void login(AsciiString loginName, AsciiString password = AsciiString::TheEmptyString, AsciiString email = AsciiString::TheEmptyString);
  125. virtual void reconnectProfile( void );
  126. virtual void disconnectFromChat( void );
  127. virtual void UTMRoom( RoomType roomType, const char *key, const char *val, Bool authenticate = FALSE );
  128. virtual void UTMPlayer( const char *name, const char *key, const char *val, Bool authenticate = FALSE );
  129. virtual void startGame( void );
  130. virtual void leaveRoom( RoomType roomType );
  131. virtual void setReady( Bool ready );
  132. virtual void enumPlayers( RoomType roomType, peerEnumPlayersCallback callback, void *userData );
  133. virtual void startListingGames( peerListingGamesCallback callback );
  134. virtual void stopListingGames( void );
  135. virtual void joinGroupRoom( Int ID );
  136. virtual void joinStagingRoom( GServer server, AsciiString password );
  137. virtual void createStagingRoom( AsciiString gameName, AsciiString password, Int maxPlayers );
  138. virtual void joinBestGroupRoom( void );
  139. void loginQuick(AsciiString loginName);
  140. void loginProfile(AsciiString loginName, AsciiString password, AsciiString email);
  141. void setProfileID( Int ID ) { m_profileID = ID; }
  142. void _connectCallback(PEER peer, PEERBool success, void * param);
  143. void _nickErrorCallback(PEER peer, int type, const char * nick, void * param);
  144. void _GPConnectCallback(GPConnection * pconnection, GPConnectResponseArg * arg, void * param);
  145. void _GPReconnectCallback(GPConnection * pconnection, GPConnectResponseArg * arg, void * param);
  146. inline void finishJoiningGroupRoom( void ) { m_joiningGroupRoom = false; }
  147. inline void finishJoiningStagingRoom( void ) { m_joiningStagingRoom = false; }
  148. private:
  149. UnsignedInt m_loginTimeoutPeriod; // in ms
  150. UnsignedInt m_loginTimeout;
  151. Bool m_joiningGroupRoom;
  152. Bool m_joiningStagingRoom;
  153. GameSpyThreadClass thread;
  154. };
  155. GameSpyChatInterface *TheGameSpyChat;
  156. GameSpyChatInterface *createGameSpyChat( void )
  157. {
  158. mainThreadID = ThreadClass::_Get_Current_Thread_ID();
  159. return NEW GameSpyChat;
  160. }
  161. void GameSpyChatInterface::clearGroupRoomList(void)
  162. {
  163. m_groupRooms.clear();
  164. }
  165. GameSpyChat::GameSpyChat()
  166. {
  167. m_peer = NULL;
  168. }
  169. GameSpyChat::~GameSpyChat()
  170. {
  171. reset();
  172. if (thread.Is_Running())
  173. thread.Stop();
  174. TheGameSpyThread = NULL;
  175. }
  176. void GameSpyChat::init( void )
  177. {
  178. reset();
  179. DEBUG_ASSERTCRASH(!thread.Is_Running(), ("Thread is running"));
  180. thread.Execute();
  181. thread.Set_Priority(0);
  182. TheGameSpyThread = &thread;
  183. }
  184. void GameSpyChat::reset( void )
  185. {
  186. MutexClass::LockClass m(TheGameSpyMutex);
  187. m_loginName.clear();
  188. m_password.clear();
  189. m_email.clear();
  190. m_usingProfiles = false;
  191. m_profileID = 0;
  192. if (m_peer)
  193. peerShutdown(m_peer);
  194. m_peer = NULL;
  195. m_groupRooms.clear();
  196. m_currentGroupRoomID = 0;
  197. m_loginTimeoutPeriod = 5000;
  198. m_loginTimeout = 0;
  199. m_joiningGroupRoom = false;
  200. m_joiningStagingRoom = false;
  201. //if (thread.Is_Running())
  202. //thread.Stop();
  203. }
  204. void GameSpyChat::update( void )
  205. {
  206. MutexClass::LockClass m(TheGameSpyMutex, 0);
  207. if (!m.Failed() && m_peer)
  208. {
  209. if (!TheGameSpyThread->getNextShellScreen().isEmpty())
  210. {
  211. TheShell->pop();
  212. TheShell->push(TheGameSpyThread->getNextShellScreen());
  213. TheGameSpyThread->setNextShellScreen( AsciiString.TheEmptyString );
  214. }
  215. if (TheGameSpyThread->showLocaleSelect())
  216. {
  217. TheGameSpyThread->setShowLocaleSelect(false);
  218. WindowLayout *layout = NULL;
  219. layout = TheWindowManager->winCreateLayout( AsciiString( "Menus/PopupLocaleSelect.wnd" ) );
  220. layout->runInit();
  221. layout->hide( FALSE );
  222. layout->bringForward();
  223. TheWindowManager->winSetModal( layout->getFirstWindow() );
  224. }
  225. //if (!isConnected())
  226. //return;
  227. peerThink(m_peer);
  228. gpProcess(TheGPConnection);
  229. if (TheNAT != NULL) {
  230. NATStateType NATState = TheNAT->update();
  231. if (NATState == NATSTATE_DONE)
  232. {
  233. GameSpyLaunchGame();
  234. }
  235. else if (NATState == NATSTATE_FAILED)
  236. {
  237. GameSpyLaunchGame();
  238. }
  239. }
  240. if (TheFirewallHelper != NULL) {
  241. if (TheFirewallHelper->behaviorDetectionUpdate()) {
  242. TheGlobalData->m_firewallBehavior = TheFirewallHelper->getFirewallBehavior();
  243. OptionPreferences *pref = NEW OptionPreferences;
  244. char num[16];
  245. num[0] = 0;
  246. itoa(TheGlobalData->m_firewallBehavior, num, 10);
  247. AsciiString numstr;
  248. numstr = num;
  249. (*pref)["FirewallBehavior"] = numstr;
  250. pref->write();
  251. // we are now done with the firewall helper
  252. delete TheFirewallHelper;
  253. TheFirewallHelper = NULL;
  254. }
  255. }
  256. UnsignedInt now = timeGetTime();
  257. if (m_loginTimeout && now > m_loginTimeout)
  258. {
  259. // login timed out
  260. m_loginTimeout = 0;
  261. GSMessageBoxOk(UnicodeString(L"Error connecting"), UnicodeString(L"Timed out connecting"), NULL);
  262. // Enable controls again
  263. //EnableLoginControls(TRUE);
  264. if (TheGameSpyGame)
  265. delete TheGameSpyGame;
  266. TheGameSpyGame = NULL;
  267. if (m_peer)
  268. peerShutdown(m_peer);
  269. m_peer = NULL;
  270. gpDisconnect(TheGPConnection);
  271. gpDestroy(TheGPConnection);
  272. }
  273. }
  274. }
  275. Bool GameSpyChat::isConnected( void )
  276. {
  277. return m_peer && peerIsConnected(m_peer);
  278. }
  279. void GameSpyChat::UTMRoom( RoomType roomType, const char *key, const char *val, Bool authenticate )
  280. {
  281. peerUTMRoom( m_peer, roomType, key, val, (authenticate)?PEERTrue:PEERFalse );
  282. }
  283. void GameSpyChat::UTMPlayer( const char *name, const char *key, const char *val, Bool authenticate )
  284. {
  285. peerUTMPlayer( m_peer, name, key, val, (authenticate)?PEERTrue:PEERFalse );
  286. }
  287. void GameSpyChat::startGame( void )
  288. {
  289. peerStartGame( m_peer, NULL, PEER_STOP_REPORTING );
  290. }
  291. void GameSpyChat::leaveRoom( RoomType roomType )
  292. {
  293. peerLeaveRoom( m_peer, roomType, NULL );
  294. }
  295. void GameSpyChat::setReady( Bool ready )
  296. {
  297. peerSetReady( m_peer, (ready)?PEERTrue:PEERFalse );
  298. }
  299. void GameSpyChat::enumPlayers( RoomType roomType, peerEnumPlayersCallback callback, void *userData )
  300. {
  301. peerEnumPlayers( m_peer, roomType, callback, userData );
  302. }
  303. void GameSpyChat::startListingGames( peerListingGamesCallback callback )
  304. {
  305. peerSetUpdatesRoomChannel( m_peer, "#gmtest_updates" );
  306. peerStartListingGames( m_peer, NULL, callback, NULL );
  307. }
  308. void GameSpyChat::stopListingGames( void )
  309. {
  310. peerStopListingGames( m_peer );
  311. }
  312. void GameSpyChat::joinGroupRoom( Int ID )
  313. {
  314. if (m_joiningGroupRoom || m_joiningStagingRoom)
  315. return;
  316. m_joiningGroupRoom = true;
  317. if (getCurrentGroupRoomID())
  318. {
  319. leaveRoom(GroupRoom);
  320. setCurrentGroupRoomID(0);
  321. }
  322. peerJoinGroupRoom(m_peer, ID, JoinRoomCallback, (void *)ID, PEERFalse);
  323. }
  324. void GameSpyChat::joinStagingRoom( GServer server, AsciiString password )
  325. {
  326. if (m_joiningGroupRoom || m_joiningStagingRoom)
  327. return;
  328. m_joiningStagingRoom = true;
  329. peerJoinStagingRoom(m_peer, server, password.str(), JoinRoomCallback, server, PEERFalse);
  330. }
  331. void GameSpyChat::createStagingRoom( AsciiString gameName, AsciiString password, Int maxPlayers )
  332. {
  333. if (m_joiningGroupRoom || m_joiningStagingRoom)
  334. return;
  335. m_joiningStagingRoom = true;
  336. Int oldGroupID = TheGameSpyChat->getCurrentGroupRoomID();
  337. TheGameSpyChat->leaveRoom(GroupRoom);
  338. TheGameSpyChat->setCurrentGroupRoomID(0);
  339. DEBUG_LOG(("GameSpyChat::createStagingRoom - creating staging room, name is %s\n", m_loginName.str()));
  340. peerCreateStagingRoom(m_peer, m_loginName.str(), maxPlayers, password.str(), createRoomCallback, (void *)oldGroupID, PEERFalse);
  341. }
  342. void GameSpyChat::joinBestGroupRoom( void )
  343. {
  344. if (m_groupRooms.size())
  345. {
  346. int minID = -1;
  347. int minPlayers = 1000;
  348. GroupRoomMap::iterator iter = m_groupRooms.begin();
  349. while (iter != m_groupRooms.end())
  350. {
  351. GameSpyGroupRoom room = iter->second;
  352. DEBUG_LOG(("Group room %d: %s (%d, %d, %d, %d)\n", room.m_groupID, room.m_name.str(), room.m_numWaiting, room.m_maxWaiting,
  353. room.m_numGames, room.m_numPlaying));
  354. if (minPlayers > 25 && room.m_numWaiting < minPlayers)
  355. {
  356. minID = room.m_groupID;
  357. minPlayers = room.m_numWaiting;
  358. }
  359. ++iter;
  360. }
  361. if (minID > 0)
  362. {
  363. joinGroupRoom(minID);
  364. }
  365. else
  366. {
  367. GSMessageBoxOk(UnicodeString(L"Oops"), UnicodeString(L"No empty group rooms"), NULL);
  368. }
  369. }
  370. else
  371. {
  372. GSMessageBoxOk(UnicodeString(L"Oops"), UnicodeString(L"No group rooms"), NULL);
  373. }
  374. }
  375. void GameSpyChat::disconnectFromChat( void )
  376. {
  377. TheScriptEngine->signalUIInteract("GameSpyLogout");
  378. if (m_peer)
  379. {
  380. peerShutdown(m_peer);
  381. m_peer = NULL;
  382. }
  383. if (TheGameSpyGame)
  384. delete TheGameSpyGame;
  385. TheGameSpyGame = NULL;
  386. }
  387. //-----------------------------------------------------------------------
  388. void DisconnectedCallback(PEER peer, const char * reason,
  389. void * param)
  390. {
  391. TheScriptEngine->signalUIInteract("GameSpyLogout");
  392. if (TheGameSpyGame)
  393. delete TheGameSpyGame;
  394. TheGameSpyGame = NULL;
  395. GSMessageBoxOk(TheGameText->fetch("GUI:GSErrorTitle"), TheGameText->fetch("GUI:GSDisconnected"), NULL);
  396. WindowLayout * mainMenu = TheShell->findScreenByFilename("Menus/MainMenu.wnd");
  397. if (mainMenu)
  398. {
  399. while (TheShell->top() != mainMenu)
  400. {
  401. TheShell->pop();
  402. }
  403. }
  404. }
  405. void ReadyChangedCallback(PEER peer, const char * nick,
  406. PEERBool ready, void * param)
  407. {
  408. if (TheGameSpyGame)
  409. {
  410. Int slotNum = TheGameSpyGame->getSlotNum(nick);
  411. if (slotNum >= 0)
  412. {
  413. GameSlot *slot = TheGameSpyGame->getSlot(slotNum);
  414. if (slot)
  415. {
  416. if (ready) {
  417. slot->setAccept();
  418. } else {
  419. slot->unAccept();
  420. }
  421. if (TheGameSpyGame->amIHost())
  422. {
  423. peerUTMRoom(TheGameSpyChat->getPeer(), StagingRoom, "SL/", GameInfoToAsciiString(TheGameSpyGame).str(), PEERFalse);
  424. }
  425. WOLDisplaySlotList();
  426. }
  427. }
  428. }
  429. }
  430. void GameStartedCallback(PEER peer, unsigned int IP,
  431. const char * message, void * param)
  432. {
  433. GameSpyStartGame();
  434. }
  435. void populateLobbyPlayerListbox(void);
  436. void PlayerJoinedCallback(PEER peer, RoomType roomType,
  437. const char * nick, void * param)
  438. {
  439. if (roomType == GroupRoom && TheGameSpyChat->getCurrentGroupRoomID())
  440. {
  441. populateLobbyPlayerListbox();
  442. }
  443. if (roomType == StagingRoom && TheGameSpyGame)
  444. {
  445. DEBUG_LOG(("StagingRoom, Game OK\n"));
  446. for (Int i=1; i<MAX_SLOTS; ++i)
  447. {
  448. GameSlot *slot = TheGameSpyGame->getSlot(i);
  449. if (slot && slot->getState() == SLOT_OPEN)
  450. {
  451. DEBUG_LOG(("Putting %s in slot %d\n", nick, i));
  452. UnicodeString uName;
  453. uName.translate(nick);
  454. slot->setState(SLOT_PLAYER, uName);
  455. slot->setColor(-1);
  456. slot->setPlayerTemplate(-1);
  457. slot->setStartPos(-1);
  458. slot->setTeamNumber(-1);
  459. TheGameSpyGame->resetAccepted();
  460. Int id;
  461. UnsignedInt ip;
  462. PEERBool success = peerGetPlayerInfoNoWait(TheGameSpyChat->getPeer(), nick, &ip, &id);
  463. DEBUG_LOG(("PlayerJoinedCallback - result from peerGetPlayerInfoNoWait, %d: ip=%d.%d.%d.%d, id=%d\n", success,
  464. (ip >> 24) & 0xff,
  465. (ip >> 16) & 0xff,
  466. (ip >> 8) & 0xff,
  467. ip & 0xff,
  468. id));
  469. success = PEERFalse; // silence compiler warnings in release build
  470. slot->setIP(ip);
  471. if (TheGameSpyGame->amIHost())
  472. {
  473. peerUTMRoom(TheGameSpyChat->getPeer(), StagingRoom, "SL/", GameInfoToAsciiString(TheGameSpyGame).str(), PEERFalse);
  474. }
  475. WOLDisplaySlotList();
  476. break;
  477. }
  478. }
  479. if (i == MAX_SLOTS)
  480. {
  481. // we got all the way through without room for him - kick him
  482. if (TheGameSpyGame->amIHost())
  483. {
  484. peerUTMRoom(TheGameSpyChat->getPeer(), StagingRoom, "SL/", GameInfoToAsciiString(TheGameSpyGame).str(), PEERFalse);
  485. }
  486. }
  487. }
  488. }
  489. void PlayerLeftCallback(PEER peer, RoomType roomType,
  490. const char * nick, const char * reason,
  491. void * param)
  492. {
  493. if (roomType == GroupRoom && TheGameSpyChat->getCurrentGroupRoomID())
  494. {
  495. populateLobbyPlayerListbox();
  496. }
  497. if (roomType == StagingRoom && TheGameSpyGame)
  498. {
  499. Int slotNum = TheGameSpyGame->getSlotNum(nick);
  500. if (slotNum >= 0)
  501. {
  502. GameSlot *slot = TheGameSpyGame->getSlot(slotNum);
  503. if (slot)
  504. {
  505. slot->setState(SLOT_OPEN);
  506. DEBUG_LOG(("Removing %s from slot %d\n", nick, slotNum));
  507. if (TheGameSpyGame->amIHost())
  508. {
  509. peerUTMRoom(TheGameSpyChat->getPeer(), StagingRoom, "SL/", GameInfoToAsciiString(TheGameSpyGame).str(), PEERFalse);
  510. }
  511. TheGameSpyGame->resetAccepted();
  512. WOLDisplaySlotList();
  513. }
  514. }
  515. }
  516. }
  517. void PlayerChangedNickCallback(PEER peer, RoomType roomType,
  518. const char * oldNick,
  519. const char * newNick, void * param)
  520. {
  521. if (TheGameSpyChat->getCurrentGroupRoomID())
  522. {
  523. populateLobbyPlayerListbox();
  524. }
  525. }
  526. void PingCallback(PEER peer, const char * nick, int ping,
  527. void * param)
  528. {
  529. DEBUG_LOG(("PingCallback\n"));
  530. }
  531. void CrossPingCallback(PEER peer, const char * nick1,
  532. const char * nick2, int crossPing,
  533. void * param)
  534. {
  535. DEBUG_LOG(("CrossPingCallback\n"));
  536. }
  537. static void RoomUTMCallback(PEER peer, RoomType roomType, const char * nick,
  538. const char * command, const char * parameters,
  539. PEERBool authenticated, void * param)
  540. {
  541. DEBUG_LOG(("RoomUTMCallback: %s says %s = [%s]\n", nick, command, parameters));
  542. if (roomType == StagingRoom && TheGameSpyGame)
  543. {
  544. Int slotNum = TheGameSpyGame->getSlotNum(nick);
  545. if (slotNum == 0 && !TheGameSpyGame->amIHost())
  546. {
  547. if (!strcmp(command, "SL"))
  548. {
  549. AsciiString options = parameters;
  550. options.trim();
  551. ParseAsciiStringToGameInfo(TheGameSpyGame, options.str());
  552. WOLDisplaySlotList();
  553. }
  554. else if (!strcmp(command, "HWS")) // HostWantsStart
  555. {
  556. Int slotNum = TheGameSpyGame->getLocalSlotNum();
  557. GameSlot *slot = TheGameSpyGame->getSlot(slotNum);
  558. if (slot->isAccepted() == false)
  559. {
  560. GameSpyAddText(TheGameText->fetch("GUI:HostWantsToStart"), GSCOLOR_DEFAULT);
  561. }
  562. }
  563. }
  564. }
  565. }
  566. static void PlayerUTMCallback(PEER peer, const char * nick,
  567. const char * command, const char * parameters,
  568. PEERBool authenticated, void * param)
  569. {
  570. DEBUG_LOG(("PlayerUTMCallback: %s says %s = [%s]\n", nick, command, parameters));
  571. if (TheGameSpyGame)
  572. {
  573. Int slotNum = TheGameSpyGame->getSlotNum(nick);
  574. if (slotNum != 0 && TheGameSpyGame->amIHost())
  575. {
  576. if (!strcmp(command, "REQ"))
  577. {
  578. AsciiString options = parameters;
  579. options.trim();
  580. Bool change = false;
  581. Bool shouldUnaccept = false;
  582. AsciiString key;
  583. options.nextToken(&key, "=");
  584. Int val = atoi(options.str()+1);
  585. UnsignedInt uVal = atoi(options.str()+1);
  586. DEBUG_LOG(("GameOpt request: key=%s, val=%s from player %d\n", key.str(), options.str(), slotNum));
  587. GameSlot *slot = TheGameSpyGame->getSlot(slotNum);
  588. if (!slot)
  589. return;
  590. if (key == "Color")
  591. {
  592. if (val >= -1 && val < TheMultiplayerSettings->getNumColors() && val != slot->getColor())
  593. {
  594. Bool colorAvailable = TRUE;
  595. if(val != -1 )
  596. {
  597. for(Int i=0; i <MAX_SLOTS; i++)
  598. {
  599. GameSlot *checkSlot = TheGameSpyGame->getSlot(i);
  600. if(val == checkSlot->getColor() && slot != checkSlot)
  601. {
  602. colorAvailable = FALSE;
  603. break;
  604. }
  605. }
  606. }
  607. if(colorAvailable)
  608. slot->setColor(val);
  609. change = true;
  610. }
  611. else
  612. {
  613. DEBUG_LOG(("Rejecting invalid color %d\n", val));
  614. }
  615. }
  616. else if (key == "PlayerTemplate")
  617. {
  618. if (val >= PLAYERTEMPLATE_MIN && val < ThePlayerTemplateStore->getPlayerTemplateCount() && val != slot->getPlayerTemplate())
  619. {
  620. slot->setPlayerTemplate(val);
  621. change = true;
  622. shouldUnaccept = true;
  623. }
  624. else
  625. {
  626. DEBUG_LOG(("Rejecting invalid PlayerTemplate %d\n", val));
  627. }
  628. }
  629. else if (key == "StartPos")
  630. {
  631. if (val >= -1 && val < MAX_SLOTS && val != slot->getStartPos())
  632. {
  633. slot->setStartPos(val);
  634. change = true;
  635. shouldUnaccept = true;
  636. }
  637. else
  638. {
  639. DEBUG_LOG(("Rejecting invalid startPos %d\n", val));
  640. }
  641. }
  642. else if (key == "Team")
  643. {
  644. if (val >= -1 && val < MAX_SLOTS/2 && val != slot->getTeamNumber())
  645. {
  646. slot->setTeamNumber(val);
  647. change = true;
  648. shouldUnaccept = true;
  649. }
  650. else
  651. {
  652. DEBUG_LOG(("Rejecting invalid team %d\n", val));
  653. }
  654. }
  655. else if (key == "IP")
  656. {
  657. if (uVal != slot->getIP())
  658. {
  659. slot->setIP(uVal);
  660. change = true;
  661. shouldUnaccept = true;
  662. }
  663. else
  664. {
  665. DEBUG_LOG(("Rejecting invalid IP %d\n", uVal));
  666. }
  667. }
  668. else if (key == "NAT")
  669. {
  670. if ((val >= FirewallHelperClass::FIREWALL_TYPE_SIMPLE) &&
  671. (val <= FirewallHelperClass::FIREWALL_TYPE_DESTINATION_PORT_DELTA))
  672. {
  673. slot->setNATBehavior((FirewallHelperClass::FirewallBehaviorType)val);
  674. DEBUG_LOG(("Setting NAT behavior to %d for player %d\n", val, slotNum));
  675. change = true;
  676. }
  677. else
  678. {
  679. DEBUG_LOG(("Rejecting invalid NAT behavior %d from player %d\n", val, slotNum));
  680. }
  681. }
  682. if (change)
  683. {
  684. if (shouldUnaccept)
  685. TheGameSpyGame->resetAccepted();
  686. peerUTMRoom(TheGameSpyChat->getPeer(), StagingRoom, "SL/", GameInfoToAsciiString(TheGameSpyGame).str(), PEERFalse);
  687. WOLDisplaySlotList();
  688. DEBUG_LOG(("Slot value is color=%d, PlayerTemplate=%d, startPos=%d, team=%d, IP=0x%8.8X\n",
  689. slot->getColor(), slot->getPlayerTemplate(), slot->getStartPos(), slot->getTeamNumber(), slot->getIP()));
  690. DEBUG_LOG(("Slot list updated to %s\n", GameInfoToAsciiString(TheGameSpyGame).str()));
  691. }
  692. }
  693. }
  694. }
  695. }
  696. void GOABasicCallback(PEER peer, PEERBool playing, char * outbuf,
  697. int maxlen, void * param)
  698. {
  699. _snprintf(outbuf, maxlen, "\\gamename\\c&cgenerals\\gamever\\%s\\location\\%d",
  700. TheVersion->getAsciiVersion().str(), 0);
  701. outbuf[maxlen-1] = 0;
  702. DEBUG_LOG(("GOABasicCallback: [%s]\n", outbuf));
  703. TheGameSpyGame->gotGOACall();
  704. }
  705. void GOAInfoCallback(PEER peer, PEERBool playing, char * outbuf,
  706. int maxlen, void * param)
  707. {
  708. _snprintf(outbuf, maxlen, "\\hostname\\%s\\hostport\\%d\\mapname\\%s\\gametype\\%s\\numplayers\\%d\\maxplayers\\%d\\gamemode\\%s",
  709. TheGameSpyChat->getLoginName().str(), 0, TheGameSpyGame->getMap().str(), "battle", TheGameSpyGame->getNumPlayers(), TheGameSpyGame->getMaxPlayers(), "wait");
  710. outbuf[maxlen-1] = 0;
  711. DEBUG_LOG(("GOAInfoCallback: [%s]\n", outbuf));
  712. TheGameSpyGame->gotGOACall();
  713. }
  714. void GOARulesCallback(PEER peer, PEERBool playing, char * outbuf,
  715. int maxlen, void * param)
  716. {
  717. _snprintf(outbuf, maxlen, "\\password\\0\\seed\\%d",
  718. TheGameSpyGame->getSeed());
  719. outbuf[maxlen-1] = 0;
  720. DEBUG_LOG(("GOARulesCallback: [%s]\n", outbuf));
  721. TheGameSpyGame->gotGOACall();
  722. }
  723. void GOAPlayersCallback(PEER peer, PEERBool playing, char * outbuf,
  724. int maxlen, void * param)
  725. {
  726. AsciiString buf, tmp;
  727. for (Int i=0; i<MAX_SLOTS; ++i)
  728. {
  729. DEBUG_LOG(("GOAPlayersCallback - about to call getSlot for player %d\n", i));
  730. GameSlot *slot = TheGameSpyGame->getSlot(i);
  731. AsciiString name;
  732. switch (slot->getState())
  733. {
  734. case SLOT_OPEN:
  735. name = "O";
  736. break;
  737. case SLOT_CLOSED:
  738. name = "X";
  739. break;
  740. case SLOT_EASY_AI:
  741. name = "CE";
  742. break;
  743. case SLOT_MED_AI:
  744. name = "CM";
  745. break;
  746. case SLOT_BRUTAL_AI:
  747. name = "CB";
  748. break;
  749. case SLOT_PLAYER:
  750. {
  751. AsciiString tmp;
  752. tmp.translate(slot->getName());
  753. name.format("H%s", tmp.str());
  754. }
  755. break;
  756. default:
  757. name = "?";
  758. break;
  759. }
  760. tmp.format("\\player_%d\\%s\\color_%d\\%d\\faction_%d\\%d\\team_%d\\%d\\pos_%d\\%d",
  761. i, name.str(),
  762. i, slot->getColor(),
  763. i, slot->getPlayerTemplate(),
  764. i, slot->getTeamNumber(),
  765. i, slot->getStartPos());
  766. buf.concat(tmp);
  767. }
  768. _snprintf(outbuf, maxlen, buf.str());
  769. outbuf[maxlen-1] = 0;
  770. DEBUG_LOG(("GOAPlayersCallback: [%s]\n", outbuf));
  771. TheGameSpyGame->gotGOACall();
  772. }
  773. void JoinRoomCallback(PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void *param)
  774. {
  775. DEBUG_LOG(("JoinRoomCallback: success==%d, result==%d\n", success, result));
  776. switch (roomType)
  777. {
  778. case GroupRoom:
  779. {
  780. ((GameSpyChat *)TheGameSpyChat)->finishJoiningGroupRoom();
  781. if (success)
  782. {
  783. // update our internal group room ID
  784. TheGameSpyChat->setCurrentGroupRoomID((Int)param);
  785. // see if we need to change screens
  786. WindowLayout *layout = TheShell->top();
  787. AsciiString windowFile = layout->getFilename();
  788. DEBUG_LOG(("Joined group room, active screen was %s\n", windowFile.str()));
  789. if (windowFile.compareNoCase("Menus/WOLCustomLobby.wnd") == 0)
  790. {
  791. // already on the right screen - just refresh it
  792. //GroupRoomJoinLobbyRefresh();
  793. }
  794. else
  795. {
  796. // change to the right screen
  797. TheShell->pop();
  798. TheShell->push("Menus/WOLCustomLobby.wnd");
  799. }
  800. }
  801. else
  802. {
  803. // failed to join lobby - bail to welcome screen
  804. WindowLayout *layout = TheShell->top();
  805. AsciiString windowFile = layout->getFilename();
  806. DEBUG_LOG(("Joined group room, active screen was %s\n", windowFile.str()));
  807. if (windowFile.compareNoCase("Menus/WOLWelcomeMenu.wnd") != 0)
  808. {
  809. TheShell->pop();
  810. TheShell->push("Menus/WOLWelcomeMenu.wnd");
  811. }
  812. GSMessageBoxOk(UnicodeString(L"Oops"), UnicodeString(L"Unable to join group room"), NULL);
  813. }
  814. // Update buddy location
  815. if (TheGameSpyChat->getUsingProfile())
  816. {
  817. if (TheGameSpyChat->getCurrentGroupRoomID())
  818. {
  819. AsciiString s;
  820. s.format("c&cgenerals://0.0.0.0:0/%d", TheGameSpyChat->getCurrentGroupRoomID());
  821. gpSetStatus(TheGPConnection, GP_CHATTING, "Chatting", s.str());
  822. }
  823. else
  824. {
  825. gpSetStatus(TheGPConnection, GP_ONLINE, "Online", "");
  826. }
  827. }
  828. }
  829. break;
  830. case StagingRoom:
  831. {
  832. ((GameSpyChat *)TheGameSpyChat)->finishJoiningStagingRoom();
  833. if (success)
  834. {
  835. DEBUG_LOG(("JoinRoomCallback - Joined staging room\n"));
  836. GServer server = (GServer)param;
  837. // leave any chat channels
  838. TheGameSpyChat->leaveRoom(GroupRoom);
  839. TheGameSpyChat->setCurrentGroupRoomID(0);
  840. // set up game info
  841. TheGameSpyGame->enterGame();
  842. TheGameSpyGame->setServer(server);
  843. GameSlot *slot = TheGameSpyGame->getSlot(0);
  844. AsciiString options, hostName;
  845. hostName = ServerGetPlayerStringValue(server, 0, "player", "<Empty>");
  846. UnicodeString uHostName;
  847. uHostName.translate(hostName.str() + 1); // go past the 'H'
  848. slot->setState(SLOT_PLAYER, uHostName);
  849. UnsignedInt localIP = peerGetLocalIP(TheGameSpyChat->getPeer());
  850. GetLocalChatConnectionAddress("peerchat.gamespy.com", 6667, localIP);
  851. localIP = ntohl(localIP); // The IP returned from GetLocalChatConnectionAddress is in network byte order.
  852. options.format("IP=%d", localIP);
  853. peerUTMPlayer(TheGameSpyChat->getPeer(), hostName.str(), "REQ/", options.str(), PEERFalse);
  854. options.format("NAT=%d", TheFirewallHelper->getFirewallBehavior());
  855. peerUTMPlayer(TheGameSpyChat->getPeer(), hostName.str(), "REQ/", options.str(), PEERFalse);
  856. // refresh the map cache
  857. TheMapCache->updateCache();
  858. // switch screens
  859. TheShell->pop();
  860. TheShell->push("Menus/GameSpyGameOptionsMenu.wnd");
  861. }
  862. else
  863. {
  864. // let the user know
  865. GSMessageBoxOk(UnicodeString(L"Oops"), UnicodeString(L"Unable to join game"), NULL);
  866. DEBUG_LOG(("JoinRoomCallback - Failed to join staging room.\n"));
  867. }
  868. // Update buddy location
  869. if (TheGameSpyChat->getUsingProfile())
  870. {
  871. if (TheGameSpyChat->getCurrentGroupRoomID())
  872. {
  873. AsciiString s;
  874. s.format("c&cgenerals://0.0.0.0:0/%d", TheGameSpyChat->getCurrentGroupRoomID());
  875. gpSetStatus(TheGPConnection, GP_CHATTING, "Chatting", s.str());
  876. }
  877. else
  878. {
  879. gpSetStatus(TheGPConnection, GP_ONLINE, "Online", "");
  880. }
  881. }
  882. break;
  883. }
  884. }
  885. //*didJoin = (success == PEERJoinSuccess || success == PEERTrue);
  886. }
  887. void createRoomCallback(PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void *param)
  888. {
  889. DEBUG_LOG(("CreateRoomCallback: success==%d, result==%d\n", success, result));
  890. if (roomType != StagingRoom)
  891. {
  892. DEBUG_CRASH(("Non-staging room create!"));
  893. return;
  894. }
  895. ((GameSpyChat *)TheGameSpyChat)->finishJoiningStagingRoom();
  896. Int oldGroupID = (Int)param;
  897. if (success)
  898. {
  899. // set up the game info
  900. UnsignedInt localIP = peerGetLocalIP(TheGameSpyChat->getPeer());
  901. DEBUG_LOG(("createRoomCallback - peerGetLocalIP returned %d.%d.%d.%d as the local IP\n",
  902. localIP >> 24, (localIP >> 16) & 0xff, (localIP >> 8) & 0xff, localIP & 0xff));
  903. // GetLocalChatConnectionAddress("peerchat.gamespy.com", 6667, localIP);
  904. // DEBUG_LOG(("createRoomCallback - GetLocalChatConnectionAddress returned %d.%d.%d.%d as the local IP\n",
  905. // localIP >> 24, (localIP >> 16) & 0xff, (localIP >> 8) & 0xff, localIP & 0xff));
  906. localIP = ntohl(localIP); // The IP returned from GetLocalChatConnectionAddress is in network byte order.
  907. TheGameSpyGame->setLocalIP(localIP);
  908. UnicodeString name;
  909. name.translate(TheGameSpyChat->getLoginName());
  910. TheGameSpyGame->enterGame();
  911. // TheGameSpyGame->setSeed(GameClientRandomValue(0, INT_MAX - 1));
  912. TheGameSpyGame->setSeed(GetTickCount());
  913. GameSlot newSlot;
  914. newSlot.setState(SLOT_PLAYER, name);
  915. newSlot.setIP(localIP);
  916. TheGameSpyGame->setSlot(0,newSlot);
  917. TheMapCache->updateCache();
  918. TheGameSpyGame->setMap(TheGlobalData->m_mapName);
  919. AsciiString asciiMap;
  920. asciiMap = TheGlobalData->m_mapName;
  921. asciiMap.toLower();
  922. std::map<AsciiString, MapMetaData>::iterator it = TheMapCache->find(asciiMap);
  923. if (it != TheMapCache->end())
  924. {
  925. TheGameSpyGame->getSlot(0)->setMapAvailability(true);
  926. TheGameSpyGame->setMapCRC( it->second.m_CRC );
  927. TheGameSpyGame->setMapSize( it->second.m_filesize );
  928. TheGameSpyGame->adjustSlotsForMap(); // BGC- adjust the slots for the new map.
  929. }
  930. // change to the proper screen
  931. TheShell->pop();
  932. TheShell->push("Menus/GameSpyGameOptionsMenu.wnd");
  933. }
  934. else
  935. {
  936. // join the lobby again
  937. TheGameSpyChat->joinGroupRoom(oldGroupID);
  938. GSMessageBoxOk(UnicodeString(L"Oops"), UnicodeString(L"Unable to create game"), NULL);
  939. }
  940. // Update buddy location
  941. if (TheGameSpyChat->getUsingProfile())
  942. {
  943. if (TheGameSpyChat->getCurrentGroupRoomID())
  944. {
  945. AsciiString s;
  946. s.format("c&cgenerals://0.0.0.0:0/%d", TheGameSpyChat->getCurrentGroupRoomID());
  947. gpSetStatus(TheGPConnection, GP_CHATTING, "Chatting", s.str());
  948. }
  949. else
  950. {
  951. gpSetStatus(TheGPConnection, GP_ONLINE, "Online", "");
  952. }
  953. }
  954. }
  955. // Gets called once for each group room when listing group rooms.
  956. // After this has been called for each group room, it will be
  957. // called one more time with groupID==0 and name==NULL.
  958. /////////////////////////////////////////////////////////////////
  959. void ListGroupRoomsCallback(PEER peer, PEERBool success,
  960. int groupID, GServer server,
  961. const char * name, int numWaiting,
  962. int maxWaiting, int numGames,
  963. int numPlaying, void * param)
  964. {
  965. DEBUG_LOG(("ListGroupRoomsCallback\n"));
  966. if (success)
  967. {
  968. if (groupID)
  969. {
  970. GroupRoomMap *grMap = TheGameSpyChat->getGroupRooms();
  971. (*grMap)[groupID].m_name = name;
  972. (*grMap)[groupID].m_numWaiting = numWaiting;
  973. (*grMap)[groupID].m_maxWaiting = maxWaiting;
  974. (*grMap)[groupID].m_numGames = numGames;
  975. (*grMap)[groupID].m_numPlaying = numPlaying;
  976. (*grMap)[groupID].m_groupID = groupID;
  977. }
  978. else
  979. {
  980. // we've got the complete list.
  981. UpdateGroupRoomList();
  982. }
  983. }
  984. }
  985. // Called when peerConnect completes.
  986. static void connectCallback(PEER peer, PEERBool success, void * param)
  987. {
  988. ((GameSpyChat *)TheGameSpyChat)->_connectCallback(peer, success, param);
  989. }
  990. static void nickErrorCallback(PEER peer, int type, const char * nick, void * param)
  991. {
  992. ((GameSpyChat *)TheGameSpyChat)->_nickErrorCallback(peer, type, nick, param);
  993. }
  994. static void GPConnectCallback(GPConnection * pconnection, GPConnectResponseArg * arg, void * param)
  995. {
  996. ((GameSpyChat *)TheGameSpyChat)->_GPConnectCallback(pconnection, arg, param);
  997. }
  998. static void GPReconnectCallback(GPConnection * pconnection, GPConnectResponseArg * arg, void * param)
  999. {
  1000. ((GameSpyChat *)TheGameSpyChat)->_GPReconnectCallback(pconnection, arg, param);
  1001. }
  1002. void GameSpyChat::_connectCallback(PEER peer, PEERBool success, void * param)
  1003. {
  1004. m_loginTimeout = 0;
  1005. if (!success) {
  1006. GSMessageBoxOk(UnicodeString(L"Error connecting"), UnicodeString(L"Failed to connect"), NULL);
  1007. DEBUG_LOG(("GameSpyChat::_connectCallback - failed to connect.\n"));
  1008. }
  1009. if(!success)
  1010. {
  1011. peerShutdown(m_peer);
  1012. m_peer = NULL;
  1013. gpDisconnect(TheGPConnection);
  1014. gpDestroy(TheGPConnection);
  1015. // Enable controls again
  1016. //EnableLoginControls(TRUE);
  1017. return;
  1018. }
  1019. DEBUG_LOG(("Connected as profile %d (%s)\n", m_profileID, m_loginName.str()));
  1020. TheGameSpyGame = NEW GameSpyGameInfo;
  1021. // Enable controls again
  1022. //EnableLoginControls(TRUE);
  1023. // the readFromServer() call will set the screen
  1024. if (m_profileID)
  1025. {
  1026. TheGameSpyPlayerInfo->readFromServer();
  1027. }
  1028. TheScriptEngine->signalUIInteract("GameSpyLogin");
  1029. TheShell->popImmediate();
  1030. TheShell->push("Menus/WOLWelcomeMenu.wnd");
  1031. clearGroupRoomList();
  1032. peerListGroupRooms(m_peer, ListGroupRoomsCallback, NULL, PEERFalse);
  1033. }
  1034. // Called if there's an error with the nick.
  1035. void GameSpyChat::_nickErrorCallback(PEER peer, int type, const char * nick, void * param)
  1036. {
  1037. // Let the user know.
  1038. /////////////////////
  1039. if(type == PEER_IN_USE)
  1040. {
  1041. AsciiString nickStr = nick;
  1042. AsciiString origName, appendedVal;
  1043. nickStr.nextToken(&origName, "{}");
  1044. nickStr.nextToken(&appendedVal, "{}");
  1045. Int intVal = 1;
  1046. if (!appendedVal.isEmpty())
  1047. {
  1048. intVal = atoi(appendedVal.str()) + 1;
  1049. }
  1050. DEBUG_LOG(("Nickname taken: origName=%s, tries=%d\n", origName.str(), intVal));
  1051. if (intVal < 10)
  1052. {
  1053. nickStr.format("%s{%d}", origName.str(), intVal);
  1054. // Retry the connect with a similar nick.
  1055. DEBUG_LOG(("GameSpyChat::_nickErrorCallback - nick was taken, setting to %s\n", nickStr.str()));
  1056. m_loginName = nickStr;
  1057. peerRetryWithNick(peer, nickStr.str());
  1058. }
  1059. else
  1060. {
  1061. GSMessageBoxOk(UnicodeString(L"Error connecting"), UnicodeString(L"That nickname is already taken; please choose another one."), NULL);
  1062. // Cancel the connect.
  1063. peerRetryWithNick(peer, NULL);
  1064. // Enable controls again
  1065. //EnableLoginControls(TRUE);
  1066. m_loginTimeout = 0;
  1067. }
  1068. }
  1069. else
  1070. {
  1071. GSMessageBoxOk(UnicodeString(L"Error connecting"), UnicodeString(L"That nickname contains at least 1 invalid character, please choose another one."), NULL);
  1072. // Cancel the connect.
  1073. peerRetryWithNick(peer, NULL);
  1074. // Enable controls again
  1075. //EnableLoginControls(TRUE);
  1076. m_loginTimeout = 0;
  1077. }
  1078. }
  1079. void GameSpyChat::_GPConnectCallback(GPConnection * pconnection, GPConnectResponseArg * arg, void * param)
  1080. {
  1081. DEBUG_LOG(("GPConnectCallback:\n"));
  1082. GPResult *res = (GPResult *)param;
  1083. *res = arg->result;
  1084. setProfileID(arg->profile);
  1085. if (*res != GP_NO_ERROR)
  1086. {
  1087. // couldn't connect. bummer.
  1088. GSMessageBoxOk(UnicodeString(L"Error connecting"), UnicodeString(L"Error connecting to buddy server"), NULL);
  1089. gpDisconnect(TheGPConnection);
  1090. gpDestroy(TheGPConnection);
  1091. m_loginTimeout = 0;
  1092. return;
  1093. }
  1094. // Connect to chat.
  1095. ///////////////////
  1096. peerConnect(m_peer, m_loginName.str(), m_profileID, nickErrorCallback, connectCallback, NULL, PEERFalse);
  1097. }
  1098. static Bool inGPReconnect = false;
  1099. void GameSpyChat::_GPReconnectCallback(GPConnection * pconnection, GPConnectResponseArg * arg, void * param)
  1100. {
  1101. inGPReconnect = false;
  1102. DEBUG_LOG(("GPConnectCallback:\n"));
  1103. setProfileID(arg->profile);
  1104. if (arg->result != GP_NO_ERROR)
  1105. {
  1106. // couldn't connect. bummer.
  1107. GSMessageBoxOk(UnicodeString(L"Error connecting"), UnicodeString(L"Error connecting to buddy server"), NULL);
  1108. gpDisconnect(TheGPConnection);
  1109. gpDestroy(TheGPConnection);
  1110. return;
  1111. }
  1112. else
  1113. {
  1114. // yay! we're back in!
  1115. GSMessageBoxOk(UnicodeString(L"Connected!"), UnicodeString(L"Reonnected to buddy server"), NULL);
  1116. }
  1117. }
  1118. void GameSpyChat::loginProfile(AsciiString loginName, AsciiString password, AsciiString email)
  1119. {
  1120. // Connect to GP.
  1121. ///////////////////
  1122. m_profileID = 0;
  1123. gpInitialize(TheGPConnection, 0);
  1124. gpSetCallback(TheGPConnection, GP_ERROR, (GPCallback)GPErrorCallback, NULL);
  1125. gpSetCallback(TheGPConnection, GP_RECV_BUDDY_REQUEST, (GPCallback)GPRecvBuddyRequestCallback, NULL);
  1126. gpSetCallback(TheGPConnection, GP_RECV_BUDDY_MESSAGE, (GPCallback)GPRecvBuddyMessageCallback, NULL);
  1127. gpSetCallback(TheGPConnection, GP_RECV_BUDDY_STATUS, (GPCallback)GPRecvBuddyStatusCallback, NULL);
  1128. GPResult res = GP_PARAMETER_ERROR;
  1129. m_loginName = loginName;
  1130. DEBUG_LOG(("GameSpyChat::loginProfile - m_loginName set to %s\n", m_loginName.str()));
  1131. m_password = password;
  1132. m_email = email;
  1133. gpConnect(TheGPConnection, loginName.str(), email.str(), password.str(), GP_FIREWALL, GP_NON_BLOCKING, (GPCallback)GPConnectCallback, &res);
  1134. /*
  1135. if (res != GP_NO_ERROR)
  1136. {
  1137. // couldn't connect. bummer.
  1138. GSMessageBoxOk(UnicodeString(L"Error connecting"), UnicodeString(L"Error connecting to buddy server"), NULL);
  1139. gpDisconnect(TheGPConnection);
  1140. gpDestroy(TheGPConnection);
  1141. loginTimeout = 0;
  1142. return;
  1143. }
  1144. // Connect to chat.
  1145. ///////////////////
  1146. GameSpyLocalNickname = loginName;
  1147. peerConnect(TheGameSpyChat->getPeer(), loginName.str(), GameSpyLocalProfile, nickErrorCallback, connectCallback, NULL, PEERFalse);
  1148. */
  1149. }
  1150. void GameSpyChat::reconnectProfile( void )
  1151. {
  1152. if (inGPReconnect)
  1153. return;
  1154. inGPReconnect = true;
  1155. gpInitialize(TheGPConnection, 0);
  1156. gpSetCallback(TheGPConnection, GP_ERROR, (GPCallback)GPErrorCallback, NULL);
  1157. gpSetCallback(TheGPConnection, GP_RECV_BUDDY_REQUEST, (GPCallback)GPRecvBuddyRequestCallback, NULL);
  1158. gpSetCallback(TheGPConnection, GP_RECV_BUDDY_MESSAGE, (GPCallback)GPRecvBuddyMessageCallback, NULL);
  1159. gpSetCallback(TheGPConnection, GP_RECV_BUDDY_STATUS, (GPCallback)GPRecvBuddyStatusCallback, NULL);
  1160. gpConnect(TheGPConnection, m_loginName.str(), m_email.str(), m_password.str(), GP_FIREWALL, GP_NON_BLOCKING, (GPCallback)GPReconnectCallback, NULL);
  1161. }
  1162. void GameSpyChat::loginQuick(AsciiString login)
  1163. {
  1164. m_profileID = 0; // no buddy stuff
  1165. // Connect to chat.
  1166. ///////////////////
  1167. m_loginName = login;
  1168. DEBUG_LOG(("GameSpyChat::loginQuick - setting login to %s\n", m_loginName));
  1169. peerConnect(m_peer, login.str(), 0, nickErrorCallback, connectCallback, NULL, PEERFalse);
  1170. }
  1171. void GameSpyChat::login(AsciiString loginName, AsciiString password, AsciiString email)
  1172. {
  1173. MutexClass::LockClass m(TheGameSpyMutex);
  1174. if ( ISMAINTHREAD )
  1175. {
  1176. thread.queueLogin(loginName, password, email);
  1177. return;
  1178. }
  1179. // Setup the callbacks.
  1180. ///////////////////////
  1181. PEERCallbacks callbacks;
  1182. memset(&callbacks, 0, sizeof(PEERCallbacks));
  1183. callbacks.disconnected = DisconnectedCallback;
  1184. callbacks.readyChanged = ReadyChangedCallback;
  1185. callbacks.roomMessage = RoomMessageCallback;
  1186. callbacks.playerMessage = PlayerMessageCallback;
  1187. callbacks.gameStarted = GameStartedCallback;
  1188. callbacks.playerJoined = PlayerJoinedCallback;
  1189. callbacks.playerLeft = PlayerLeftCallback;
  1190. callbacks.playerChangedNick = PlayerChangedNickCallback;
  1191. callbacks.ping = PingCallback;
  1192. callbacks.crossPing = CrossPingCallback;
  1193. callbacks.roomUTM = RoomUTMCallback;
  1194. callbacks.playerUTM = PlayerUTMCallback;
  1195. callbacks.GOABasic = GOABasicCallback;
  1196. callbacks.GOAInfo = GOAInfoCallback;
  1197. callbacks.GOARules = GOARulesCallback;
  1198. callbacks.GOAPlayers = GOAPlayersCallback;
  1199. //callbacks.globalKeyChanged = GlobalKeyChanged;
  1200. callbacks.param = NULL;
  1201. // Init peer.
  1202. /////////////
  1203. m_peer = peerInitialize(&callbacks);
  1204. if(!m_peer)
  1205. {
  1206. GSMessageBoxOk(UnicodeString(L"No Peer"), UnicodeString(L"No Peer"), NULL);
  1207. return;
  1208. }
  1209. // Setup which rooms to do pings and cross-pings in.
  1210. ////////////////////////////////////////////////////
  1211. PEERBool pingRooms[NumRooms];
  1212. PEERBool crossPingRooms[NumRooms];
  1213. pingRooms[TitleRoom] = PEERTrue;
  1214. pingRooms[GroupRoom] = PEERTrue;
  1215. pingRooms[StagingRoom] = PEERFalse;
  1216. crossPingRooms[TitleRoom] = PEERFalse;
  1217. crossPingRooms[GroupRoom] = PEERFalse;
  1218. crossPingRooms[StagingRoom] = PEERTrue;
  1219. // Set the title.
  1220. /////////////////
  1221. if(!peerSetTitle(m_peer, "gmtest", "HA6zkS", "gmtest", "HA6zkS", 15, pingRooms, crossPingRooms))
  1222. {
  1223. GSMessageBoxOk(UnicodeString(L"Error setting title"), UnicodeString(L"Error setting title"), NULL);
  1224. peerShutdown(m_peer);
  1225. m_peer = NULL;
  1226. return;
  1227. }
  1228. //EnableLoginControls( FALSE );
  1229. m_loginTimeout = timeGetTime() + m_loginTimeoutPeriod;
  1230. if (!loginName.isEmpty() && !email.isEmpty() && !password.isEmpty())
  1231. {
  1232. m_usingProfiles = true;
  1233. loginProfile(loginName, password, email);
  1234. }
  1235. else
  1236. {
  1237. m_usingProfiles = false;
  1238. loginQuick(loginName);
  1239. }
  1240. }