PeerThread.cpp 89 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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: PeerThread.cpp //////////////////////////////////////////////////////
  24. // GameSpy Peer (chat) thread
  25. // This thread communicates with GameSpy's chat server
  26. // and talks through a message queue with the rest of
  27. // the game.
  28. // Author: Matthew D. Campbell, June 2002
  29. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  30. #include "Common/Registry.h"
  31. #include "Common/StackDump.h"
  32. #include "Common/UserPreferences.h"
  33. #include "Common/Version.h"
  34. #include "GameNetwork/IPEnumeration.h"
  35. #include "GameNetwork/GameSpy/BuddyThread.h"
  36. #include "GameNetwork/GameSpy/PeerDefs.h"
  37. #include "GameNetwork/GameSpy/PeerThread.h"
  38. #include "GameNetwork/GameSpy/PersistentStorageThread.h"
  39. #include "GameNetwork/GameSpy/ThreadUtils.h"
  40. #include "strtok_r.h"
  41. #include "mutex.h"
  42. #include "thread.h"
  43. #include "Common/MiniLog.h"
  44. #ifdef _INTERNAL
  45. // for occasional debugging...
  46. //#pragma optimize("", off)
  47. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  48. #endif
  49. // enable this for trying to track down why SBServers are losing their keyvals -MDC 2/20/2003
  50. #undef SERVER_DEBUGGING
  51. #ifdef SERVER_DEBUGGING
  52. void CheckServers(PEER peer);
  53. #endif // SERVER_DEBUGGING
  54. #ifdef DEBUG_LOGGING
  55. //#define PING_TEST
  56. static LogClass s_pingLog("Ping.txt");
  57. #define PING_LOG(x) s_pingLog.log x
  58. #else // DEBUG_LOGGING
  59. #define PING_LOG(x) {}
  60. #endif // DEBUG_LOGGING
  61. #ifdef DEBUG_LOGGING
  62. static LogClass s_stateChangedLog("StateChanged.txt");
  63. #define STATECHANGED_LOG(x) s_stateChangedLog.log x
  64. #else // DEBUG_LOGGING
  65. #define STATECHANGED_LOG(x) {}
  66. #endif // DEBUG_LOGGING
  67. // we should always be using broadcast keys from now on. Remove the old code sometime when
  68. // we're not in a rush, ok?
  69. // -MDC 2/14/2003
  70. #define USE_BROADCAST_KEYS
  71. #ifdef _INTERNAL
  72. // for occasional debugging...
  73. //#pragma optimize("", off)
  74. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  75. #endif
  76. int isThreadHosting = 0;
  77. static UnsignedInt s_lastStateChangedHeartbeat = 0;
  78. static Bool s_wantStateChangedHeartbeat = FALSE;
  79. static UnsignedInt s_heartbeatInterval = 10000;
  80. static SOCKET qr2Sock = INVALID_SOCKET;
  81. enum
  82. {
  83. EXECRC_KEY = NUM_RESERVED_KEYS + 1,
  84. INICRC_KEY,
  85. PW_KEY,
  86. OBS_KEY,
  87. USE_STATS_KEY,
  88. LADIP_KEY,
  89. LADPORT_KEY,
  90. PINGSTR_KEY,
  91. NUMPLAYER_KEY,
  92. MAXPLAYER_KEY,
  93. NUMOBS_KEY,
  94. NAME__KEY,
  95. FACTION__KEY,
  96. COLOR__KEY,
  97. WINS__KEY,
  98. LOSSES__KEY
  99. };
  100. #define EXECRC_STR "exeCRC"
  101. #define INICRC_STR "iniCRC"
  102. #define PW_STR "pw"
  103. #define OBS_STR "obs"
  104. #define USE_STATS_STR "stat"
  105. #define LADIP_STR "ladIP"
  106. #define LADPORT_STR "ladPort"
  107. #define PINGSTR_STR "pings"
  108. #define NUMPLAYER_STR "numRealPlayers"
  109. #define MAXPLAYER_STR "maxRealPlayers"
  110. #define NUMOBS_STR "numObservers"
  111. #define NAME__STR "name"
  112. #define FACTION__STR "faction"
  113. #define COLOR__STR "color"
  114. #define WINS__STR "wins"
  115. #define LOSSES__STR "losses"
  116. //-------------------------------------------------------------------------
  117. typedef std::queue<PeerRequest> RequestQueue;
  118. typedef std::queue<PeerResponse> ResponseQueue;
  119. class PeerThreadClass;
  120. class GameSpyPeerMessageQueue : public GameSpyPeerMessageQueueInterface
  121. {
  122. public:
  123. virtual ~GameSpyPeerMessageQueue();
  124. GameSpyPeerMessageQueue();
  125. virtual void startThread( void );
  126. virtual void endThread( void );
  127. virtual Bool isThreadRunning( void );
  128. virtual Bool isConnected( void );
  129. virtual Bool isConnecting( void );
  130. virtual void addRequest( const PeerRequest& req );
  131. virtual Bool getRequest( PeerRequest& req );
  132. virtual void addResponse( const PeerResponse& resp );
  133. virtual Bool getResponse( PeerResponse& resp );
  134. virtual SerialAuthResult getSerialAuthResult( void ) { return m_serialAuth; }
  135. void setSerialAuthResult( SerialAuthResult result ) { m_serialAuth = result; }
  136. PeerThreadClass* getThread( void );
  137. private:
  138. MutexClass m_requestMutex;
  139. MutexClass m_responseMutex;
  140. RequestQueue m_requests;
  141. ResponseQueue m_responses;
  142. PeerThreadClass *m_thread;
  143. SerialAuthResult m_serialAuth;
  144. };
  145. GameSpyPeerMessageQueueInterface* GameSpyPeerMessageQueueInterface::createNewMessageQueue( void )
  146. {
  147. return NEW GameSpyPeerMessageQueue;
  148. }
  149. GameSpyPeerMessageQueueInterface *TheGameSpyPeerMessageQueue;
  150. #define MESSAGE_QUEUE ((GameSpyPeerMessageQueue *)TheGameSpyPeerMessageQueue)
  151. //-------------------------------------------------------------------------
  152. class PeerThreadClass : public ThreadClass
  153. {
  154. public:
  155. PeerThreadClass() : ThreadClass()
  156. {
  157. //Added By Sadullah Nader
  158. //Initializations inserted
  159. m_roomJoined = m_allowObservers = m_hasPassword = FALSE;
  160. m_useStats = TRUE;
  161. m_exeCRC = m_iniCRC = 0;
  162. m_gameVersion = 0;
  163. m_ladderPort = 0;
  164. m_localRoomID = 0;
  165. m_maxPlayers = 0;
  166. m_numObservers = 0;
  167. m_maxPlayers = 0;
  168. m_qmGroupRoom = 0;
  169. m_sawEndOfEnumPlayers = m_sawMatchbot = FALSE;
  170. m_sawCompleteGameList = FALSE;
  171. //
  172. m_isConnecting = m_isConnected = false;
  173. m_groupRoomID = m_profileID = 0;
  174. m_nextStagingServer = 1; m_stagingServers.clear();
  175. m_pingStr = ""; m_mapName = ""; m_ladderIP = ""; m_isHosting = false;
  176. for (Int i=0; i<MAX_SLOTS; ++i)
  177. {
  178. m_playerNames[i] = "";
  179. //Added by Sadullah Nader
  180. //Initializations
  181. m_playerColors[i] = 0;
  182. m_playerFactions[i] = 0;
  183. m_playerLosses[i] = 0;
  184. m_playerProfileID[i] = 0;
  185. m_playerWins[i] = 0;
  186. //
  187. }
  188. }
  189. void Thread_Function();
  190. void markAsDisconnected( void ) { m_isConnecting = m_isConnected = false; }
  191. void connectCallback( PEER peer, PEERBool success );
  192. void nickErrorCallback( PEER peer, Int type, const char *nick );
  193. Bool isConnecting( void ) { return m_isConnecting; }
  194. Bool isConnected( void ) { return m_isConnected; }
  195. Int addServerToMap( SBServer server );
  196. Int removeServerFromMap( SBServer server );
  197. void clearServers( void );
  198. SBServer findServerByID( Int id );
  199. Int findServer( SBServer server );
  200. // get info about the game we are hosting
  201. Bool isHosting( void ) { return m_isHosting; }
  202. void stopHostingAlready(PEER peer);
  203. Bool hasPassword( void ) { return m_hasPassword; }
  204. Bool allowObservers( void ) { return m_allowObservers; }
  205. Bool useStats(void) const { return m_useStats; }
  206. std::string getMapName( void ) { return m_mapName; }
  207. UnsignedInt exeCRC( void ) { return m_exeCRC; }
  208. UnsignedInt iniCRC( void ) { return m_iniCRC; }
  209. UnsignedInt gameVersion( void ) { return m_gameVersion; }
  210. std::wstring getLocalStagingServerName( void ) { return m_localStagingServerName; }
  211. Int getLocalRoomID( void ) { return m_localRoomID; }
  212. std::string ladderIP( void ) { return m_ladderIP; }
  213. UnsignedShort ladderPort( void ) { return m_ladderPort; }
  214. std::string pingStr( void ) { return m_pingStr; }
  215. std::string getPlayerName(Int idx) { return m_playerNames[idx]; }
  216. Int getPlayerWins(Int idx) { return m_playerWins[idx]; }
  217. Int getPlayerLosses(Int idx) { return m_playerLosses[idx]; }
  218. Int getPlayerProfileID(Int idx) { return m_playerProfileID[idx]; }
  219. Int getPlayerFaction(Int idx) { return m_playerFactions[idx]; }
  220. Int getPlayerColor(Int idx) { return m_playerColors[idx]; }
  221. Int getNumPlayers(void) { return m_numPlayers; }
  222. Int getMaxPlayers(void) { return m_maxPlayers; }
  223. Int getNumObservers(void) { return m_numObservers; }
  224. void roomJoined( Bool val ) { m_roomJoined = val; }
  225. void setQMGroupRoom( Int groupID ) { m_qmGroupRoom = groupID; }
  226. void sawEndOfEnumPlayers( void ) { m_sawEndOfEnumPlayers = true; }
  227. void sawMatchbot( std::string bot ) { m_sawMatchbot = true; m_matchbotName = bot; }
  228. QMStatus getQMStatus( void ) { return m_qmStatus; }
  229. void handleQMMatch(PEER peer, Int mapIndex, Int seed, char *playerName[MAX_SLOTS], char *playerIP[MAX_SLOTS], char *playerSide[MAX_SLOTS], char *playerColor[MAX_SLOTS], char *playerNAT[MAX_SLOTS]);
  230. std::string getQMBotName( void ) { return m_matchbotName; }
  231. Int getQMGroupRoom( void ) { return m_qmGroupRoom; }
  232. Int getQMLadder( void ) { return m_qmInfo.QM.ladderID; }
  233. Int getCurrentGroupRoom(void) { return m_groupRoomID; }
  234. #ifdef USE_BROADCAST_KEYS
  235. void pushStatsToRoom(PEER peer);
  236. void getStatsFromRoom(PEER peer, RoomType roomType);
  237. void trackStatsForPlayer(RoomType roomType, const char *nick, const char *key, const char *val);
  238. int lookupStatForPlayer(RoomType roomType, const char *nick, const char *key);
  239. void clearPlayerStats(RoomType roomType);
  240. #endif // USE_BROADCAST_KEYS
  241. void setSawCompleteGameList(Bool val) { m_sawCompleteGameList = val; }
  242. Bool getSawCompleteGameList() { return m_sawCompleteGameList; }
  243. private:
  244. Bool m_isConnecting;
  245. Bool m_isConnected;
  246. std::string m_loginName, m_originalName, m_password, m_email;
  247. Int m_profileID;
  248. Int m_groupRoomID;
  249. Bool m_sawCompleteGameList;
  250. #ifdef USE_BROADCAST_KEYS
  251. enum { NumKeys = 6, ValBufSize = 20 };
  252. static const char *s_keys[NumKeys];
  253. static char s_valueBuffers[NumKeys][ValBufSize];
  254. static const char *s_values[NumKeys];
  255. typedef std::map<std::string, int> PlayerStatMap;
  256. PlayerStatMap m_groupRoomStats;
  257. PlayerStatMap m_stagingRoomStats;
  258. std::string packStatKey(const char *nick, const char *key);
  259. #endif // USE_BROADCAST_KEYS
  260. // game-hosting info for GOA callbacks
  261. Bool m_isHosting;
  262. Bool m_hasPassword;
  263. std::string m_mapName;
  264. std::string m_playerNames[MAX_SLOTS];
  265. UnsignedInt m_exeCRC;
  266. UnsignedInt m_iniCRC;
  267. UnsignedInt m_gameVersion;
  268. Bool m_allowObservers;
  269. Bool m_useStats;
  270. std::string m_pingStr;
  271. std::string m_ladderIP;
  272. UnsignedShort m_ladderPort;
  273. Int m_playerWins[MAX_SLOTS];
  274. Int m_playerLosses[MAX_SLOTS];
  275. Int m_playerProfileID[MAX_SLOTS];
  276. Int m_playerColors[MAX_SLOTS];
  277. Int m_playerFactions[MAX_SLOTS];
  278. Int m_numPlayers;
  279. Int m_maxPlayers;
  280. Int m_numObservers;
  281. Int m_nextStagingServer;
  282. std::map<Int, SBServer> m_stagingServers;
  283. std::wstring m_localStagingServerName;
  284. Int m_localRoomID;
  285. void doQuickMatch( PEER peer );
  286. QMStatus m_qmStatus;
  287. PeerRequest m_qmInfo;
  288. Bool m_roomJoined;
  289. Int m_qmGroupRoom;
  290. Bool m_sawEndOfEnumPlayers;
  291. Bool m_sawMatchbot;
  292. std::string m_matchbotName;
  293. };
  294. #ifdef USE_BROADCAST_KEYS
  295. const char* PeerThreadClass::s_keys[6] = { "b_locale", "b_wins", "b_losses", "b_points", "b_side", "b_pre" };
  296. char PeerThreadClass::s_valueBuffers[6][20] = { "", "", "", "", "", "" };
  297. const char* PeerThreadClass::s_values[6] = { s_valueBuffers[0], s_valueBuffers[1], s_valueBuffers[2],
  298. s_valueBuffers[3], s_valueBuffers[4], s_valueBuffers[5]};
  299. void PeerThreadClass::trackStatsForPlayer(RoomType roomType, const char *nick, const char *key, const char *val)
  300. {
  301. switch (roomType)
  302. {
  303. case GroupRoom:
  304. m_groupRoomStats[packStatKey(nick, key)] = atoi(val);
  305. break;
  306. case StagingRoom:
  307. m_stagingRoomStats[packStatKey(nick, key)] = atoi(val);
  308. break;
  309. }
  310. }
  311. std::string PeerThreadClass::packStatKey(const char *nick, const char *key)
  312. {
  313. std::string s = nick;
  314. s.append(key);
  315. return s;
  316. }
  317. int PeerThreadClass::lookupStatForPlayer(RoomType roomType, const char *nick, const char *key)
  318. {
  319. std::string fullKey = packStatKey(nick, key);
  320. PlayerStatMap::const_iterator it;
  321. switch (roomType)
  322. {
  323. case GroupRoom:
  324. it = m_groupRoomStats.find(fullKey);
  325. if (it != m_groupRoomStats.end())
  326. return it->second;
  327. break;
  328. case StagingRoom:
  329. it = m_stagingRoomStats.find(fullKey);
  330. if (it != m_stagingRoomStats.end())
  331. return it->second;
  332. break;
  333. }
  334. return 0;
  335. }
  336. void PeerThreadClass::clearPlayerStats(RoomType roomType)
  337. {
  338. switch (roomType)
  339. {
  340. case GroupRoom:
  341. m_groupRoomStats.clear();
  342. break;
  343. case StagingRoom:
  344. m_stagingRoomStats.clear();
  345. break;
  346. }
  347. }
  348. void PeerThreadClass::pushStatsToRoom(PEER peer)
  349. {
  350. DEBUG_LOG(("PeerThreadClass::pushStatsToRoom(): stats are %s=%s,%s=%s,%s=%s,%s=%s,%s=%s,%s=%s\n",
  351. s_keys[0], s_values[0],
  352. s_keys[1], s_values[1],
  353. s_keys[2], s_values[2],
  354. s_keys[3], s_values[3],
  355. s_keys[4], s_values[4],
  356. s_keys[5], s_values[5]));
  357. peerSetRoomKeys(peer, GroupRoom, m_loginName.c_str(), 6, s_keys, s_values);
  358. peerSetRoomKeys(peer, StagingRoom, m_loginName.c_str(), 6, s_keys, s_values);
  359. }
  360. void getRoomKeysCallback(PEER peer, PEERBool success, RoomType roomType, const char *nick, int num, char **keys, char **values, void *param);
  361. void PeerThreadClass::getStatsFromRoom(PEER peer, RoomType roomType)
  362. {
  363. peerGetRoomKeys(peer, GroupRoom, "*", NumKeys, s_keys, getRoomKeysCallback, this, PEERFalse);
  364. }
  365. #endif // USE_BROADCAST_KEYS
  366. Int PeerThreadClass::addServerToMap( SBServer server )
  367. {
  368. Int val = m_nextStagingServer++;
  369. m_stagingServers[val] = server;
  370. return val;
  371. }
  372. Int PeerThreadClass::removeServerFromMap( SBServer server )
  373. {
  374. for (std::map<Int, SBServer>::iterator it = m_stagingServers.begin(); it != m_stagingServers.end(); ++it)
  375. {
  376. if (it->second == server)
  377. {
  378. Int val = it->first;
  379. m_stagingServers.erase(it);
  380. return val;
  381. }
  382. }
  383. return 0;
  384. }
  385. void PeerThreadClass::clearServers( void )
  386. {
  387. m_stagingServers.clear();
  388. }
  389. SBServer PeerThreadClass::findServerByID( Int id )
  390. {
  391. std::map<Int, SBServer>::iterator it = m_stagingServers.find(id);
  392. if (it != m_stagingServers.end())
  393. {
  394. SBServer server = it->second;
  395. if (server && !server->keyvals)
  396. {
  397. DEBUG_CRASH(("Referencing a missing server!"));
  398. return 0;
  399. }
  400. return it->second;
  401. }
  402. return 0;
  403. }
  404. Int PeerThreadClass::findServer( SBServer server )
  405. {
  406. char tmp[10] = "";
  407. const char *newName = SBServerGetStringValue(server, "gamename", tmp);
  408. UnsignedInt newPrivateIP = SBServerGetPrivateInetAddress(server);
  409. UnsignedShort newPrivatePort = SBServerGetPrivateQueryPort(server);
  410. UnsignedInt newPublicIP = SBServerGetPublicInetAddress(server);
  411. SBServer serverToRemove = NULL;
  412. for (std::map<Int, SBServer>::iterator it = m_stagingServers.begin(); it != m_stagingServers.end(); ++it)
  413. {
  414. if (it->second == server)
  415. {
  416. return it->first;
  417. }
  418. else
  419. {
  420. const char *oldName = SBServerGetStringValue(it->second, "gamename", tmp);
  421. UnsignedInt oldPrivateIP = SBServerGetPrivateInetAddress(it->second);
  422. UnsignedShort oldPrivatePort = SBServerGetPrivateQueryPort(it->second);
  423. UnsignedInt oldPublicIP = SBServerGetPublicInetAddress(it->second);
  424. if (!strcmp(oldName, newName) &&
  425. oldPrivateIP == newPrivateIP &&
  426. oldPublicIP == newPublicIP &&
  427. oldPrivatePort == newPrivatePort)
  428. {
  429. serverToRemove = it->second;
  430. }
  431. }
  432. }
  433. if (serverToRemove)
  434. {
  435. // this is the same as another game - it has just migrated to another port. Remove the old and replace it.
  436. PeerResponse resp;
  437. resp.peerResponseType = PeerResponse::PEERRESPONSE_STAGINGROOM;
  438. resp.stagingRoom.id = removeServerFromMap( serverToRemove );
  439. resp.stagingRoom.action = PEER_REMOVE;
  440. resp.stagingRoom.isStaging = TRUE;
  441. resp.stagingRoom.percentComplete = -1;
  442. TheGameSpyPeerMessageQueue->addResponse(resp);
  443. }
  444. return addServerToMap(server);
  445. }
  446. static enum CallbackType
  447. {
  448. CALLBACK_CONNECT,
  449. CALLBACK_ERROR,
  450. CALLBACK_RECVMESSAGE,
  451. CALLBACK_RECVREQUEST,
  452. CALLBACK_RECVSTATUS,
  453. CALLBACK_MAX
  454. };
  455. void connectCallbackWrapper( PEER peer, PEERBool success, void *param )
  456. {
  457. #ifdef SERVER_DEBUGGING
  458. DEBUG_LOG(("In connectCallbackWrapper()\n"));
  459. CheckServers(peer);
  460. #endif // SERVER_DEBUGGING
  461. if (param != NULL)
  462. {
  463. ((PeerThreadClass *)param)->connectCallback( peer, success );
  464. }
  465. }
  466. void nickErrorCallbackWrapper( PEER peer, Int type, const char *nick, void *param )
  467. {
  468. if (param != NULL)
  469. {
  470. ((PeerThreadClass *)param)->nickErrorCallback( peer, type, nick );
  471. }
  472. }
  473. static void joinRoomCallback(PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void *param);
  474. //-------------------------------------------------------------------------
  475. GameSpyPeerMessageQueue::GameSpyPeerMessageQueue()
  476. {
  477. m_thread = NULL;
  478. m_serialAuth = SERIAL_OK;
  479. }
  480. GameSpyPeerMessageQueue::~GameSpyPeerMessageQueue()
  481. {
  482. endThread();
  483. }
  484. void GameSpyPeerMessageQueue::startThread( void )
  485. {
  486. if (!m_thread)
  487. {
  488. m_thread = NEW PeerThreadClass;
  489. m_thread->Execute();
  490. }
  491. else
  492. {
  493. if (!m_thread->Is_Running())
  494. {
  495. m_thread->Execute();
  496. }
  497. }
  498. }
  499. void GameSpyPeerMessageQueue::endThread( void )
  500. {
  501. if (m_thread)
  502. delete m_thread;
  503. m_thread = NULL;
  504. }
  505. Bool GameSpyPeerMessageQueue::isThreadRunning( void )
  506. {
  507. return (m_thread) ? m_thread->Is_Running() : false;
  508. }
  509. Bool GameSpyPeerMessageQueue::isConnected( void )
  510. {
  511. return (m_thread) ? m_thread->isConnected() : false;
  512. }
  513. Bool GameSpyPeerMessageQueue::isConnecting( void )
  514. {
  515. return (m_thread) ? m_thread->isConnecting() : false;
  516. }
  517. void GameSpyPeerMessageQueue::addRequest( const PeerRequest& req )
  518. {
  519. MutexClass::LockClass m(m_requestMutex);
  520. if (m.Failed())
  521. return;
  522. m_requests.push(req);
  523. }
  524. //PeerRequest GameSpyPeerMessageQueue::getRequest( void )
  525. Bool GameSpyPeerMessageQueue::getRequest( PeerRequest& req )
  526. {
  527. MutexClass::LockClass m(m_requestMutex, 0);
  528. if (m.Failed())
  529. return false;
  530. if (m_requests.empty())
  531. return false;
  532. req = m_requests.front();
  533. m_requests.pop();
  534. return true;
  535. }
  536. void GameSpyPeerMessageQueue::addResponse( const PeerResponse& resp )
  537. {
  538. if (resp.nick == "(END)")
  539. return;
  540. MutexClass::LockClass m(m_responseMutex);
  541. if (m.Failed())
  542. return;
  543. m_responses.push(resp);
  544. }
  545. //PeerResponse GameSpyPeerMessageQueue::getResponse( void )
  546. Bool GameSpyPeerMessageQueue::getResponse( PeerResponse& resp )
  547. {
  548. MutexClass::LockClass m(m_responseMutex, 0);
  549. if (m.Failed())
  550. return false;
  551. if (m_responses.empty())
  552. return false;
  553. resp = m_responses.front();
  554. m_responses.pop();
  555. return true;
  556. }
  557. PeerThreadClass* GameSpyPeerMessageQueue::getThread( void )
  558. {
  559. return m_thread;
  560. }
  561. //-------------------------------------------------------------------------
  562. static void disconnectedCallback(PEER peer, const char * reason, void * param);
  563. static void roomMessageCallback(PEER peer, RoomType roomType, const char * nick, const char * message, MessageType messageType, void * param);
  564. static void playerMessageCallback(PEER peer, const char * nick, const char * message, MessageType messageType, void * param);
  565. static void playerJoinedCallback(PEER peer, RoomType roomType, const char * nick, void * param);
  566. static void playerLeftCallback(PEER peer, RoomType roomType, const char * nick, const char * reason, void * param);
  567. static void playerChangedNickCallback(PEER peer, RoomType roomType, const char * oldNick, const char * newNick, void * param);
  568. static void playerInfoCallback(PEER peer, RoomType roomType, const char * nick, unsigned int IP, int profileID, void * param);
  569. static void playerFlagsChangedCallback(PEER peer, RoomType roomType, const char * nick, int oldFlags, int newFlags, void * param);
  570. static void listingGamesCallback(PEER peer, PEERBool success, const char * name, SBServer server, PEERBool staging, int msg, Int percentListed, void * param);
  571. static void roomUTMCallback(PEER peer, RoomType roomType, const char * nick, const char * command, const char * parameters, PEERBool authenticated, void * param);
  572. static void playerUTMCallback(PEER peer, const char * nick, const char * command, const char * parameters, PEERBool authenticated, void * param);
  573. static void gameStartedCallback(PEER peer, UnsignedInt IP, const char *message, void *param);
  574. static void globalKeyChangedCallback(PEER peer, const char *nick, const char *key, const char *val, void *param);
  575. static void roomKeyChangedCallback(PEER peer, RoomType roomType, const char *nick, const char *key, const char *val, void *param);
  576. // convenience function to set buddy status
  577. static void updateBuddyStatus( GameSpyBuddyStatus status, Int groupRoom = 0, std::string gameName = "" )
  578. {
  579. if (!TheGameSpyBuddyMessageQueue)
  580. return;
  581. BuddyRequest req;
  582. req.buddyRequestType = BuddyRequest::BUDDYREQUEST_SETSTATUS;
  583. switch(status)
  584. {
  585. case BUDDY_OFFLINE:
  586. req.arg.status.status = GP_OFFLINE;
  587. strcpy(req.arg.status.statusString, "Offline");
  588. strcpy(req.arg.status.locationString, "");
  589. break;
  590. case BUDDY_ONLINE:
  591. req.arg.status.status = GP_ONLINE;
  592. strcpy(req.arg.status.statusString, "Online");
  593. strcpy(req.arg.status.locationString, "");
  594. break;
  595. case BUDDY_LOBBY:
  596. req.arg.status.status = GP_CHATTING;
  597. strcpy(req.arg.status.statusString, "Chatting");
  598. sprintf(req.arg.status.locationString, "%d", groupRoom);
  599. break;
  600. case BUDDY_STAGING:
  601. req.arg.status.status = GP_STAGING;
  602. strcpy(req.arg.status.statusString, "Staging");
  603. sprintf(req.arg.status.locationString, "%s", gameName.c_str());
  604. break;
  605. case BUDDY_LOADING:
  606. req.arg.status.status = GP_PLAYING;
  607. strcpy(req.arg.status.statusString, "Loading");
  608. sprintf(req.arg.status.locationString, "%s", gameName.c_str());
  609. break;
  610. case BUDDY_PLAYING:
  611. req.arg.status.status = GP_PLAYING;
  612. strcpy(req.arg.status.statusString, "Playing");
  613. sprintf(req.arg.status.locationString, "%s", gameName.c_str());
  614. break;
  615. case BUDDY_MATCHING:
  616. req.arg.status.status = GP_ONLINE;
  617. strcpy(req.arg.status.statusString, "Matching");
  618. strcpy(req.arg.status.locationString, "");
  619. break;
  620. }
  621. DEBUG_LOG(("updateBuddyStatus %d:%s\n", req.arg.status.status, req.arg.status.statusString));
  622. TheGameSpyBuddyMessageQueue->addRequest(req);
  623. }
  624. static void createRoomCallback(PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void *param)
  625. {
  626. Int *s = (Int *)param;
  627. if (s)
  628. *s = result;
  629. }
  630. static const char * KeyTypeToString(qr2_key_type type)
  631. {
  632. switch(type)
  633. {
  634. case key_server:
  635. return "server";
  636. case key_player:
  637. return "player";
  638. case key_team:
  639. return "team";
  640. }
  641. return "Unkown key type";
  642. }
  643. static const char * ErrorTypeToString(qr2_error_t error)
  644. {
  645. switch(error)
  646. {
  647. case e_qrnoerror:
  648. return "noerror";
  649. case e_qrwsockerror:
  650. return "wsockerror";
  651. case e_qrbinderror:
  652. return "rbinderror";
  653. case e_qrdnserror:
  654. return "dnserror";
  655. case e_qrconnerror:
  656. return "connerror";
  657. }
  658. return "Unknown error type";
  659. }
  660. static void QRServerKeyCallback
  661. (
  662. PEER peer,
  663. int key,
  664. qr2_buffer_t buffer,
  665. void * param
  666. )
  667. {
  668. //DEBUG_LOG(("QR_SERVER_KEY | %d (%s)\n", key, qr2_registered_key_list[key]));
  669. PeerThreadClass *t = (PeerThreadClass *)param;
  670. if (!t)
  671. {
  672. DEBUG_LOG(("QRServerKeyCallback: bailing because of no thread info\n"));
  673. return;
  674. }
  675. if (!t->isHosting())
  676. t->stopHostingAlready(peer);
  677. #ifdef DEBUG_LOGGING
  678. AsciiString val = "";
  679. #define ADD(x) { qr2_buffer_add(buffer, x); val = x; }
  680. #define ADDINT(x) { qr2_buffer_add_int(buffer, x); val.format("%d",x); }
  681. #else
  682. #define ADD(x) { qr2_buffer_add(buffer, x); }
  683. #define ADDINT(x) { qr2_buffer_add_int(buffer, x); }
  684. #endif
  685. switch(key)
  686. {
  687. case HOSTNAME_KEY:
  688. ADD(t->getPlayerName(0).c_str());
  689. break;
  690. case GAMEVER_KEY:
  691. ADDINT(t->gameVersion());
  692. break;
  693. case EXECRC_KEY:
  694. ADDINT(t->exeCRC());
  695. break;
  696. case INICRC_KEY:
  697. ADDINT(t->iniCRC());
  698. break;
  699. case GAMENAME_KEY:
  700. {
  701. std::string tmp = t->getPlayerName(0);
  702. tmp.append(" ");
  703. tmp.append(WideCharStringToMultiByte(t->getLocalStagingServerName().c_str()));
  704. ADD(tmp.c_str());
  705. }
  706. break;
  707. case MAPNAME_KEY:
  708. ADD(t->getMapName().c_str());
  709. break;
  710. case PW_KEY:
  711. ADDINT(t->hasPassword());
  712. break;
  713. case OBS_KEY:
  714. ADDINT(t->allowObservers());
  715. break;
  716. case USE_STATS_KEY:
  717. ADDINT(t->useStats());
  718. break;
  719. case LADIP_KEY:
  720. ADD(t->ladderIP().c_str());
  721. break;
  722. case LADPORT_KEY:
  723. ADDINT(t->ladderPort());
  724. break;
  725. case PINGSTR_KEY:
  726. ADD(t->pingStr().c_str());
  727. break;
  728. case NUMPLAYER_KEY:
  729. ADDINT(t->getNumPlayers());
  730. break;
  731. case MAXPLAYER_KEY:
  732. ADDINT(t->getMaxPlayers());
  733. break;
  734. case NUMOBS_KEY:
  735. ADDINT(t->getNumObservers());
  736. break;
  737. default:
  738. ADD("");
  739. //DEBUG_LOG(("QR_SERVER_KEY | %d (%s)\n", key, qr2_registered_key_list[key]));
  740. break;
  741. }
  742. DEBUG_LOG(("QR_SERVER_KEY | %d (%s) = [%s]\n", key, qr2_registered_key_list[key], val.str()));
  743. }
  744. static void QRPlayerKeyCallback
  745. (
  746. PEER peer,
  747. int key,
  748. int index,
  749. qr2_buffer_t buffer,
  750. void * param
  751. )
  752. {
  753. //DEBUG_LOG(("QR_PLAYER_KEY | %d | %d (%s)\n", key, index, qr2_registered_key_list[key]));
  754. PeerThreadClass *t = (PeerThreadClass *)param;
  755. if (!t)
  756. {
  757. DEBUG_LOG(("QRPlayerKeyCallback: bailing because of no thread info\n"));
  758. return;
  759. }
  760. if (!t->isHosting())
  761. t->stopHostingAlready(peer);
  762. #undef ADD
  763. #undef ADDINT
  764. #ifdef DEBUG_LOGGING
  765. AsciiString val = "";
  766. #define ADD(x) { qr2_buffer_add(buffer, x); val = x; }
  767. #define ADDINT(x) { qr2_buffer_add_int(buffer, x); val.format("%d",x); }
  768. #else
  769. #define ADD(x) { qr2_buffer_add(buffer, x); }
  770. #define ADDINT(x) { qr2_buffer_add_int(buffer, x); }
  771. #endif
  772. switch(key)
  773. {
  774. case NAME__KEY:
  775. ADD(t->getPlayerName(index).c_str());
  776. break;
  777. case WINS__KEY:
  778. ADDINT(t->getPlayerWins(index));
  779. break;
  780. case LOSSES__KEY:
  781. ADDINT(t->getPlayerLosses(index));
  782. break;
  783. case PID__KEY:
  784. ADDINT(t->getPlayerProfileID(index));
  785. break;
  786. case FACTION__KEY:
  787. ADDINT(t->getPlayerLosses(index));
  788. break;
  789. case COLOR__KEY:
  790. ADDINT(t->getPlayerLosses(index));
  791. break;
  792. default:
  793. ADD("");
  794. //DEBUG_LOG(("QR_PLAYER_KEY | %d | %d (%s)\n", key, index, qr2_registered_key_list[key]));
  795. break;
  796. }
  797. DEBUG_LOG(("QR_PLAYER_KEY | %d | %d (%s) = [%s]\n", key, index, qr2_registered_key_list[key], val.str()));
  798. }
  799. static void QRTeamKeyCallback
  800. (
  801. PEER peer,
  802. int key,
  803. int index,
  804. qr2_buffer_t buffer,
  805. void * param
  806. )
  807. {
  808. //DEBUG_LOG(("QR_TEAM_KEY | %d | %d\n", key, index));
  809. PeerThreadClass *t = (PeerThreadClass *)param;
  810. if (!t)
  811. {
  812. DEBUG_LOG(("QRTeamKeyCallback: bailing because of no thread info\n"));
  813. return;
  814. }
  815. if (!t->isHosting())
  816. t->stopHostingAlready(peer);
  817. // we don't report teams, so this shouldn't get called
  818. qr2_buffer_add(buffer, "");
  819. }
  820. static void QRKeyListCallback
  821. (
  822. PEER peer,
  823. qr2_key_type type,
  824. qr2_keybuffer_t keyBuffer,
  825. void * param
  826. )
  827. {
  828. DEBUG_LOG(("QR_KEY_LIST | %s\n", KeyTypeToString(type)));
  829. /*
  830. PeerThreadClass *t = (PeerThreadClass *)param;
  831. if (!t)
  832. {
  833. DEBUG_LOG(("QRKeyListCallback: bailing because of no thread info\n"));
  834. return;
  835. }
  836. if (!t->isHosting())
  837. t->stopHostingAlready(peer);
  838. */
  839. // register the keys we use
  840. switch(type)
  841. {
  842. case key_server:
  843. qr2_keybuffer_add(keyBuffer, HOSTNAME_KEY);
  844. qr2_keybuffer_add(keyBuffer, GAMEVER_KEY);
  845. //qr2_keybuffer_add(keyBuffer, GAMENAME_KEY);
  846. qr2_keybuffer_add(keyBuffer, MAPNAME_KEY);
  847. qr2_keybuffer_add(keyBuffer, EXECRC_KEY);
  848. qr2_keybuffer_add(keyBuffer, INICRC_KEY);
  849. qr2_keybuffer_add(keyBuffer, PW_KEY);
  850. qr2_keybuffer_add(keyBuffer, OBS_KEY);
  851. qr2_keybuffer_add(keyBuffer, USE_STATS_KEY);
  852. qr2_keybuffer_add(keyBuffer, LADIP_KEY);
  853. qr2_keybuffer_add(keyBuffer, LADPORT_KEY);
  854. qr2_keybuffer_add(keyBuffer, PINGSTR_KEY);
  855. qr2_keybuffer_add(keyBuffer, NUMPLAYER_KEY);
  856. qr2_keybuffer_add(keyBuffer, MAXPLAYER_KEY);
  857. qr2_keybuffer_add(keyBuffer, NUMOBS_KEY);
  858. break;
  859. case key_player:
  860. qr2_keybuffer_add(keyBuffer, NAME__KEY);
  861. qr2_keybuffer_add(keyBuffer, WINS__KEY);
  862. qr2_keybuffer_add(keyBuffer, LOSSES__KEY);
  863. qr2_keybuffer_add(keyBuffer, PID__KEY);
  864. qr2_keybuffer_add(keyBuffer, FACTION__KEY);
  865. qr2_keybuffer_add(keyBuffer, COLOR__KEY);
  866. break;
  867. case key_team:
  868. // no custom team keys
  869. break;
  870. }
  871. }
  872. static int QRCountCallback
  873. (
  874. PEER peer,
  875. qr2_key_type type,
  876. void * param
  877. )
  878. {
  879. PeerThreadClass *t = (PeerThreadClass *)param;
  880. if (!t)
  881. {
  882. DEBUG_LOG(("QRCountCallback: bailing because of no thread info\n"));
  883. return 0;
  884. }
  885. if (!t->isHosting())
  886. t->stopHostingAlready(peer);
  887. if(type == key_player)
  888. {
  889. DEBUG_LOG(("QR_COUNT | %s = %d\n", KeyTypeToString(type), t->getNumPlayers() + t->getNumObservers()));
  890. return t->getNumPlayers() + t->getNumObservers();
  891. }
  892. else if(type == key_team)
  893. {
  894. DEBUG_LOG(("QR_COUNT | %s = %d\n", KeyTypeToString(type), 0));
  895. return 0;
  896. }
  897. DEBUG_LOG(("QR_COUNT | %s = %d\n", KeyTypeToString(type), 0));
  898. return 0;
  899. }
  900. void PeerThreadClass::stopHostingAlready(PEER peer)
  901. {
  902. isThreadHosting = 0; // debugging
  903. s_lastStateChangedHeartbeat = 0;
  904. s_wantStateChangedHeartbeat = FALSE;
  905. peerStopGame(peer);
  906. if (qr2Sock != INVALID_SOCKET)
  907. {
  908. closesocket(qr2Sock);
  909. qr2Sock = INVALID_SOCKET;
  910. }
  911. }
  912. static void QRAddErrorCallback
  913. (
  914. PEER peer,
  915. qr2_error_t error,
  916. char * errorString,
  917. void * param
  918. )
  919. {
  920. DEBUG_LOG(("QR_ADD_ERROR | %s | %s\n", ErrorTypeToString(error), errorString));
  921. PeerResponse resp;
  922. resp.peerResponseType = PeerResponse::PEERRESPONSE_FAILEDTOHOST;
  923. TheGameSpyPeerMessageQueue->addResponse(resp);
  924. }
  925. static void QRNatNegotiateCallback
  926. (
  927. PEER peer,
  928. int cookie,
  929. void * param
  930. )
  931. {
  932. DEBUG_LOG(("QR_NAT_NEGOTIATE | 0x%08X\n", cookie));
  933. }
  934. static void KickedCallback
  935. (
  936. PEER peer,
  937. RoomType roomType,
  938. const char * nick,
  939. const char * reason,
  940. void * param
  941. )
  942. {
  943. DEBUG_LOG(("Kicked from %d by %s: \"%s\"\n", roomType, nick, reason));
  944. }
  945. static void NewPlayerListCallback
  946. (
  947. PEER peer,
  948. RoomType roomType,
  949. void * param
  950. )
  951. {
  952. DEBUG_LOG(("NewPlayerListCallback\n"));
  953. }
  954. static void AuthenticateCDKeyCallback
  955. (
  956. PEER peer,
  957. int result,
  958. const char * message,
  959. void * param
  960. )
  961. {
  962. DEBUG_LOG(("CD Key Result: %s (%d) %X\n", message, result, param));
  963. #ifdef SERVER_DEBUGGING
  964. CheckServers(peer);
  965. #endif // SERVER_DEBUGGING
  966. SerialAuthResult *val = (SerialAuthResult *)param;
  967. if (val)
  968. {
  969. if (result >= 1)
  970. {
  971. *val = SERIAL_OK;
  972. }
  973. else
  974. {
  975. *val = SERIAL_AUTHFAILED;
  976. }
  977. }
  978. #ifdef SERVER_DEBUGGING
  979. CheckServers(peer);
  980. #endif // SERVER_DEBUGGING
  981. }
  982. static SerialAuthResult doCDKeyAuthentication( PEER peer )
  983. {
  984. SerialAuthResult retval = SERIAL_NONEXISTENT;
  985. if (!peer)
  986. return retval;
  987. AsciiString s = "";
  988. if (GetStringFromRegistry("\\ergc", "", s) && s.isNotEmpty())
  989. {
  990. #ifdef SERVER_DEBUGGING
  991. DEBUG_LOG(("Before peerAuthenticateCDKey()\n"));
  992. CheckServers(peer);
  993. #endif // SERVER_DEBUGGING
  994. peerAuthenticateCDKey(peer, s.str(), AuthenticateCDKeyCallback, &retval, PEERTrue);
  995. #ifdef SERVER_DEBUGGING
  996. DEBUG_LOG(("After peerAuthenticateCDKey()\n"));
  997. CheckServers(peer);
  998. #endif // SERVER_DEBUGGING
  999. }
  1000. if (retval == SERIAL_OK)
  1001. {
  1002. PSRequest req;
  1003. req.requestType = PSRequest::PSREQUEST_READCDKEYSTATS;
  1004. req.cdkey = s.str();
  1005. TheGameSpyPSMessageQueue->addRequest(req);
  1006. }
  1007. return retval;
  1008. }
  1009. #define INBUF_LEN 256
  1010. void checkQR2Queries( PEER peer, SOCKET sock )
  1011. {
  1012. static char indata[INBUF_LEN];
  1013. struct sockaddr_in saddr;
  1014. int saddrlen = sizeof(struct sockaddr_in);
  1015. fd_set set;
  1016. struct timeval timeout = {0,0};
  1017. int error;
  1018. FD_ZERO ( &set );
  1019. FD_SET ( sock, &set );
  1020. while (1)
  1021. {
  1022. error = select(FD_SETSIZE, &set, NULL, NULL, &timeout);
  1023. if (SOCKET_ERROR == error || 0 == error)
  1024. return;
  1025. //else we have data
  1026. error = recvfrom(sock, indata, INBUF_LEN - 1, 0, (struct sockaddr *)&saddr, &saddrlen);
  1027. if (error != SOCKET_ERROR)
  1028. {
  1029. indata[error] = '\0';
  1030. peerParseQuery( peer, indata, error, (sockaddr *)&saddr );
  1031. }
  1032. }
  1033. }
  1034. static UnsignedInt localIP = 0;
  1035. void PeerThreadClass::Thread_Function()
  1036. {
  1037. try {
  1038. _set_se_translator( DumpExceptionInfo ); // Hook that allows stack trace.
  1039. PEER peer;
  1040. // Setup the callbacks.
  1041. ///////////////////////
  1042. PEERCallbacks callbacks;
  1043. memset(&callbacks, 0, sizeof(PEERCallbacks));
  1044. callbacks.disconnected = disconnectedCallback;
  1045. //callbacks.readyChanged = readyChangedCallback;
  1046. callbacks.roomMessage = roomMessageCallback;
  1047. callbacks.playerMessage = playerMessageCallback;
  1048. callbacks.gameStarted = gameStartedCallback;
  1049. callbacks.playerJoined = playerJoinedCallback;
  1050. callbacks.playerLeft = playerLeftCallback;
  1051. callbacks.playerChangedNick = playerChangedNickCallback;
  1052. callbacks.playerFlagsChanged = playerFlagsChangedCallback;
  1053. callbacks.playerInfo = playerInfoCallback;
  1054. callbacks.roomUTM = roomUTMCallback;
  1055. callbacks.playerUTM = playerUTMCallback;
  1056. callbacks.globalKeyChanged = globalKeyChangedCallback;
  1057. callbacks.roomKeyChanged = roomKeyChangedCallback;
  1058. callbacks.qrServerKey = QRServerKeyCallback;
  1059. callbacks.qrPlayerKey = QRPlayerKeyCallback;
  1060. callbacks.qrTeamKey = QRTeamKeyCallback;
  1061. callbacks.qrKeyList = QRKeyListCallback;
  1062. callbacks.qrCount = QRCountCallback;
  1063. callbacks.qrAddError = QRAddErrorCallback;
  1064. callbacks.qrNatNegotiateCallback = QRNatNegotiateCallback;
  1065. callbacks.kicked = KickedCallback;
  1066. callbacks.newPlayerList = NewPlayerListCallback;
  1067. callbacks.param = this;
  1068. m_qmGroupRoom = 0;
  1069. peer = peerInitialize( &callbacks );
  1070. DEBUG_ASSERTCRASH( peer != NULL, ("NULL peer!") );
  1071. m_isConnected = m_isConnecting = false;
  1072. qr2_register_key(EXECRC_KEY, EXECRC_STR);
  1073. qr2_register_key(INICRC_KEY, INICRC_STR);
  1074. qr2_register_key(PW_KEY, PW_STR);
  1075. qr2_register_key(OBS_KEY, OBS_STR);
  1076. qr2_register_key(USE_STATS_KEY, USE_STATS_STR);
  1077. qr2_register_key(LADIP_KEY, LADIP_STR);
  1078. qr2_register_key(LADPORT_KEY, LADPORT_STR);
  1079. qr2_register_key(PINGSTR_KEY, PINGSTR_STR);
  1080. qr2_register_key(NUMOBS_KEY, NUMOBS_STR);
  1081. qr2_register_key(NUMPLAYER_KEY, NUMPLAYER_STR);
  1082. qr2_register_key(MAXPLAYER_KEY, MAXPLAYER_STR);
  1083. qr2_register_key(NAME__KEY, NAME__STR "_");
  1084. qr2_register_key(WINS__KEY, WINS__STR "_");
  1085. qr2_register_key(LOSSES__KEY, LOSSES__STR "_");
  1086. qr2_register_key(FACTION__KEY, FACTION__STR "_");
  1087. qr2_register_key(COLOR__KEY, COLOR__STR "_");
  1088. const Int NumKeys = 15;
  1089. unsigned char allKeysArray[NumKeys] = {
  1090. /*
  1091. PID__KEY,
  1092. NAME__KEY,
  1093. WINS__KEY,
  1094. LOSSES__KEY,
  1095. FACTION__KEY,
  1096. COLOR__KEY,
  1097. */
  1098. MAPNAME_KEY,
  1099. GAMEVER_KEY,
  1100. GAMENAME_KEY,
  1101. EXECRC_KEY,
  1102. INICRC_KEY,
  1103. PW_KEY,
  1104. OBS_KEY,
  1105. USE_STATS_KEY,
  1106. LADIP_KEY,
  1107. LADPORT_KEY,
  1108. PINGSTR_KEY,
  1109. NUMOBS_KEY,
  1110. NUMPLAYER_KEY,
  1111. MAXPLAYER_KEY,
  1112. HOSTNAME_KEY
  1113. };
  1114. /*
  1115. const char *allKeys = "\\pid_\\mapname\\gamever\\gamename" \
  1116. "\\" EXECRC_STR "\\" INICRC_STR \
  1117. "\\" PW_STR "\\" OBS_STR "\\" USE_STATS_STR "\\" LADIP_STR "\\" LADPORT_STR \
  1118. "\\" PINGSTR_STR "\\" NUMOBS_STR \
  1119. "\\" NUMPLAYER_STR "\\" MAXPLAYER_STR \
  1120. "\\" NAME__STR "_" "\\" WINS__STR "_" "\\" LOSSES__STR "_" "\\" FACTION__STR "_" "\\" COLOR__STR "_";
  1121. */
  1122. const char * key = "username";
  1123. peerSetRoomWatchKeys(peer, StagingRoom, 1, &key, PEERTrue);
  1124. peerSetRoomWatchKeys(peer, GroupRoom, 1, &key, PEERTrue);
  1125. m_localRoomID = 0;
  1126. m_localStagingServerName = L"";
  1127. m_qmStatus = QM_IDLE;
  1128. // Setup which rooms to do pings and cross-pings in.
  1129. ////////////////////////////////////////////////////
  1130. PEERBool pingRooms[NumRooms];
  1131. PEERBool crossPingRooms[NumRooms];
  1132. pingRooms[TitleRoom] = PEERFalse;
  1133. pingRooms[GroupRoom] = PEERFalse;
  1134. pingRooms[StagingRoom] = PEERFalse;
  1135. crossPingRooms[TitleRoom] = PEERFalse;
  1136. crossPingRooms[GroupRoom] = PEERFalse;
  1137. crossPingRooms[StagingRoom] = PEERFalse;
  1138. /*********
  1139. First step, set our game authentication info
  1140. We could do:
  1141. strcpy(gcd_gamename,"ccgenzh");
  1142. strcpy(gcd_secret_key,"D6s9k3");
  1143. or
  1144. strcpy(gcd_gamename,"ccgeneralsb");
  1145. strcpy(gcd_secret_key,"whatever the key is");
  1146. ...but this is more secure:
  1147. **********/
  1148. char gameName[12] = {0};
  1149. char secretKey[7] = {0};
  1150. /**
  1151. gameName[0]='c';gameName[1]='c';gameName[2]='g';gameName[3]='e';
  1152. gameName[4]='n';gameName[5]='e';gameName[6]='r';gameName[7]='a';
  1153. gameName[8]='l';gameName[9]='s';gameName[10]='b';gameName[11]='\0';
  1154. secretKey[0]='g';secretKey[1]='3';secretKey[2]='T';secretKey[3]='9';
  1155. secretKey[4]='s';secretKey[5]='2';secretKey[6]='\0';
  1156. /**/
  1157. gameName[0]='c';gameName[1]='c';gameName[2]='g';gameName[3]='e';
  1158. gameName[4]='n';gameName[5]='z';gameName[6]='h';gameName[7]='\0';
  1159. secretKey[0]='D';secretKey[1]='6';secretKey[2]='s';secretKey[3]='9';
  1160. secretKey[4]='k';secretKey[5]='3';secretKey[6]='\0';
  1161. /**/
  1162. // Set the title.
  1163. /////////////////
  1164. if(!peerSetTitle( peer , gameName, secretKey, gameName, secretKey, GetRegistryVersion(), 30, PEERTrue, pingRooms, crossPingRooms))
  1165. {
  1166. DEBUG_CRASH(("Error setting title"));
  1167. peerShutdown( peer );
  1168. peer = NULL;
  1169. return;
  1170. }
  1171. OptionPreferences pref;
  1172. UnsignedInt preferredIP = INADDR_ANY;
  1173. UnsignedInt selectedIP = pref.getOnlineIPAddress();
  1174. DEBUG_LOG(("Looking for IP %X\n", selectedIP));
  1175. IPEnumeration IPs;
  1176. EnumeratedIP *IPlist = IPs.getAddresses();
  1177. while (IPlist)
  1178. {
  1179. DEBUG_LOG(("Looking at IP %s\n", IPlist->getIPstring().str()));
  1180. if (selectedIP == IPlist->getIP())
  1181. {
  1182. preferredIP = IPlist->getIP();
  1183. DEBUG_LOG(("Connecting to GameSpy chat server via IP address %8.8X\n", preferredIP));
  1184. break;
  1185. }
  1186. IPlist = IPlist->getNext();
  1187. }
  1188. chatSetLocalIP(preferredIP);
  1189. UnsignedInt preferredQRPort = 0;
  1190. AsciiString selectedQRPort = pref["GameSpyQRPort"];
  1191. if (selectedQRPort.isNotEmpty())
  1192. {
  1193. preferredQRPort = atoi(selectedQRPort.str());
  1194. }
  1195. PeerRequest incomingRequest;
  1196. while ( running )
  1197. {
  1198. // deal with requests
  1199. if (TheGameSpyPeerMessageQueue->getRequest(incomingRequest))
  1200. {
  1201. DEBUG_LOG(("TheGameSpyPeerMessageQueue->getRequest() got request of type %d\n", incomingRequest.peerRequestType));
  1202. switch (incomingRequest.peerRequestType)
  1203. {
  1204. case PeerRequest::PEERREQUEST_LOGIN:
  1205. {
  1206. m_isConnecting = true;
  1207. m_originalName = incomingRequest.nick;
  1208. m_loginName = incomingRequest.nick;
  1209. m_profileID = incomingRequest.login.profileID;
  1210. m_password = incomingRequest.password;
  1211. m_email = incomingRequest.email;
  1212. peerConnect( peer, incomingRequest.nick.c_str(), incomingRequest.login.profileID, nickErrorCallbackWrapper, connectCallbackWrapper, this, PEERTrue );
  1213. #ifdef SERVER_DEBUGGING
  1214. DEBUG_LOG(("After peerConnect()\n"));
  1215. CheckServers(peer);
  1216. #endif // SERVER_DEBUGGING
  1217. if (m_isConnected)
  1218. {
  1219. SerialAuthResult ret = doCDKeyAuthentication( peer );
  1220. if (ret != SERIAL_OK)
  1221. {
  1222. m_isConnecting = m_isConnected = false;
  1223. MESSAGE_QUEUE->setSerialAuthResult( ret );
  1224. peerDisconnect( peer );
  1225. }
  1226. }
  1227. m_isConnecting = false;
  1228. // check our connection
  1229. //if (m_isConnected)
  1230. //{
  1231. // GetLocalChatConnectionAddress("peerchat.gamespy.com", 6667, localIP);
  1232. //}
  1233. }
  1234. break;
  1235. case PeerRequest::PEERREQUEST_LOGOUT:
  1236. m_isConnecting = m_isConnected = false;
  1237. peerDisconnect( peer );
  1238. break;
  1239. case PeerRequest::PEERREQUEST_JOINGROUPROOM:
  1240. m_groupRoomID = incomingRequest.groupRoom.id;
  1241. isThreadHosting = 0; // debugging
  1242. s_lastStateChangedHeartbeat = 0;
  1243. s_wantStateChangedHeartbeat = FALSE;
  1244. peerStopGame( peer );
  1245. peerLeaveRoom( peer, GroupRoom, NULL );
  1246. peerLeaveRoom( peer, StagingRoom, NULL );
  1247. if (qr2Sock != INVALID_SOCKET)
  1248. {
  1249. closesocket(qr2Sock);
  1250. qr2Sock = INVALID_SOCKET;
  1251. }
  1252. m_isHosting = false;
  1253. m_localRoomID = m_groupRoomID;
  1254. DEBUG_LOG(("Requesting to join room %d in thread %X\n", m_localRoomID, this));
  1255. peerJoinGroupRoom( peer, incomingRequest.groupRoom.id, joinRoomCallback, (void *)this, PEERTrue );
  1256. break;
  1257. case PeerRequest::PEERREQUEST_LEAVEGROUPROOM:
  1258. m_groupRoomID = 0;
  1259. updateBuddyStatus( BUDDY_ONLINE );
  1260. peerLeaveRoom( peer, GroupRoom, NULL );
  1261. peerLeaveRoom( peer, StagingRoom, NULL ); m_isHosting = false;
  1262. break;
  1263. case PeerRequest::PEERREQUEST_JOINSTAGINGROOM:
  1264. {
  1265. m_groupRoomID = 0;
  1266. updateBuddyStatus( BUDDY_ONLINE );
  1267. peerLeaveRoom( peer, GroupRoom, NULL );
  1268. peerLeaveRoom( peer, StagingRoom, NULL ); m_isHosting = false;
  1269. SBServer server = findServerByID(incomingRequest.stagingRoom.id);
  1270. m_localStagingServerName = incomingRequest.text;
  1271. DEBUG_LOG(("Setting m_localStagingServerName to [%ls]\n", m_localStagingServerName.c_str()));
  1272. m_localRoomID = incomingRequest.stagingRoom.id;
  1273. DEBUG_LOG(("Requesting to join room %d\n", m_localRoomID));
  1274. if (server)
  1275. {
  1276. peerJoinStagingRoom( peer, server, incomingRequest.password.c_str(), joinRoomCallback, (void *)this, PEERTrue );
  1277. }
  1278. else
  1279. {
  1280. PeerResponse resp;
  1281. resp.peerResponseType = PeerResponse::PEERRESPONSE_JOINSTAGINGROOM;
  1282. resp.joinStagingRoom.id = incomingRequest.stagingRoom.id;
  1283. resp.joinStagingRoom.ok = FALSE;
  1284. resp.joinStagingRoom.result = PEERJoinFailed;
  1285. TheGameSpyPeerMessageQueue->addResponse(resp);
  1286. }
  1287. }
  1288. break;
  1289. case PeerRequest::PEERREQUEST_LEAVESTAGINGROOM:
  1290. m_groupRoomID = 0;
  1291. updateBuddyStatus( BUDDY_ONLINE );
  1292. peerLeaveRoom( peer, GroupRoom, NULL );
  1293. peerLeaveRoom( peer, StagingRoom, NULL );
  1294. isThreadHosting = 0; // debugging
  1295. s_lastStateChangedHeartbeat = 0;
  1296. s_wantStateChangedHeartbeat = FALSE;
  1297. if (m_isHosting)
  1298. {
  1299. peerStopGame( peer );
  1300. if (qr2Sock != INVALID_SOCKET)
  1301. {
  1302. closesocket(qr2Sock);
  1303. qr2Sock = INVALID_SOCKET;
  1304. }
  1305. m_isHosting = false;
  1306. }
  1307. break;
  1308. case PeerRequest::PEERREQUEST_MESSAGEPLAYER:
  1309. {
  1310. std::string s = WideCharStringToMultiByte(incomingRequest.text.c_str());
  1311. peerMessagePlayer( peer, incomingRequest.nick.c_str(), s.c_str(), (incomingRequest.message.isAction)?ActionMessage:NormalMessage );
  1312. }
  1313. break;
  1314. case PeerRequest::PEERREQUEST_MESSAGEROOM:
  1315. {
  1316. std::string s = WideCharStringToMultiByte(incomingRequest.text.c_str());
  1317. peerMessageRoom( peer, (m_groupRoomID)?GroupRoom:StagingRoom, s.c_str(), (incomingRequest.message.isAction)?ActionMessage:NormalMessage );
  1318. }
  1319. break;
  1320. case PeerRequest::PEERREQUEST_PUSHSTATS:
  1321. {
  1322. DEBUG_LOG(("PEERREQUEST_PUSHSTATS: stats are %d,%d,%d,%d,%d,%d\n",
  1323. incomingRequest.statsToPush.locale, incomingRequest.statsToPush.wins, incomingRequest.statsToPush.losses, incomingRequest.statsToPush.rankPoints, incomingRequest.statsToPush.side, incomingRequest.statsToPush.preorder));
  1324. // Testing alternate way to push stats
  1325. #ifdef USE_BROADCAST_KEYS
  1326. _snprintf(s_valueBuffers[0], 20, "%d", incomingRequest.statsToPush.locale);
  1327. _snprintf(s_valueBuffers[1], 20, "%d", incomingRequest.statsToPush.wins);
  1328. _snprintf(s_valueBuffers[2], 20, "%d", incomingRequest.statsToPush.losses);
  1329. _snprintf(s_valueBuffers[3], 20, "%d", incomingRequest.statsToPush.rankPoints);
  1330. _snprintf(s_valueBuffers[4], 20, "%d", incomingRequest.statsToPush.side);
  1331. _snprintf(s_valueBuffers[5], 20, "%d", incomingRequest.statsToPush.preorder);
  1332. pushStatsToRoom(peer);
  1333. #else
  1334. const char *keys[6] = { "locale", "wins", "losses", "points", "side", "pre" };
  1335. char valueStrings[6][20];
  1336. char *values[6] = { valueStrings[0], valueStrings[1], valueStrings[2],
  1337. valueStrings[3], valueStrings[4], valueStrings[5]};
  1338. _snprintf(values[0], 20, "%d", incomingRequest.statsToPush.locale);
  1339. _snprintf(values[1], 20, "%d", incomingRequest.statsToPush.wins);
  1340. _snprintf(values[2], 20, "%d", incomingRequest.statsToPush.losses);
  1341. _snprintf(values[3], 20, "%d", incomingRequest.statsToPush.rankPoints);
  1342. _snprintf(values[4], 20, "%d", incomingRequest.statsToPush.side);
  1343. _snprintf(values[5], 20, "%d", incomingRequest.statsToPush.preorder);
  1344. peerSetGlobalKeys(peer, 6, (const char **)keys, (const char **)values);
  1345. peerSetGlobalWatchKeys(peer, GroupRoom, 0, NULL, PEERFalse);
  1346. peerSetGlobalWatchKeys(peer, StagingRoom, 0, NULL, PEERFalse);
  1347. peerSetGlobalWatchKeys(peer, GroupRoom, 6, keys, PEERTrue);
  1348. peerSetGlobalWatchKeys(peer, StagingRoom, 6, keys, PEERTrue);
  1349. #endif
  1350. }
  1351. break;
  1352. case PeerRequest::PEERREQUEST_SETGAMEOPTIONS:
  1353. {
  1354. m_mapName = incomingRequest.gameOptsMapName;
  1355. m_numPlayers = incomingRequest.gameOptions.numPlayers;
  1356. m_numObservers = incomingRequest.gameOptions.numObservers;
  1357. m_maxPlayers = incomingRequest.gameOptions.maxPlayers;
  1358. DEBUG_LOG(("peerStateChanged(): Marking game options state as changed - %d players, %d observers\n", m_numPlayers, m_numObservers));
  1359. for (Int i=0; i<MAX_SLOTS; ++i)
  1360. {
  1361. m_playerNames[i] = incomingRequest.gameOptsPlayerNames[i];
  1362. m_playerWins[i] = incomingRequest.gameOptions.wins[i];
  1363. m_playerLosses[i] = incomingRequest.gameOptions.losses[i];
  1364. m_playerProfileID[i] = incomingRequest.gameOptions.profileID[i];
  1365. m_playerFactions[i] = incomingRequest.gameOptions.faction[i];
  1366. m_playerColors[i] = incomingRequest.gameOptions.color[i];
  1367. }
  1368. s_wantStateChangedHeartbeat = TRUE;
  1369. /*
  1370. peerStateChanged( peer );
  1371. #ifdef DEBUG_LOGGING
  1372. static UnsignedInt prev = 0;
  1373. UnsignedInt now = timeGetTime();
  1374. UnsignedInt diff = now - prev;
  1375. prev = now;
  1376. #endif
  1377. STATECHANGED_LOG(("peerStateChanged() at time %d (difference of %d ms)\n", now, diff));
  1378. */
  1379. peerUTMRoom( peer, StagingRoom, "SL/", incomingRequest.options.c_str(), PEERFalse ); // send the full string to people in the room
  1380. }
  1381. break;
  1382. case PeerRequest::PEERREQUEST_GETEXTENDEDSTAGINGROOMINFO:
  1383. {
  1384. SBServer server = findServerByID( incomingRequest.stagingRoom.id );
  1385. if (server)
  1386. {
  1387. DEBUG_LOG(("Requesting full update on a game\n"));
  1388. peerUpdateGame( peer, server, PEERTrue );
  1389. }
  1390. else
  1391. {
  1392. DEBUG_LOG(("Tried to update non-existent server!\n"));
  1393. }
  1394. }
  1395. break;
  1396. case PeerRequest::PEERREQUEST_CREATESTAGINGROOM:
  1397. {
  1398. Int oldGroupID = m_groupRoomID;
  1399. m_groupRoomID = 0;
  1400. updateBuddyStatus( BUDDY_ONLINE );
  1401. if (!incomingRequest.stagingRoomCreation.restrictGameList)
  1402. {
  1403. peerLeaveRoom( peer, GroupRoom, NULL );
  1404. peerLeaveRoom( peer, StagingRoom, NULL );
  1405. }
  1406. m_isHosting = TRUE;
  1407. Int res = PEERJoinFailed;
  1408. if (qr2Sock == INVALID_SOCKET)
  1409. {
  1410. // allocate a port
  1411. if (preferredQRPort < 1024)
  1412. {
  1413. preferredQRPort = 6500 + (ntohl(localIP) & 0xff);
  1414. }
  1415. DEBUG_LOG(("Using %8.8X:%d for QR2\n", ntohl(localIP), preferredQRPort));
  1416. }
  1417. else
  1418. {
  1419. closesocket(qr2Sock);
  1420. qr2Sock = INVALID_SOCKET;
  1421. }
  1422. qr2Sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  1423. struct sockaddr_in saddr;
  1424. saddr.sin_port=htons(preferredQRPort);
  1425. saddr.sin_addr.s_addr=localIP;
  1426. saddr.sin_family=AF_INET;
  1427. if (bind(qr2Sock, (sockaddr *)&saddr, sizeof(saddr)) != 0)
  1428. {
  1429. DEBUG_LOG(("Could not bind to %d! Falling back to GameSpy's default port\n", preferredQRPort));
  1430. closesocket(qr2Sock);
  1431. qr2Sock = INVALID_SOCKET;
  1432. preferredQRPort = 0;
  1433. }
  1434. std::string compositeGame = m_loginName;
  1435. compositeGame.append(" ");
  1436. compositeGame.append(WideCharStringToMultiByte(incomingRequest.text.c_str()));
  1437. m_localStagingServerName = incomingRequest.text;
  1438. m_playerNames[0] = m_loginName;
  1439. peerCreateStagingRoomWithSocket(peer, compositeGame.c_str(), MAX_SLOTS, incomingRequest.password.c_str(), qr2Sock, preferredQRPort, createRoomCallback, (void *)&res, PEERTrue);
  1440. //peerCreateStagingRoomWithSocket(peer, WideCharStringToMultiByte(incomingRequest.text.c_str()).c_str(), MAX_SLOTS, incomingRequest.password.c_str(), qr2Sock, preferredQRPort, createRoomCallback, (void *)&res, PEERTrue);
  1441. DEBUG_LOG(("PEERREQUEST_CREATESTAGINGROOM - creating staging room, name is %ls, passwd is %s, result = %d\n",
  1442. incomingRequest.text.c_str(), incomingRequest.password.c_str(), res));
  1443. PeerResponse resp;
  1444. resp.peerResponseType = PeerResponse::PEERRESPONSE_CREATESTAGINGROOM;
  1445. resp.createStagingRoom.result = res;
  1446. TheGameSpyPeerMessageQueue->addResponse(resp);
  1447. if (res != PEERJoinSuccess && res != PEERAlreadyInRoom)
  1448. {
  1449. m_localRoomID = oldGroupID;
  1450. DEBUG_LOG(("Requesting to join room %d\n", m_localRoomID));
  1451. if (incomingRequest.stagingRoomCreation.restrictGameList)
  1452. {
  1453. peerLeaveRoom( peer, StagingRoom, NULL );
  1454. }
  1455. else
  1456. {
  1457. peerJoinGroupRoom( peer, oldGroupID, joinRoomCallback, (void *)this, PEERTrue );
  1458. }
  1459. m_isHosting = FALSE;
  1460. m_localStagingServerName = L"";
  1461. m_playerNames[0] = "";
  1462. }
  1463. else
  1464. {
  1465. if (incomingRequest.stagingRoomCreation.restrictGameList)
  1466. {
  1467. peerLeaveRoom( peer, GroupRoom, NULL );
  1468. }
  1469. isThreadHosting = 1; // debugging
  1470. s_lastStateChangedHeartbeat = timeGetTime(); // wait the full interval before updating state
  1471. s_wantStateChangedHeartbeat = FALSE;
  1472. m_isHosting = TRUE;
  1473. m_allowObservers = incomingRequest.stagingRoomCreation.allowObservers;
  1474. m_useStats = incomingRequest.stagingRoomCreation.useStats;
  1475. m_mapName = "";
  1476. for (Int i=0; i<MAX_SLOTS; ++i)
  1477. {
  1478. m_playerNames[i] = "";
  1479. m_playerWins[i] = 0;
  1480. m_playerLosses[i] = 0;
  1481. m_playerProfileID[i] = 0;
  1482. m_playerFactions[i] = 0;
  1483. m_playerColors[i] = 0;
  1484. }
  1485. if (incomingRequest.password.length() > 0)
  1486. m_hasPassword = true;
  1487. else
  1488. m_hasPassword = false;
  1489. m_playerNames[0] = m_loginName;
  1490. m_exeCRC = incomingRequest.stagingRoomCreation.exeCRC;
  1491. m_iniCRC = incomingRequest.stagingRoomCreation.iniCRC;
  1492. m_gameVersion = incomingRequest.stagingRoomCreation.gameVersion;
  1493. m_localStagingServerName = incomingRequest.text;
  1494. m_ladderIP = incomingRequest.ladderIP;
  1495. m_pingStr = incomingRequest.hostPingStr;
  1496. m_ladderPort = incomingRequest.stagingRoomCreation.ladPort;
  1497. #ifdef USE_BROADCAST_KEYS
  1498. pushStatsToRoom(peer);
  1499. #endif // USE_BROADCAST_KEYS
  1500. DEBUG_LOG(("Setting m_localStagingServerName to [%ls]\n", m_localStagingServerName.c_str()));
  1501. updateBuddyStatus( BUDDY_STAGING, 0, WideCharStringToMultiByte(m_localStagingServerName.c_str()) );
  1502. }
  1503. }
  1504. break;
  1505. case PeerRequest::PEERREQUEST_STARTGAMELIST:
  1506. {
  1507. m_sawCompleteGameList = FALSE;
  1508. PeerResponse resp;
  1509. resp.peerResponseType = PeerResponse::PEERRESPONSE_STAGINGROOM;
  1510. resp.stagingRoom.action = PEER_CLEAR;
  1511. resp.stagingRoom.isStaging = TRUE;
  1512. resp.stagingRoom.percentComplete = 0;
  1513. clearServers();
  1514. TheGameSpyPeerMessageQueue->addResponse(resp);
  1515. peerStartListingGames( peer, allKeysArray, NumKeys, (incomingRequest.gameList.restrictGameList?"~":NULL), listingGamesCallback, this );
  1516. }
  1517. break;
  1518. case PeerRequest::PEERREQUEST_STOPGAMELIST:
  1519. {
  1520. peerStopListingGames( peer );
  1521. }
  1522. break;
  1523. case PeerRequest::PEERREQUEST_STARTGAME:
  1524. {
  1525. peerStartGame( peer, NULL, PEER_STOP_REPORTING);
  1526. }
  1527. break;
  1528. case PeerRequest::PEERREQUEST_UTMPLAYER:
  1529. {
  1530. if (incomingRequest.nick.length() > 0)
  1531. {
  1532. peerUTMPlayer( peer, incomingRequest.nick.c_str(), incomingRequest.id.c_str(), incomingRequest.options.c_str(), PEERFalse );
  1533. }
  1534. }
  1535. break;
  1536. case PeerRequest::PEERREQUEST_UTMROOM:
  1537. {
  1538. peerUTMRoom( peer, (incomingRequest.UTM.isStagingRoom)?StagingRoom:GroupRoom, incomingRequest.id.c_str(), incomingRequest.options.c_str(), PEERFalse );
  1539. }
  1540. break;
  1541. case PeerRequest::PEERREQUEST_STARTQUICKMATCH:
  1542. {
  1543. m_qmInfo = incomingRequest;
  1544. doQuickMatch( peer );
  1545. }
  1546. break;
  1547. }
  1548. }
  1549. if (isThreadHosting && s_wantStateChangedHeartbeat)
  1550. {
  1551. UnsignedInt now = timeGetTime();
  1552. if (now > s_lastStateChangedHeartbeat + s_heartbeatInterval)
  1553. {
  1554. s_lastStateChangedHeartbeat = now;
  1555. s_wantStateChangedHeartbeat = FALSE;
  1556. peerStateChanged( peer );
  1557. #ifdef DEBUG_LOGGING
  1558. static UnsignedInt prev = 0;
  1559. UnsignedInt now = timeGetTime();
  1560. UnsignedInt diff = now - prev;
  1561. prev = now;
  1562. #endif
  1563. STATECHANGED_LOG(("peerStateChanged() at time %d (difference of %d ms)\n", now, diff));
  1564. }
  1565. }
  1566. // update the network
  1567. PEERBool isConnected = PEERTrue;
  1568. isConnected = peerIsConnected( peer );
  1569. if ( isConnected == PEERTrue )
  1570. {
  1571. if (qr2Sock != INVALID_SOCKET)
  1572. {
  1573. // check hosting activity
  1574. checkQR2Queries( peer, qr2Sock );
  1575. }
  1576. peerThink( peer );
  1577. }
  1578. // end our timeslice
  1579. Switch_Thread();
  1580. }
  1581. DEBUG_LOG(("voluntarily ending peer thread %d\n", running));
  1582. peerShutdown( peer );
  1583. } catch ( ... ) {
  1584. DEBUG_CRASH(("Exception in peer thread!"));
  1585. try {
  1586. PeerResponse resp;
  1587. resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT;
  1588. resp.discon.reason = DISCONNECT_LOSTCON;
  1589. TheGameSpyPeerMessageQueue->addResponse(resp);
  1590. }
  1591. catch (...)
  1592. {
  1593. }
  1594. }
  1595. }
  1596. static void qmProfileIDCallback( PEER peer, PEERBool success, const char *nick, int profileID, void *param )
  1597. {
  1598. Int *i = (Int *)param;
  1599. if (!i || !success || !nick)
  1600. return;
  1601. *i = profileID;
  1602. }
  1603. static Int matchbotProfileID = 0;
  1604. void quickmatchEnumPlayersCallback( PEER peer, PEERBool success, RoomType roomType, int index, const char * nick, int flags, void * param )
  1605. {
  1606. PeerThreadClass *t = (PeerThreadClass *)param;
  1607. if (!t || !success || nick == NULL || nick[0] == '\0')
  1608. {
  1609. t->sawEndOfEnumPlayers();
  1610. return;
  1611. }
  1612. Int id = 0;
  1613. peerGetPlayerProfileID(peer, nick, qmProfileIDCallback, &id, PEERTrue);
  1614. DEBUG_LOG(("Saw player %s with id %d (looking for %d)\n", nick, id, matchbotProfileID));
  1615. if (id == matchbotProfileID)
  1616. {
  1617. t->sawMatchbot(nick);
  1618. }
  1619. PeerResponse resp;
  1620. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERJOIN;
  1621. resp.nick = nick;
  1622. resp.player.roomType = roomType;
  1623. resp.player.IP = 0;
  1624. TheGameSpyPeerMessageQueue->addResponse(resp);
  1625. }
  1626. void PeerThreadClass::handleQMMatch(PEER peer, Int mapIndex, Int seed,
  1627. char *playerName[MAX_SLOTS],
  1628. char *playerIP[MAX_SLOTS],
  1629. char *playerSide[MAX_SLOTS],
  1630. char *playerColor[MAX_SLOTS],
  1631. char *playerNAT[MAX_SLOTS])
  1632. {
  1633. if (m_qmStatus == QM_WORKING)
  1634. {
  1635. m_qmStatus = QM_MATCHED;
  1636. peerLeaveRoom(peer, GroupRoom, "");
  1637. for (Int i=0; i<MAX_SLOTS; ++i)
  1638. {
  1639. if (playerName[i] && stricmp(playerName[i], m_loginName.c_str()))
  1640. {
  1641. peerMessagePlayer( peer, playerName[i], "We're matched!", NormalMessage );
  1642. }
  1643. }
  1644. PeerResponse resp;
  1645. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  1646. resp.qmStatus.status = QM_MATCHED;
  1647. for (i=0; i<MAX_SLOTS; ++i)
  1648. {
  1649. if (playerName[i])
  1650. {
  1651. resp.stagingRoomPlayerNames[i] = playerName[i];
  1652. resp.qmStatus.IP[i] = atoi(playerIP[i]);
  1653. resp.qmStatus.side[i] = atoi(playerSide[i]);
  1654. resp.qmStatus.color[i] = atoi(playerColor[i]);
  1655. resp.qmStatus.nat[i] = atoi(playerNAT[i]);
  1656. }
  1657. else
  1658. {
  1659. resp.stagingRoomPlayerNames[i] = "";
  1660. resp.qmStatus.IP[i] = 0;
  1661. resp.qmStatus.side[i] = 0;
  1662. resp.qmStatus.color[i] = 0;
  1663. resp.qmStatus.nat[i] = 0;
  1664. }
  1665. }
  1666. resp.qmStatus.seed = seed;
  1667. resp.qmStatus.mapIdx = mapIndex;
  1668. TheGameSpyPeerMessageQueue->addResponse(resp);
  1669. }
  1670. }
  1671. void PeerThreadClass::doQuickMatch( PEER peer )
  1672. {
  1673. m_qmStatus = QM_JOININGQMCHANNEL;
  1674. Bool done = false;
  1675. matchbotProfileID = m_qmInfo.QM.botID;
  1676. setQMGroupRoom( m_qmInfo.QM.roomID );
  1677. m_sawMatchbot = false;
  1678. updateBuddyStatus( BUDDY_MATCHING );
  1679. while (!done && running)
  1680. {
  1681. if (!peerIsConnected( peer ))
  1682. {
  1683. done = true;
  1684. }
  1685. else
  1686. {
  1687. // update the network
  1688. peerThink( peer );
  1689. // end our timeslice
  1690. Switch_Thread();
  1691. PeerRequest incomingRequest;
  1692. if (TheGameSpyPeerMessageQueue->getRequest(incomingRequest))
  1693. {
  1694. switch (incomingRequest.peerRequestType)
  1695. {
  1696. case PeerRequest::PEERREQUEST_WIDENQUICKMATCHSEARCH:
  1697. {
  1698. if (m_qmStatus != QM_IDLE && m_qmStatus != QM_STOPPED && m_sawMatchbot)
  1699. {
  1700. peerMessagePlayer( peer, m_matchbotName.c_str(), "\\WIDEN", NormalMessage );
  1701. }
  1702. }
  1703. break;
  1704. case PeerRequest::PEERREQUEST_STOPQUICKMATCH:
  1705. {
  1706. m_qmStatus = QM_STOPPED;
  1707. peerLeaveRoom(peer, GroupRoom, "");
  1708. done = true;
  1709. }
  1710. break;
  1711. case PeerRequest::PEERREQUEST_LOGOUT:
  1712. {
  1713. m_qmStatus = QM_STOPPED;
  1714. peerLeaveRoom(peer, GroupRoom, "");
  1715. done = true;
  1716. }
  1717. break;
  1718. case PeerRequest::PEERREQUEST_LEAVEGROUPROOM:
  1719. {
  1720. m_qmStatus = QM_STOPPED;
  1721. peerLeaveRoom(peer, GroupRoom, "");
  1722. done = true;
  1723. }
  1724. break;
  1725. case PeerRequest::PEERREQUEST_UTMPLAYER:
  1726. {
  1727. peerUTMPlayer( peer, incomingRequest.nick.c_str(), incomingRequest.id.c_str(), incomingRequest.options.c_str(), PEERFalse );
  1728. }
  1729. break;
  1730. default:
  1731. {
  1732. DEBUG_CRASH(("Unanticipated request %d to peer thread!", incomingRequest.peerRequestType));
  1733. }
  1734. break;
  1735. }
  1736. }
  1737. if (!done)
  1738. {
  1739. // do the next bit of QM
  1740. switch (m_qmStatus)
  1741. {
  1742. case QM_JOININGQMCHANNEL:
  1743. {
  1744. PeerResponse resp;
  1745. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  1746. resp.qmStatus.status = QM_JOININGQMCHANNEL;
  1747. TheGameSpyPeerMessageQueue->addResponse(resp);
  1748. m_groupRoomID = m_qmGroupRoom;
  1749. peerLeaveRoom( peer, GroupRoom, NULL );
  1750. peerLeaveRoom( peer, StagingRoom, NULL ); m_isHosting = false;
  1751. m_localRoomID = m_groupRoomID;
  1752. m_roomJoined = false;
  1753. DEBUG_LOG(("Requesting to join room %d in thread %X\n", m_localRoomID, this));
  1754. peerJoinGroupRoom( peer, m_localRoomID, joinRoomCallback, (void *)this, PEERTrue );
  1755. if (m_roomJoined)
  1756. {
  1757. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  1758. resp.qmStatus.status = QM_LOOKINGFORBOT;
  1759. TheGameSpyPeerMessageQueue->addResponse(resp);
  1760. m_qmStatus = QM_LOOKINGFORBOT;
  1761. m_sawMatchbot = false;
  1762. m_sawEndOfEnumPlayers = false;
  1763. peerEnumPlayers( peer, GroupRoom, quickmatchEnumPlayersCallback, this );
  1764. }
  1765. else
  1766. {
  1767. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  1768. resp.qmStatus.status = QM_COULDNOTFINDBOT;
  1769. TheGameSpyPeerMessageQueue->addResponse(resp);
  1770. done = true;
  1771. m_qmStatus = QM_STOPPED;
  1772. }
  1773. }
  1774. break;
  1775. case QM_LOOKINGFORBOT:
  1776. {
  1777. if (m_sawEndOfEnumPlayers)
  1778. {
  1779. if (m_sawMatchbot)
  1780. {
  1781. char buf[64];
  1782. buf[63] = '\0';
  1783. std::string msg = "\\CINFO";
  1784. _snprintf(buf, 63, "\\Widen\\%d", m_qmInfo.QM.widenTime);
  1785. msg.append(buf);
  1786. _snprintf(buf, 63, "\\LadID\\%d", m_qmInfo.QM.ladderID);
  1787. msg.append(buf);
  1788. _snprintf(buf, 63, "\\LadPass\\%d", m_qmInfo.QM.ladderPassCRC);
  1789. msg.append(buf);
  1790. _snprintf(buf, 63, "\\PointsMin\\%d", m_qmInfo.QM.minPointPercentage);
  1791. msg.append(buf);
  1792. _snprintf(buf, 63, "\\PointsMax\\%d", m_qmInfo.QM.maxPointPercentage);
  1793. msg.append(buf);
  1794. _snprintf(buf, 63, "\\Points\\%d", m_qmInfo.QM.points);
  1795. msg.append(buf);
  1796. _snprintf(buf, 63, "\\Discons\\%d", m_qmInfo.QM.discons);
  1797. msg.append(buf);
  1798. _snprintf(buf, 63, "\\DisconMax\\%d", m_qmInfo.QM.maxDiscons);
  1799. msg.append(buf);
  1800. _snprintf(buf, 63, "\\NumPlayers\\%d", m_qmInfo.QM.numPlayers);
  1801. msg.append(buf);
  1802. _snprintf(buf, 63, "\\Pings\\%s", m_qmInfo.QM.pings);
  1803. msg.append(buf);
  1804. _snprintf(buf, 63, "\\IP\\%d", ntohl(peerGetLocalIP(peer)));// not ntohl(localIP), as we need EXTERNAL address for proper NAT negotiation!
  1805. msg.append(buf);
  1806. _snprintf(buf, 63, "\\Side\\%d", m_qmInfo.QM.side);
  1807. msg.append(buf);
  1808. _snprintf(buf, 63, "\\Color\\%d", m_qmInfo.QM.color);
  1809. msg.append(buf);
  1810. _snprintf(buf, 63, "\\NAT\\%d", m_qmInfo.QM.NAT);
  1811. msg.append(buf);
  1812. _snprintf(buf, 63, "\\EXE\\%d", m_qmInfo.QM.exeCRC);
  1813. msg.append(buf);
  1814. _snprintf(buf, 63, "\\INI\\%d", m_qmInfo.QM.iniCRC);
  1815. msg.append(buf);
  1816. buf[0] = 0;
  1817. msg.append("\\Maps\\");
  1818. for (Int i=0; i<m_qmInfo.qmMaps.size(); ++i)
  1819. {
  1820. if (m_qmInfo.qmMaps[i])
  1821. msg.append("1");
  1822. else
  1823. msg.append("0");
  1824. }
  1825. DEBUG_LOG(("Sending QM options of [%s] to %s\n", msg.c_str(), m_matchbotName.c_str()));
  1826. peerMessagePlayer( peer, m_matchbotName.c_str(), msg.c_str(), NormalMessage );
  1827. m_qmStatus = QM_WORKING;
  1828. PeerResponse resp;
  1829. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  1830. resp.qmStatus.status = QM_SENTINFO;
  1831. TheGameSpyPeerMessageQueue->addResponse(resp);
  1832. }
  1833. else
  1834. {
  1835. // no QM bot. Bail.
  1836. PeerResponse resp;
  1837. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  1838. resp.qmStatus.status = QM_COULDNOTFINDBOT;
  1839. TheGameSpyPeerMessageQueue->addResponse(resp);
  1840. m_qmStatus = QM_STOPPED;
  1841. peerLeaveRoom(peer, GroupRoom, "");
  1842. done = true;
  1843. }
  1844. }
  1845. }
  1846. break;
  1847. case QM_WORKING:
  1848. {
  1849. }
  1850. break;
  1851. case QM_MATCHED:
  1852. {
  1853. // leave QM channel, and clean up. Our work here is done.
  1854. peerLeaveRoom( peer, GroupRoom, NULL );
  1855. peerLeaveRoom( peer, StagingRoom, NULL ); m_isHosting = false;
  1856. m_qmStatus = QM_STOPPED;
  1857. peerLeaveRoom(peer, GroupRoom, "");
  1858. done = true;
  1859. }
  1860. break;
  1861. case QM_INCHANNEL:
  1862. {
  1863. }
  1864. break;
  1865. case QM_NEGOTIATINGFIREWALLS:
  1866. {
  1867. }
  1868. break;
  1869. case QM_STARTINGGAME:
  1870. {
  1871. }
  1872. break;
  1873. case QM_COULDNOTFINDCHANNEL:
  1874. {
  1875. }
  1876. break;
  1877. case QM_COULDNOTNEGOTIATEFIREWALLS:
  1878. {
  1879. }
  1880. break;
  1881. }
  1882. }
  1883. }
  1884. }
  1885. updateBuddyStatus( BUDDY_ONLINE );
  1886. }
  1887. static void getPlayerProfileIDCallback(PEER peer, PEERBool success, const char * nick, int profileID, void * param)
  1888. {
  1889. if (success && param != NULL)
  1890. {
  1891. *((Int *)param) = profileID;
  1892. }
  1893. }
  1894. static void stagingRoomPlayerEnum( PEER peer, PEERBool success, RoomType roomType, int index, const char * nick, int flags, void * param )
  1895. {
  1896. DEBUG_LOG(("Enum: success=%d, index=%d, nick=%s, flags=%d\n", success, index, nick, flags));
  1897. if (!nick || !success)
  1898. return;
  1899. Int id = 0;
  1900. peerGetPlayerProfileID(peer, nick, getPlayerProfileIDCallback, &id, PEERTrue);
  1901. DEBUG_ASSERTCRASH(id != 0, ("Failed to fetch player ID!"));
  1902. PeerResponse *resp = (PeerResponse *)param;
  1903. if (flags & PEER_FLAG_OP)
  1904. {
  1905. resp->joinStagingRoom.isHostPresent = TRUE;
  1906. }
  1907. if (index < MAX_SLOTS)
  1908. {
  1909. resp->stagingRoomPlayerNames[index] = nick;
  1910. }
  1911. if (id)
  1912. {
  1913. PSRequest req;
  1914. req.requestType = PSRequest::PSREQUEST_READPLAYERSTATS;
  1915. req.player.id = id;
  1916. TheGameSpyPSMessageQueue->addRequest(req);
  1917. }
  1918. }
  1919. static void joinRoomCallback(PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void *param)
  1920. {
  1921. DEBUG_LOG(("JoinRoomCallback: success==%d, result==%d\n", success, result));
  1922. PeerThreadClass *t = (PeerThreadClass *)param;
  1923. if (!t)
  1924. return;
  1925. DEBUG_LOG(("Room id was %d from thread %X\n", t->getLocalRoomID(), t));
  1926. DEBUG_LOG(("Current staging server name is [%ls]\n", t->getLocalStagingServerName().c_str()));
  1927. DEBUG_LOG(("Room type is %d (GroupRoom=%d, StagingRoom=%d, TitleRoom=%d)\n", roomType, GroupRoom, StagingRoom, TitleRoom));
  1928. #ifdef USE_BROADCAST_KEYS
  1929. if (success)
  1930. {
  1931. t->pushStatsToRoom(peer);
  1932. t->getStatsFromRoom(peer, roomType);
  1933. }
  1934. #endif // USE_BROADCAST_KEYS
  1935. switch (roomType)
  1936. {
  1937. case GroupRoom:
  1938. {
  1939. #ifdef USE_BROADCAST_KEYS
  1940. t->clearPlayerStats(GroupRoom);
  1941. #endif // USE_BROADCAST_KEYS
  1942. PeerResponse resp;
  1943. resp.peerResponseType = PeerResponse::PEERRESPONSE_JOINGROUPROOM;
  1944. resp.joinGroupRoom.id = t->getLocalRoomID();
  1945. resp.joinGroupRoom.ok = success;
  1946. TheGameSpyPeerMessageQueue->addResponse(resp);
  1947. t->roomJoined(success == PEERTrue);
  1948. DEBUG_LOG(("Entered group room %d, qm is %d\n", t->getLocalRoomID(), t->getQMGroupRoom()));
  1949. if ((!t->getQMGroupRoom()) || (t->getQMGroupRoom() != t->getLocalRoomID()))
  1950. {
  1951. DEBUG_LOG(("Updating buddy status\n"));
  1952. updateBuddyStatus( BUDDY_LOBBY, t->getLocalRoomID() );
  1953. }
  1954. }
  1955. break;
  1956. case StagingRoom:
  1957. {
  1958. #ifdef USE_BROADCAST_KEYS
  1959. t->clearPlayerStats(StagingRoom);
  1960. #endif // USE_BROADCAST_KEYS
  1961. PeerResponse resp;
  1962. resp.peerResponseType = PeerResponse::PEERRESPONSE_JOINSTAGINGROOM;
  1963. resp.joinStagingRoom.id = t->getLocalRoomID();
  1964. resp.joinStagingRoom.ok = success;
  1965. resp.joinStagingRoom.result = result;
  1966. if (success)
  1967. {
  1968. DEBUG_LOG(("joinRoomCallback() - game name is now '%ls'\n", t->getLocalStagingServerName().c_str()));
  1969. updateBuddyStatus( BUDDY_STAGING, 0, WideCharStringToMultiByte(t->getLocalStagingServerName().c_str()) );
  1970. }
  1971. resp.joinStagingRoom.isHostPresent = FALSE;
  1972. DEBUG_LOG(("Enum of staging room players\n"));
  1973. peerEnumPlayers(peer, StagingRoom, stagingRoomPlayerEnum, &resp);
  1974. DEBUG_LOG(("Host %s present\n", (resp.joinStagingRoom.isHostPresent)?"is":"is not"));
  1975. TheGameSpyPeerMessageQueue->addResponse(resp);
  1976. }
  1977. break;
  1978. }
  1979. }
  1980. // Gets called once for each group room when listing group rooms.
  1981. // After this has been called for each group room, it will be
  1982. // called one more time with groupID==0 and name==NULL.
  1983. /////////////////////////////////////////////////////////////////
  1984. static void listGroupRoomsCallback(PEER peer, PEERBool success,
  1985. int groupID, SBServer server,
  1986. const char * name, int numWaiting,
  1987. int maxWaiting, int numGames,
  1988. int numPlaying, void * param)
  1989. {
  1990. DEBUG_LOG(("listGroupRoomsCallback, success=%d, server=%X, groupID=%d\n", success, server, groupID));
  1991. #ifdef SERVER_DEBUGGING
  1992. CheckServers(peer);
  1993. #endif // SERVER_DEBUGGING
  1994. PeerThreadClass *t = (PeerThreadClass *)param;
  1995. if (!t)
  1996. {
  1997. DEBUG_LOG(("No thread! Bailing!\n"));
  1998. return;
  1999. }
  2000. if (success)
  2001. {
  2002. DEBUG_LOG(("Saw group room of %d (%s) at address %X %X\n", groupID, name, server, (server)?server->keyvals:0));
  2003. PeerResponse resp;
  2004. resp.peerResponseType = PeerResponse::PEERRESPONSE_GROUPROOM;
  2005. resp.groupRoom.id = groupID;
  2006. resp.groupRoom.numWaiting = numWaiting;
  2007. resp.groupRoom.maxWaiting = maxWaiting;
  2008. resp.groupRoom.numGames = numGames;
  2009. resp.groupRoom.numPlaying = numPlaying;
  2010. if (name)
  2011. {
  2012. resp.groupRoomName = name;
  2013. //t->setQMGroupRoom(groupID);
  2014. }
  2015. else
  2016. {
  2017. resp.groupRoomName.empty();
  2018. }
  2019. TheGameSpyPeerMessageQueue->addResponse(resp);
  2020. #ifdef SERVER_DEBUGGING
  2021. CheckServers(peer);
  2022. DEBUG_LOG(("\n"));
  2023. #endif // SERVER_DEBUGGING
  2024. }
  2025. else
  2026. {
  2027. DEBUG_LOG(("Failure!\n"));
  2028. }
  2029. }
  2030. void PeerThreadClass::connectCallback( PEER peer, PEERBool success )
  2031. {
  2032. PeerResponse resp;
  2033. if(!success)
  2034. {
  2035. //updateBuddyStatus( BUDDY_OFFLINE );
  2036. resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT;
  2037. resp.discon.reason = DISCONNECT_COULDNOTCONNECT;
  2038. TheGameSpyPeerMessageQueue->addResponse(resp);
  2039. return;
  2040. }
  2041. updateBuddyStatus( BUDDY_ONLINE );
  2042. m_isConnected = true;
  2043. DEBUG_LOG(("Connected as profile %d (%s)\n", m_profileID, m_loginName.c_str()));
  2044. resp.peerResponseType = PeerResponse::PEERRESPONSE_LOGIN;
  2045. resp.player.profileID = m_profileID;
  2046. resp.nick = m_loginName;
  2047. GetLocalChatConnectionAddress("peerchat.gamespy.com", 6667, localIP);
  2048. chatSetLocalIP(localIP);
  2049. resp.player.internalIP = ntohl(localIP);
  2050. resp.player.externalIP = ntohl(peerGetLocalIP(peer));
  2051. TheGameSpyPeerMessageQueue->addResponse(resp);
  2052. PSRequest psReq;
  2053. psReq.requestType = PSRequest::PSREQUEST_READPLAYERSTATS;
  2054. psReq.player.id = m_profileID;
  2055. psReq.nick = m_originalName;
  2056. psReq.email = m_email;
  2057. psReq.password = m_password;
  2058. TheGameSpyPSMessageQueue->addRequest(psReq);
  2059. #ifdef SERVER_DEBUGGING
  2060. DEBUG_LOG(("Before peerListGroupRooms()\n"));
  2061. CheckServers(peer);
  2062. #endif // SERVER_DEBUGGING
  2063. peerListGroupRooms( peer, NULL, listGroupRoomsCallback, this, PEERTrue );
  2064. #ifdef SERVER_DEBUGGING
  2065. DEBUG_LOG(("After peerListGroupRooms()\n"));
  2066. CheckServers(peer);
  2067. #endif // SERVER_DEBUGGING
  2068. }
  2069. void PeerThreadClass::nickErrorCallback( PEER peer, Int type, const char *nick )
  2070. {
  2071. if(type == PEER_IN_USE)
  2072. {
  2073. Int len = strlen(nick);
  2074. std::string nickStr = nick;
  2075. Int newVal = 0;
  2076. if (nick[len-1] == '}' && nick[len-3] == '{' && isdigit(nick[len-2]))
  2077. {
  2078. newVal = nick[len-2] - '0' + 1;
  2079. nickStr.erase(len-3, 3);
  2080. }
  2081. DEBUG_LOG(("Nickname taken: was %s, new val = %d, new nick = %s\n", nick, newVal, nickStr.c_str()));
  2082. if (newVal < 10)
  2083. {
  2084. nickStr.append("{");
  2085. char tmp[2];
  2086. tmp[0] = '0'+newVal;
  2087. tmp[1] = '\0';
  2088. nickStr.append(tmp);
  2089. nickStr.append("}");
  2090. // Retry the connect with a similar nick.
  2091. m_loginName = nickStr;
  2092. peerRetryWithNick(peer, nickStr.c_str());
  2093. }
  2094. else
  2095. {
  2096. PeerResponse resp;
  2097. resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT;
  2098. resp.discon.reason = DISCONNECT_NICKTAKEN;
  2099. TheGameSpyPeerMessageQueue->addResponse(resp);
  2100. // Cancel the connect.
  2101. peerRetryWithNick(peer, NULL);
  2102. }
  2103. }
  2104. else
  2105. {
  2106. PeerResponse resp;
  2107. resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT;
  2108. resp.discon.reason = DISCONNECT_BADNICK;
  2109. TheGameSpyPeerMessageQueue->addResponse(resp);
  2110. // Cancel the connect.
  2111. peerRetryWithNick(peer, NULL);
  2112. }
  2113. }
  2114. void disconnectedCallback(PEER peer, const char * reason, void * param)
  2115. {
  2116. DEBUG_LOG(("disconnectedCallback(): reason was '%s'\n", reason));
  2117. PeerThreadClass *t = (PeerThreadClass *)param;
  2118. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2119. if (t)
  2120. t->markAsDisconnected();
  2121. //updateBuddyStatus( BUDDY_OFFLINE );
  2122. PeerResponse resp;
  2123. resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT;
  2124. resp.discon.reason = DISCONNECT_LOSTCON;
  2125. SerialAuthResult res = TheGameSpyPeerMessageQueue->getSerialAuthResult();
  2126. switch (res)
  2127. {
  2128. case SERIAL_NONEXISTENT:
  2129. resp.discon.reason = DISCONNECT_SERIAL_NOT_PRESENT;
  2130. break;
  2131. case SERIAL_AUTHFAILED:
  2132. resp.discon.reason = DISCONNECT_SERIAL_INVALID;
  2133. break;
  2134. case SERIAL_BANNED:
  2135. resp.discon.reason = DISCONNECT_SERIAL_BANNED;
  2136. break;
  2137. }
  2138. TheGameSpyPeerMessageQueue->addResponse(resp);
  2139. }
  2140. void roomMessageCallback(PEER peer, RoomType roomType, const char * nick, const char * message, MessageType messageType, void * param)
  2141. {
  2142. PeerResponse resp;
  2143. resp.peerResponseType = PeerResponse::PEERRESPONSE_MESSAGE;
  2144. resp.nick = nick;
  2145. resp.text = MultiByteToWideCharSingleLine(message);
  2146. resp.message.isPrivate = FALSE;
  2147. resp.message.isAction = (messageType == ActionMessage);
  2148. TheGameSpyPeerMessageQueue->addResponse(resp);
  2149. DEBUG_LOG(("Saw text [%hs] (%ls) %d chars Orig was %s (%d chars)\n", nick, resp.text.c_str(), resp.text.length(), message, strlen(message)));
  2150. UnsignedInt IP;
  2151. peerGetPlayerInfoNoWait(peer, nick, &IP, &resp.message.profileID);
  2152. PeerThreadClass *t = (PeerThreadClass *)param;
  2153. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2154. if (t && (t->getQMStatus() != QM_IDLE && t->getQMStatus() != QM_STOPPED))
  2155. {
  2156. if (resp.message.profileID == matchbotProfileID)
  2157. {
  2158. char *lastStr = NULL;
  2159. char *cmd = strtok_r((char *)message, " ", &lastStr);
  2160. if ( cmd && strcmp(cmd, "MBOT:POOLSIZE") == 0 )
  2161. {
  2162. Int poolSize = 0;
  2163. while (1)
  2164. {
  2165. char *poolStr = strtok_r(NULL, " ", &lastStr);
  2166. char *sizeStr = strtok_r(NULL, " ", &lastStr);
  2167. if (poolStr && sizeStr)
  2168. {
  2169. Int pool = atoi(poolStr);
  2170. Int size = atoi(sizeStr);
  2171. if (pool == t->getQMLadder())
  2172. {
  2173. poolSize = size;
  2174. break;
  2175. }
  2176. }
  2177. else
  2178. break;
  2179. }
  2180. PeerResponse resp;
  2181. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  2182. resp.qmStatus.status = QM_POOLSIZE;
  2183. resp.qmStatus.poolSize = poolSize;
  2184. TheGameSpyPeerMessageQueue->addResponse(resp);
  2185. }
  2186. }
  2187. }
  2188. }
  2189. void gameStartedCallback( PEER peer, UnsignedInt IP, const char *message, void *param )
  2190. {
  2191. PeerResponse resp;
  2192. resp.peerResponseType = PeerResponse::PEERRESPONSE_GAMESTART;
  2193. TheGameSpyPeerMessageQueue->addResponse(resp);
  2194. }
  2195. void playerMessageCallback(PEER peer, const char * nick, const char * message, MessageType messageType, void * param)
  2196. {
  2197. PeerResponse resp;
  2198. resp.peerResponseType = PeerResponse::PEERRESPONSE_MESSAGE;
  2199. resp.nick = nick;
  2200. resp.text = MultiByteToWideCharSingleLine(message);
  2201. resp.message.isPrivate = TRUE;
  2202. resp.message.isAction = (messageType == ActionMessage);
  2203. UnsignedInt IP;
  2204. peerGetPlayerInfoNoWait(peer, nick, &IP, &resp.message.profileID);
  2205. TheGameSpyPeerMessageQueue->addResponse(resp);
  2206. PeerThreadClass *t = (PeerThreadClass *)param;
  2207. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2208. if (t && (t->getQMStatus() != QM_IDLE && t->getQMStatus() != QM_STOPPED))
  2209. {
  2210. if (resp.message.isPrivate && resp.message.profileID == matchbotProfileID)
  2211. {
  2212. char *lastStr = NULL;
  2213. char *cmd = strtok_r((char *)message, " ", &lastStr);
  2214. if ( cmd && strcmp(cmd, "MBOT:MATCHED") == 0 )
  2215. {
  2216. char *mapNumStr = strtok_r(NULL, " ", &lastStr);
  2217. char *seedStr = strtok_r(NULL, " ", &lastStr);
  2218. char *playerStr[MAX_SLOTS];
  2219. char *playerIPStr[MAX_SLOTS];
  2220. char *playerSideStr[MAX_SLOTS];
  2221. char *playerColorStr[MAX_SLOTS];
  2222. char *playerNATStr[MAX_SLOTS];
  2223. Int numPlayers = 0;
  2224. for (Int i=0; i<MAX_SLOTS; ++i)
  2225. {
  2226. playerStr[i] = strtok_r(NULL, " ", &lastStr);
  2227. playerIPStr[i] = strtok_r(NULL, " ", &lastStr);
  2228. playerSideStr[i] = strtok_r(NULL, " ", &lastStr);
  2229. playerColorStr[i] = strtok_r(NULL, " ", &lastStr);
  2230. playerNATStr[i] = strtok_r(NULL, " ", &lastStr);
  2231. if (playerNATStr[i])
  2232. {
  2233. ++numPlayers;
  2234. }
  2235. else
  2236. {
  2237. playerStr[i] = NULL;
  2238. playerIPStr[i] = NULL;
  2239. playerSideStr[i] = NULL;
  2240. playerColorStr[i] = NULL;
  2241. playerNATStr[i] = NULL;
  2242. }
  2243. }
  2244. if (numPlayers > 1)
  2245. {
  2246. // woohoo! got everything needed for a match!
  2247. DEBUG_LOG(("Saw %d-player QM match: map index = %s, seed = %s\n", numPlayers, mapNumStr, seedStr));
  2248. t->handleQMMatch(peer, atoi(mapNumStr), atoi(seedStr), playerStr, playerIPStr, playerSideStr, playerColorStr, playerNATStr);
  2249. }
  2250. }
  2251. else if ( cmd && strcmp(cmd, "MBOT:WORKING") == 0 )
  2252. {
  2253. Int poolSize = 0;
  2254. char *poolStr = strtok_r(NULL, " ", &lastStr);
  2255. if (poolStr)
  2256. poolSize = atoi(poolStr);
  2257. PeerResponse resp;
  2258. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  2259. resp.qmStatus.status = QM_WORKING;
  2260. resp.qmStatus.poolSize = poolSize;
  2261. TheGameSpyPeerMessageQueue->addResponse(resp);
  2262. }
  2263. else if ( cmd && strcmp(cmd, "MBOT:WIDENINGSEARCH") == 0 )
  2264. {
  2265. PeerResponse resp;
  2266. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  2267. resp.qmStatus.status = QM_WIDENINGSEARCH;
  2268. TheGameSpyPeerMessageQueue->addResponse(resp);
  2269. }
  2270. }
  2271. }
  2272. }
  2273. void roomUTMCallback(PEER peer, RoomType roomType, const char * nick, const char * command, const char * parameters, PEERBool authenticated, void * param)
  2274. {
  2275. DEBUG_LOG(("roomUTMCallback: %s says %s = [%s]\n", nick, command, parameters));
  2276. if (roomType != StagingRoom)
  2277. return;
  2278. PeerResponse resp;
  2279. resp.peerResponseType = PeerResponse::PEERRESPONSE_ROOMUTM;
  2280. resp.nick = nick;
  2281. resp.command = command;
  2282. resp.commandOptions = parameters;
  2283. TheGameSpyPeerMessageQueue->addResponse(resp);
  2284. }
  2285. void playerUTMCallback(PEER peer, const char * nick, const char * command, const char * parameters, PEERBool authenticated, void * param)
  2286. {
  2287. DEBUG_LOG(("playerUTMCallback: %s says %s = [%s]\n", nick, command, parameters));
  2288. PeerResponse resp;
  2289. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERUTM;
  2290. resp.nick = nick;
  2291. resp.command = command;
  2292. resp.commandOptions = parameters;
  2293. TheGameSpyPeerMessageQueue->addResponse(resp);
  2294. }
  2295. static void getPlayerInfo(PeerThreadClass *t, PEER peer, const char *nick, Int& id, UnsignedInt& IP,
  2296. std::string& locale, Int& wins, Int& losses, Int& rankPoints, Int& side, Int& preorder,
  2297. RoomType roomType, Int& flags)
  2298. {
  2299. if (!t || !nick)
  2300. return;
  2301. peerGetPlayerInfoNoWait(peer, nick, &IP, &id);
  2302. #ifdef USE_BROADCAST_KEYS
  2303. //locale.printf
  2304. Int localeIndex = t->lookupStatForPlayer(roomType, nick, "b_locale");
  2305. AsciiString tmp;
  2306. tmp.format("%d", localeIndex);
  2307. locale = tmp.str();
  2308. wins = t->lookupStatForPlayer(roomType, nick, "b_wins");
  2309. losses = t->lookupStatForPlayer(roomType, nick, "b_losses");
  2310. rankPoints = t->lookupStatForPlayer(roomType, nick, "b_points");
  2311. side = t->lookupStatForPlayer(roomType, nick, "b_side");
  2312. preorder = t->lookupStatForPlayer(roomType, nick, "b_pre");
  2313. #else // USE_BROADCAST_KEYS
  2314. const char *s;
  2315. s = peerGetGlobalWatchKey(peer, nick, "locale");
  2316. locale = (s)?s:"";
  2317. s = peerGetGlobalWatchKey(peer, nick, "wins");
  2318. wins = atoi((s)?s:"");
  2319. s = peerGetGlobalWatchKey(peer, nick, "losses");
  2320. losses = atoi((s)?s:"");
  2321. s = peerGetGlobalWatchKey(peer, nick, "points");
  2322. rankPoints = atoi((s)?s:"");
  2323. s = peerGetGlobalWatchKey(peer, nick, "side");
  2324. side = atoi((s)?s:"");
  2325. s = peerGetGlobalWatchKey(peer, nick, "pre");
  2326. preorder = atoi((s)?s:"");
  2327. #endif // USE_BROADCAST_KEYS
  2328. flags = 0;
  2329. peerGetPlayerFlags(peer, nick, roomType, &flags);
  2330. DEBUG_LOG(("getPlayerInfo(%d) - %s has locale %s, wins:%d, losses:%d, rankPoints:%d, side:%d, preorder:%d\n",
  2331. id, nick, locale.c_str(), wins, losses, rankPoints, side, preorder));
  2332. }
  2333. static void roomKeyChangedCallback(PEER peer, RoomType roomType, const char *nick, const char *key, const char *val, void *param)
  2334. {
  2335. #ifdef USE_BROADCAST_KEYS
  2336. PeerThreadClass *t = (PeerThreadClass *)param;
  2337. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2338. if (!t || !nick || !key || !val)
  2339. {
  2340. DEBUG_ASSERTCRASH(nick && strcmp(nick,"(END)")==0, ("roomKeyChangedCallback bad values = nick:%X:%s, key:%X:%s, val:%X:%s\n", nick, nick, key, key, val, val));
  2341. return;
  2342. }
  2343. #ifdef DEBUG_LOGGING
  2344. if (strcmp(key, "username") && strcmp(key, "b_flags"))
  2345. {
  2346. DEBUG_LOG(("roomKeyChangedCallback() - %s set %s=%s\n", nick, key, val));
  2347. }
  2348. #endif
  2349. t->trackStatsForPlayer(roomType, nick, key, val);
  2350. PeerResponse resp;
  2351. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERINFO;
  2352. resp.nick = nick;
  2353. resp.player.roomType = roomType;
  2354. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2355. resp.locale, resp.player.wins, resp.player.losses,
  2356. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2357. resp.player.roomType, resp.player.flags);
  2358. TheGameSpyPeerMessageQueue->addResponse(resp);
  2359. #endif // USE_BROADCAST_KEYS
  2360. }
  2361. #ifdef USE_BROADCAST_KEYS
  2362. void getRoomKeysCallback(PEER peer, PEERBool success, RoomType roomType, const char *nick, int num, char **keys, char **values, void *param)
  2363. {
  2364. PeerThreadClass *t = (PeerThreadClass *)param;
  2365. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2366. if (!t || !nick || !num || !success || !keys || !values)
  2367. {
  2368. DEBUG_ASSERTCRASH(!nick || strcmp(nick,"(END)")==0, ("getRoomKeysCallback bad key/value %X/%X, nick=%s", keys, values, nick));
  2369. return;
  2370. }
  2371. for (Int i=0; i<num; ++i)
  2372. {
  2373. t->trackStatsForPlayer(roomType, nick, keys[i], values[i]);
  2374. }
  2375. PeerResponse resp;
  2376. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERINFO;
  2377. resp.nick = nick;
  2378. resp.player.roomType = roomType;
  2379. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2380. resp.locale, resp.player.wins, resp.player.losses,
  2381. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2382. resp.player.roomType, resp.player.flags);
  2383. TheGameSpyPeerMessageQueue->addResponse(resp);
  2384. }
  2385. #endif // USE_BROADCAST_KEYS
  2386. static void globalKeyChangedCallback(PEER peer, const char *nick, const char *key, const char *val, void *param)
  2387. {
  2388. if (!nick)
  2389. return;
  2390. PeerThreadClass *t = (PeerThreadClass *)param;
  2391. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2392. if (!t)
  2393. return;
  2394. PeerResponse resp;
  2395. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERINFO;
  2396. resp.nick = nick;
  2397. resp.player.roomType = t->getCurrentGroupRoom()?GroupRoom:StagingRoom;
  2398. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2399. resp.locale, resp.player.wins, resp.player.losses,
  2400. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2401. resp.player.roomType, resp.player.flags);
  2402. TheGameSpyPeerMessageQueue->addResponse(resp);
  2403. }
  2404. void playerJoinedCallback(PEER peer, RoomType roomType, const char * nick, void * param)
  2405. {
  2406. if (!nick)
  2407. return;
  2408. PeerThreadClass *t = (PeerThreadClass *)param;
  2409. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2410. if (!t)
  2411. return;
  2412. PeerResponse resp;
  2413. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERJOIN;
  2414. resp.nick = nick;
  2415. resp.player.roomType = roomType;
  2416. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2417. resp.locale, resp.player.wins, resp.player.losses,
  2418. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2419. roomType, resp.player.flags);
  2420. TheGameSpyPeerMessageQueue->addResponse(resp);
  2421. }
  2422. void playerLeftCallback(PEER peer, RoomType roomType, const char * nick, const char * reason, void * param)
  2423. {
  2424. PeerResponse resp;
  2425. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERLEFT;
  2426. resp.nick = nick;
  2427. resp.player.roomType = roomType;
  2428. resp.player.profileID = 0;
  2429. PeerThreadClass *t = (PeerThreadClass *)param;
  2430. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2431. if (!t)
  2432. return;
  2433. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2434. resp.locale, resp.player.wins, resp.player.losses,
  2435. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2436. roomType, resp.player.flags);
  2437. TheGameSpyPeerMessageQueue->addResponse(resp);
  2438. // PeerThreadClass *t = (PeerThreadClass *)param;
  2439. // DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2440. if (t->getQMStatus() != QM_IDLE && t->getQMStatus() != QM_STOPPED)
  2441. {
  2442. if (!stricmp(t->getQMBotName().c_str(), nick))
  2443. {
  2444. // matchbot left - bail
  2445. PeerResponse resp;
  2446. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  2447. resp.qmStatus.status = QM_COULDNOTFINDBOT;
  2448. TheGameSpyPeerMessageQueue->addResponse(resp);
  2449. PeerRequest req;
  2450. req.peerRequestType = PeerRequest::PEERREQUEST_STOPQUICKMATCH;
  2451. TheGameSpyPeerMessageQueue->addRequest(req);
  2452. }
  2453. }
  2454. }
  2455. void playerChangedNickCallback(PEER peer, RoomType roomType, const char * oldNick, const char * newNick, void * param)
  2456. {
  2457. PeerResponse resp;
  2458. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERCHANGEDNICK;
  2459. resp.nick = newNick;
  2460. resp.oldNick = oldNick;
  2461. resp.player.roomType = roomType;
  2462. PeerThreadClass *t = (PeerThreadClass *)param;
  2463. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2464. if (!t)
  2465. return;
  2466. getPlayerInfo(t, peer, newNick, resp.player.profileID, resp.player.IP,
  2467. resp.locale, resp.player.wins, resp.player.losses,
  2468. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2469. roomType, resp.player.flags);
  2470. TheGameSpyPeerMessageQueue->addResponse(resp);
  2471. }
  2472. static void playerInfoCallback(PEER peer, RoomType roomType, const char * nick, unsigned int IP, int profileID, void * param)
  2473. {
  2474. if (!nick)
  2475. return;
  2476. PeerResponse resp;
  2477. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERINFO;
  2478. resp.nick = nick;
  2479. resp.player.roomType = roomType;
  2480. PeerThreadClass *t = (PeerThreadClass *)param;
  2481. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2482. if (!t)
  2483. return;
  2484. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2485. resp.locale, resp.player.wins, resp.player.losses,
  2486. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2487. roomType, resp.player.flags);
  2488. DEBUG_LOG(("**GS playerInfoCallback name=%s, local=%s\n", nick, resp.locale.c_str() ));
  2489. TheGameSpyPeerMessageQueue->addResponse(resp);
  2490. }
  2491. static void playerFlagsChangedCallback(PEER peer, RoomType roomType, const char * nick, int oldFlags, int newFlags, void * param)
  2492. {
  2493. if (!nick)
  2494. return;
  2495. PeerResponse resp;
  2496. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERCHANGEDFLAGS;
  2497. resp.nick = nick;
  2498. resp.player.roomType = roomType;
  2499. PeerThreadClass *t = (PeerThreadClass *)param;
  2500. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2501. if (!t)
  2502. return;
  2503. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2504. resp.locale, resp.player.wins, resp.player.losses,
  2505. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2506. roomType, resp.player.flags);
  2507. TheGameSpyPeerMessageQueue->addResponse(resp);
  2508. }
  2509. #ifdef DEBUG_LOGGING
  2510. /*
  2511. static void enumFunc(char *key, char *val, void *param)
  2512. {
  2513. DEBUG_LOG((" [%s] = [%s]\n", key, val));
  2514. }
  2515. */
  2516. #endif
  2517. static void listingGamesCallback(PEER peer, PEERBool success, const char * name, SBServer server, PEERBool staging, int msg, Int percentListed, void * param)
  2518. {
  2519. PeerThreadClass *t = (PeerThreadClass *)param;
  2520. if (!t || !success)
  2521. return;
  2522. #ifdef DEBUG_LOGGING
  2523. AsciiString cmdStr = "<Unknown>";
  2524. switch(msg)
  2525. {
  2526. case PEER_ADD:
  2527. cmdStr = "PEER_ADD";
  2528. break;
  2529. case PEER_UPDATE:
  2530. cmdStr = "PEER_UPDATE";
  2531. break;
  2532. case PEER_REMOVE:
  2533. cmdStr = "PEER_REMOVE";
  2534. break;
  2535. case PEER_CLEAR:
  2536. cmdStr = "PEER_CLEAR";
  2537. break;
  2538. case PEER_COMPLETE:
  2539. cmdStr = "PEER_COMPLETE";
  2540. break;
  2541. }
  2542. DEBUG_LOG(("listingGamesCallback() - doing command %s on server %X\n", cmdStr.str(), server));
  2543. #endif // DEBUG_LOGGING
  2544. // PeerThreadClass *t = (PeerThreadClass *)param;
  2545. DEBUG_ASSERTCRASH(name || msg==PEER_CLEAR || msg==PEER_COMPLETE, ("Game has no name!\n"));
  2546. if (!t || !success || (!name && (msg == PEER_ADD || msg == PEER_UPDATE)))
  2547. {
  2548. DEBUG_LOG(("Bailing from listingGamesCallback() - success=%d, name=%X, server=%X, msg=%X\n", success, name, server, msg));
  2549. return;
  2550. }
  2551. if (!name)
  2552. name = "bogus";
  2553. if (server && (msg == PEER_ADD || msg == PEER_UPDATE))
  2554. {
  2555. DEBUG_ASSERTCRASH(server->keyvals, ("Looking at an already-freed server for msg type %d!", msg));
  2556. if (!server->keyvals)
  2557. {
  2558. msg = PEER_REMOVE;
  2559. }
  2560. }
  2561. if (server && success && (msg == PEER_ADD || msg == PEER_UPDATE))
  2562. {
  2563. DEBUG_LOG(("Game name is '%s'\n", name));
  2564. const char *newname = SBServerGetStringValue(server, "gamename", (char *)name);
  2565. if (strcmp(newname, "ccgenzh"))
  2566. name = newname;
  2567. DEBUG_LOG(("Game name is now '%s'\n", name));
  2568. }
  2569. DEBUG_LOG(("listingGamesCallback - got percent complete %d\n", percentListed));
  2570. if (percentListed == 100)
  2571. {
  2572. if (!t->getSawCompleteGameList())
  2573. {
  2574. t->setSawCompleteGameList(TRUE);
  2575. PeerResponse completeResp;
  2576. completeResp.peerResponseType = PeerResponse::PEERRESPONSE_STAGINGROOMLISTCOMPLETE;
  2577. TheGameSpyPeerMessageQueue->addResponse(completeResp);
  2578. }
  2579. }
  2580. AsciiString gameName = name;
  2581. AsciiString tmp = gameName;
  2582. AsciiString hostName;
  2583. tmp.nextToken(&hostName, " ");
  2584. const char *firstSpace = gameName.find(' ');
  2585. if(firstSpace)
  2586. {
  2587. gameName.set(firstSpace + 1);
  2588. //gameName.trim();
  2589. DEBUG_LOG(("Hostname/Gamename split leaves '%s' hosting '%s'\n", hostName.str(), gameName.str()));
  2590. }
  2591. PeerResponse resp;
  2592. resp.peerResponseType = PeerResponse::PEERRESPONSE_STAGINGROOM;
  2593. resp.stagingRoom.action = msg;
  2594. resp.stagingRoom.isStaging = staging;
  2595. resp.stagingRoom.percentComplete = percentListed;
  2596. if (server && (msg == PEER_ADD || msg == PEER_UPDATE))
  2597. {
  2598. Bool hasPassword = (Bool)SBServerGetIntValue(server, PW_STR, FALSE);
  2599. Bool allowObservers = (Bool)SBServerGetIntValue(server, OBS_STR, FALSE);
  2600. Bool usesStats = (Bool)SBServerGetIntValue(server, USE_STATS_STR, TRUE);
  2601. const char *verStr = SBServerGetStringValue(server, "gamever", "000000");
  2602. const char *exeStr = SBServerGetStringValue(server, EXECRC_STR, "000000");
  2603. const char *iniStr = SBServerGetStringValue(server, INICRC_STR, "000000");
  2604. const char *ladIPStr = SBServerGetStringValue(server, LADIP_STR, "000000");
  2605. const char *pingStr = SBServerGetStringValue(server, PINGSTR_STR, "FFFFFFFFFFFFFFFF");
  2606. UnsignedShort ladPort = (UnsignedShort)SBServerGetIntValue(server, LADPORT_STR, 0);
  2607. UnsignedInt verVal = strtoul(verStr, NULL, 10);
  2608. UnsignedInt exeVal = strtoul(exeStr, NULL, 10);
  2609. UnsignedInt iniVal = strtoul(iniStr, NULL, 10);
  2610. resp.stagingRoom.requiresPassword = hasPassword;
  2611. resp.stagingRoom.allowObservers = allowObservers;
  2612. resp.stagingRoom.useStats = usesStats;
  2613. resp.stagingRoom.version = verVal;
  2614. resp.stagingRoom.exeCRC = exeVal;
  2615. resp.stagingRoom.iniCRC = iniVal;
  2616. resp.stagingServerLadderIP = ladIPStr;
  2617. resp.stagingServerPingString = pingStr;
  2618. resp.stagingRoom.ladderPort = ladPort;
  2619. resp.stagingRoom.numPlayers = SBServerGetIntValue(server, NUMPLAYER_STR, 0);
  2620. resp.stagingRoom.numObservers = SBServerGetIntValue(server, NUMOBS_STR, 0);
  2621. resp.stagingRoom.maxPlayers = SBServerGetIntValue(server, MAXPLAYER_STR, 8);
  2622. resp.stagingRoomMapName = SBServerGetStringValue(server, "mapname", "");
  2623. for (Int i=0; i<MAX_SLOTS; ++i)
  2624. {
  2625. resp.stagingRoomPlayerNames[i] = SBServerGetPlayerStringValue(server, i, NAME__STR, "");
  2626. resp.stagingRoom.wins[i] = SBServerGetPlayerIntValue(server, i, WINS__STR, 0);
  2627. resp.stagingRoom.losses[i] = SBServerGetPlayerIntValue(server, i, LOSSES__STR, 0);
  2628. resp.stagingRoom.profileID[i] = SBServerGetPlayerIntValue(server, i, "pid", 0);
  2629. resp.stagingRoom.color[i] = SBServerGetPlayerIntValue(server, i, COLOR__STR, 0);
  2630. resp.stagingRoom.faction[i] = SBServerGetPlayerIntValue(server, i, FACTION__STR, 0);
  2631. #ifdef DEBUG_LOGGING
  2632. if (resp.stagingRoomPlayerNames[i].length())
  2633. {
  2634. DEBUG_LOG(("Player %d raw stuff: [%s] [%d] [%d] [%d]\n", i, resp.stagingRoomPlayerNames[i].c_str(), resp.stagingRoom.wins[i], resp.stagingRoom.losses[i], resp.stagingRoom.profileID[i]));
  2635. }
  2636. #endif
  2637. }
  2638. if (resp.stagingRoomPlayerNames[0].empty())
  2639. {
  2640. resp.stagingRoomPlayerNames[0] = hostName.str();
  2641. }
  2642. DEBUG_ASSERTCRASH(resp.stagingRoomPlayerNames[0].empty() == false, ("No host!"));
  2643. DEBUG_LOG(("Raw stuff: [%s] [%s] [%s] [%d] [%d] [%d]\n", verStr, exeStr, iniStr, hasPassword, allowObservers, usesStats));
  2644. DEBUG_LOG(("Raw stuff: [%s] [%s] [%d]\n", pingStr, ladIPStr, ladPort));
  2645. DEBUG_LOG(("Saw game with stuff %s %d %X %X %X %s\n", resp.stagingRoomMapName.c_str(), hasPassword, verVal, exeVal, iniVal, SBServerGetStringValue(server, "password", "missing")));
  2646. #ifdef PING_TEST
  2647. PING_LOG(("%s\n", pingStr));
  2648. #endif
  2649. }
  2650. if (msg == PEER_ADD || msg == PEER_UPDATE)
  2651. {
  2652. if (!resp.stagingRoom.exeCRC || !resp.stagingRoom.iniCRC)
  2653. {
  2654. if (SBServerHasBasicKeys(server))
  2655. {
  2656. DEBUG_LOG(("Server %x does not have basic keys\n", server));
  2657. return;
  2658. }
  2659. else
  2660. {
  2661. DEBUG_LOG(("Server %x has basic keys, yet has no info\n", server));
  2662. }
  2663. if (msg == PEER_UPDATE)
  2664. {
  2665. PeerRequest req;
  2666. req.peerRequestType = PeerRequest::PEERREQUEST_GETEXTENDEDSTAGINGROOMINFO;
  2667. req.stagingRoom.id = t->findServer( server );
  2668. DEBUG_LOG(("Add/update a 0/0 server %X (%d, %s) - requesting full update to see if that helps.\n",
  2669. server, resp.stagingRoom.id, gameName.str()));
  2670. TheGameSpyPeerMessageQueue->addRequest(req);
  2671. }
  2672. return; // don't actually try to list it.
  2673. }
  2674. }
  2675. switch (msg)
  2676. {
  2677. case PEER_CLEAR:
  2678. t->clearServers();
  2679. break;
  2680. case PEER_ADD:
  2681. case PEER_UPDATE:
  2682. resp.stagingRoom.id = t->findServer( server );
  2683. DEBUG_LOG(("Add/update on server %X (%d, %s)\n", server, resp.stagingRoom.id, gameName.str()));
  2684. resp.stagingServerName = MultiByteToWideCharSingleLine( gameName.str() );
  2685. DEBUG_LOG(("Server had basic=%d, full=%d\n", SBServerHasBasicKeys(server), SBServerHasFullKeys(server)));
  2686. #ifdef DEBUG_LOGGING
  2687. //SBServerEnumKeys(server, enumFunc, NULL);
  2688. #endif
  2689. break;
  2690. case PEER_REMOVE:
  2691. DEBUG_LOG(("Removing server %X (%d)\n", server, resp.stagingRoom.id));
  2692. resp.stagingRoom.id = t->removeServerFromMap( server );
  2693. break;
  2694. }
  2695. TheGameSpyPeerMessageQueue->addResponse(resp);
  2696. }
  2697. //-------------------------------------------------------------------------