NetServer.cpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. // NetServer.cpp
  19. // Project: RSPiX
  20. //
  21. // History:
  22. // 09/01/97 MJR Nearing the end of a major overhaul.
  23. //
  24. // 09/06/97 MJR No longer responds to browse attempts once game starts.
  25. //
  26. // 09/07/97 MJR Added support for PROCEED and PROGRESS_REALM messages.
  27. //
  28. // 11/20/97 JMI Added support for new sCoopLevels & sCoopMode flag in
  29. // StartGame and SetupGame messages.
  30. //
  31. // 11/25/97 JMI Added determination between version conflicts and platform
  32. // conflicts. Also, added error propagation.
  33. //
  34. // 11/26/97 JMI Masking error in evaluation of version mismatch problem
  35. // such that platform mismatch was never detected.
  36. //
  37. ////////////////////////////////////////////////////////////////////////////////
  38. #include "RSPiX.h"
  39. #include "netserver.h"
  40. ////////////////////////////////////////////////////////////////////////////////
  41. // Startup
  42. ////////////////////////////////////////////////////////////////////////////////
  43. short CNetServer::Startup( // Returns 0 if successfull, non-zero otherwise
  44. unsigned short usPort, // In: Server base port number
  45. char* pszHostName, // In: Host name (max size is MaxHostName!!!)
  46. RSocket::BLOCK_CALLBACK callback) // In: Blocking callback
  47. {
  48. short sResult = 0;
  49. // Do a reset to be sure we're starting at a good point
  50. Reset();
  51. // Save base socket (all sockets are done as offsets from this one)
  52. m_usBasePort = usPort;
  53. // Save callback
  54. m_callback = callback;
  55. // Create a unique number that this host can use to identify itself when
  56. // it browses for hosts. We simply use total elapsed microseconds, which
  57. // is EXTREMELY LIKELY to be different for every host. We also look for
  58. // the correct host name, but of course, many hosts can have the same name.
  59. m_lHostMagic = rspGetMicroseconds();
  60. // Save name (truncating if necessary)
  61. strncpy(m_acHostName, pszHostName, Net::MaxHostNameSize);
  62. m_acHostName[Net::MaxHostNameSize-1] = 0;
  63. // Setup listen socket
  64. sResult = m_socketListen.Open(
  65. m_usBasePort + Net::ListenPortOffset,
  66. RSocket::typStream,
  67. RSocket::optDontWaitOnClose | RSocket::optDontCoalesce | RSocket::optDontBlock,
  68. callback);
  69. if (sResult == 0)
  70. {
  71. sResult = m_socketListen.Listen();
  72. if (sResult == 0)
  73. {
  74. // Setup antenna socket, on which we receive broadcasts from potential
  75. // clients browsing for a host.
  76. sResult = m_socketAntenna.Open(
  77. m_usBasePort + Net::AntennaPortOffset,
  78. RSocket::typDatagram,
  79. RSocket::optDontBlock,
  80. callback);
  81. if (sResult == 0)
  82. {
  83. // Must set broadcast mode even for sockets that are RECEIVING them. Doesn't
  84. // seem to make sense, but empericial results say we need to do this.
  85. sResult = m_socketAntenna.Broadcast();
  86. if (sResult == 0)
  87. {
  88. }
  89. else
  90. TRACE("CNetServer::Setup(): Error putting antenna socket into broadcast mode!\n");
  91. }
  92. else
  93. TRACE("CNetServer::Setup(): Error opening antenna socket!\n");
  94. }
  95. else
  96. TRACE("CNetServer::Setup(): Error putting listen socket into listen mode!\n");
  97. }
  98. else
  99. TRACE("CNetServer::Setup(): Error opening listen socket!\n");
  100. return sResult;
  101. }
  102. ////////////////////////////////////////////////////////////////////////////////
  103. // Shutdown
  104. ////////////////////////////////////////////////////////////////////////////////
  105. void CNetServer::Shutdown(void)
  106. {
  107. Reset();
  108. }
  109. ////////////////////////////////////////////////////////////////////////////////
  110. // Update server. This should be called regularly.
  111. ////////////////////////////////////////////////////////////////////////////////
  112. void CNetServer::Update(void)
  113. {
  114. short sResult = 0;
  115. //------------------------------------------------------------------------------
  116. // Accept new clients
  117. //------------------------------------------------------------------------------
  118. // If there's no error on the listen socket, we can try to accept clients
  119. if (!m_socketListen.IsError())
  120. {
  121. // Look for an unconnected, unused slot in the array. I'm torn between searching
  122. // for an empty client each time versus checking if the socket can accept without
  123. // blocking each time -- I'm not sure which one is quicker! Obviously, the quicker
  124. // of the two should be checked first.
  125. for (Net::ID id = 0; id < Net::MaxNumIDs; id++)
  126. {
  127. if ((m_aClients[id].m_msgr.GetState() == CNetMsgr::Disconnected) && (m_aClients[id].m_state == CClient::Unused))
  128. {
  129. // Check if a new client is trying to connect
  130. if (m_socketListen.CanAcceptWithoutBlocking())
  131. {
  132. // Try to accept client's connection
  133. short serr = m_aClients[id].m_msgr.Accept(&m_socketListen, m_callback);
  134. if (serr == 0)
  135. {
  136. // Upgrade state
  137. m_aClients[id].m_state = CClient::Used;
  138. }
  139. else
  140. {
  141. // If the return error indicates that it would have blocked, then something
  142. // is not kosher since CanAcceptWithoutBlocking() just said it woulnd NOT block.
  143. if (serr == RSocket::errWouldBlock)
  144. TRACE("CNetServer()::Update(): It waid it wouldn't block, but then said it would!\n");
  145. // Don't return an actual error code from this function because we can't
  146. // get all bent-out-of-shape over not being able to connect to a client
  147. // TRACE("CNetServer()::Update(): Tried to accept connection, but failed.\n");
  148. }
  149. }
  150. // Break out of loop that was looking for unused clients
  151. break;
  152. }
  153. }
  154. }
  155. //------------------------------------------------------------------------------
  156. // Check for any reception on our antenna socket. Potential clients that are
  157. // looking for a host will periodically broadcast a message, and as a server
  158. // we are supposed to respond.
  159. //------------------------------------------------------------------------------
  160. // Don't respond once the game has started because we currently don't support
  161. // drop-in play, so we don't want to confuse potential players
  162. if (!m_bGameStarted)
  163. {
  164. // Try to read a message. This will almost always fail due to a lack of data,
  165. // since it's relatively rare for a client to be browsing, and even then it only
  166. // sends out a message every so often. If we get an incorrectly-sized message,
  167. // we simply ignore it -- this is a datagram socket, so if the message was larger
  168. // than we expected, the rest of it will be discarded, and if it was smaller, then
  169. // we can ignore it as well. Bad messages could come from a foreign app that is
  170. // using the same port as us. If we do get a message, the address of the sender
  171. // will be recorded -- this gives us the host's address!
  172. U8 buf1[4];
  173. long lReceived;
  174. RSocket::Address address;
  175. short serr = m_socketAntenna.ReceiveFrom(buf1, sizeof(buf1), &lReceived, &address);
  176. if (serr == 0)
  177. {
  178. // Validate the message to make sure it was sent by another app of this
  179. // type, as opposed to some unknown app that happens to use the same port.
  180. if ((lReceived == sizeof(buf1)) &&
  181. (buf1[0] == Net::BroadcastMagic0) &&
  182. (buf1[1] == Net::BroadcastMagic1) &&
  183. (buf1[2] == Net::BroadcastMagic2) &&
  184. (buf1[3] == Net::BroadcastMagic3))
  185. {
  186. // Send back a message including the host name and magic number
  187. // The endian nature of the magic number will always be correct because
  188. // the only entitity that is meant to recognize this value is the one
  189. // that sent it, so as long as the encoding and decoding of the bytes
  190. // is the same, that entity will get the same value that it sent. All
  191. // other entities will see this as a meaningless value, which is fine.
  192. U8 buf2[4 + 4 + sizeof(m_acHostName)];
  193. buf2[0] = Net::BroadcastMagic0;
  194. buf2[1] = Net::BroadcastMagic1;
  195. buf2[2] = Net::BroadcastMagic2;
  196. buf2[3] = Net::BroadcastMagic3;
  197. buf2[4] = (U8)(m_lHostMagic & 0xff);
  198. buf2[5] = (U8)((m_lHostMagic >> 8) & 0xff);
  199. buf2[6] = (U8)((m_lHostMagic >> 16) & 0xff);
  200. buf2[7] = (U8)((m_lHostMagic >> 24) & 0xff);
  201. strncpy((char*)&buf2[8], m_acHostName, sizeof(m_acHostName));
  202. // Send the message directly to the sender of the previous message
  203. long lBytesSent;
  204. short serr = m_socketAntenna.SendTo(buf2, sizeof(buf2), &lBytesSent, &address);
  205. if (serr == 0)
  206. {
  207. if (lBytesSent != sizeof(buf2))
  208. TRACE("CNetServer::Update(): Error sending broadcast (wrong size)!\n");
  209. }
  210. else
  211. {
  212. if (serr != RSocket::errWouldBlock)
  213. TRACE("CNetServer::Update(): Error sending broadcast!\n");
  214. }
  215. }
  216. else
  217. TRACE("CNetServer::Update(): Validation failed -- another app may be sending crap to our port!\n");
  218. }
  219. else
  220. {
  221. if (serr != RSocket::errWouldBlock)
  222. TRACE("CNetServer::Update(): Warning: Error receiving broadcast -- ignored!\n");
  223. }
  224. }
  225. //------------------------------------------------------------------------------
  226. // Update clients
  227. //------------------------------------------------------------------------------
  228. for (Net::ID id = 0; id < Net::MaxNumIDs; id++)
  229. m_aClients[id].m_msgr.Update();
  230. }
  231. ////////////////////////////////////////////////////////////////////////////////
  232. // Get message
  233. ////////////////////////////////////////////////////////////////////////////////
  234. void CNetServer::GetMsg(
  235. NetMsg* pmsg) // Out: Message is returned here
  236. {
  237. // This indicates whether we got a message to be returned to the caller
  238. bool bGotMsgForCaller = false;
  239. // We need to service all of the currently connected clients, but we can
  240. // only handle one message each time this function is called. Actually,
  241. // we can only handle one message if it's a message that needs to be
  242. // returned to the caller. If it wasn't, then we could theoretically
  243. // handle many such messages, with the only limitation being how much time
  244. // we're willing to spend here. For now, I'm going with handling just one
  245. // message each time.
  246. //
  247. // In order to give each client a chance, we use m_idPrevGet to keep track
  248. // of which client we got a message from the previous time. Starting with
  249. // the next client after that, we search for the first client that is
  250. // connected and has a message, and we process it. We save that client's
  251. // id so that next time we will start with the client after it.
  252. //
  253. // If we go through the entire list once and don't find any clients with
  254. // messages to get, then we have no client messages to process this time.
  255. bool bGotOne = false;
  256. Net::ID id = m_idPrevGet;
  257. do {
  258. if (++id >= Net::MaxNumIDs)
  259. id = 0;
  260. if (m_aClients[id].m_msgr.GetState() == CNetMsgr::Connected)
  261. bGotOne = m_aClients[id].m_msgr.GetMsg(pmsg);
  262. } while (!bGotOne && (id != m_idPrevGet));
  263. m_idPrevGet = id;
  264. // If we got a message, handle it
  265. if (bGotOne)
  266. {
  267. // The message's ucSenderID is not transmitted as part of the message in
  268. // order to save bandwidth (every byte counts :) since we know the sender
  269. // (we're connected to the sender) and its ID is implied by it's index.
  270. pmsg->ucSenderID = id;
  271. // Used for sending messages
  272. NetMsg msg;
  273. // The login message is the only mechanism we're using to detect foreign
  274. // apps that might accidentally connect to us. None of our other messages
  275. // has any protection, so random data that happens to resemble a message
  276. // could really screw us up. Therefore, it is very important that if the
  277. // first thing we recieve from a client is NOT a LOGIN message, we
  278. // immediately disconnect it. And if we do get what looks like a LOGIN
  279. // message, we must make sure the magic numbers are right.
  280. if (!m_aClients[id].m_bLoggedIn)
  281. {
  282. if (pmsg->msg.nothing.ucType == NetMsg::LOGIN)
  283. {
  284. if (pmsg->msg.login.ulMagic == CNetMsgr::MagicNum)
  285. {
  286. ////////////////////////////////////////////////////////////////
  287. // Version negotiation and useful error results ////////////////
  288. ////////////////////////////////////////////////////////////////
  289. //
  290. // In net implementation for Postal net version 1, both the
  291. // server and the client would check the version numbers -- the
  292. // server would check msg.login.ulVersion against its
  293. // MinVersionNum & CurVersionNum and, if the server accepted the
  294. // login, the client would check msg.loginAccept.ulVersion
  295. // against its MinVersionNum & CurVersionNum. Although the
  296. // version 1 client would display an error message when it
  297. // decided it could not support the server's version, the server
  298. // would refuse a login before that, never giving the client a
  299. // chance to notice and report this to the user.
  300. // To remedy this, the Postal Net version 2's server NEVER
  301. // rejects a client and, instaed, relies on the client to reject
  302. // it. This gives the client a chance to report the error.
  303. // Since under our new scheme we never send a LOGIN_DENY, we
  304. // know, if we receive a LOGIN_DENY, that we are dealing with a
  305. // version 1 server.
  306. //
  307. // Additionally, bit fifteen of the version number is set if on
  308. // a Mac platform so we can use the same mechanism to determine
  309. // if we are attempting to connect a Mac and a PC.
  310. //
  311. // Here's the actual scenarios and results for version conflicts:
  312. //
  313. // Server 1 vs Client 2 -- Server sends Client a LOGIN_DENY so
  314. // the client knows it's dealing with a version 1 server and
  315. // reports the problem.
  316. //
  317. // Server 2 vs Client 1 -- Server accepts connection. Client
  318. // drops, though, when it sees the server's version is 2 and
  319. // reports the problem.
  320. //
  321. // For future versions:
  322. //
  323. // Server 3 vs Client 1 -- Server accepts connection. Client
  324. // drops, though, when it sees the server's version is 3 and
  325. // reports the problem.
  326. //
  327. // Server 3 vs Client 2 -- Server accepts connection. Client
  328. // drops, though, when it sees the server's version is 3 and
  329. // reports the problem.
  330. //
  331. ////////////////////////////////////////////////////////////////
  332. // Check version number to see if we can support it (this also is a platform check).
  333. if ( (pmsg->msg.login.ulVersion >= CNetMsgr::MinVersionNum) && (pmsg->msg.login.ulVersion <= CNetMsgr::CurVersionNum))
  334. {
  335. // Compatible.
  336. }
  337. else
  338. {
  339. // Must set the type.
  340. pmsg->msg.err.ucType = NetMsg::ERR;
  341. pmsg->ucSenderID = Net::InvalidID;
  342. // Determine error type (possibilities are incompatible
  343. // versions and/or incompatible platforms).
  344. if ( (pmsg->msg.login.ulVersion & CNetMsgr::MacVersionBit) ^ (CNetMsgr::MinVersionNum & CNetMsgr::MacVersionBit) )
  345. {
  346. // One of us is a Mac and one is a PC.
  347. pmsg->msg.err.error = NetMsg::ServerPlatformMismatchError;
  348. }
  349. else
  350. {
  351. // Store version number from original message before we clobber it
  352. // by creating an error message in the same area (not sure if this
  353. // is really an issue but just in case).
  354. ULONG ulVersion = pmsg->msg.login.ulVersion;
  355. // Incompatible version number.
  356. pmsg->msg.err.error = NetMsg::ServerVersionMismatchError;
  357. pmsg->msg.err.ulParam = ulVersion & ~CNetMsgr::MacVersionBit;
  358. }
  359. // Return this error msg to caller
  360. bGotMsgForCaller = true;
  361. // We rely on the client to reject us but we report the error with this
  362. // opportunity.
  363. }
  364. // Note that we always allow the login, even if the version number and/or
  365. // platform are wrong -- see comment above.
  366. // Allow login, responding with our version number and the client's assigned ID
  367. msg.msg.loginAccept.ucType = NetMsg::LOGIN_ACCEPT;
  368. msg.msg.loginAccept.idAssigned = id;
  369. msg.msg.loginAccept.ulMagic = CNetMsgr::MagicNum;
  370. msg.msg.loginAccept.ulVersion = CNetMsgr::CurVersionNum;
  371. SendMsg(id, &msg);
  372. // Mark client as "logged in"
  373. m_aClients[id].m_bLoggedIn = true;
  374. }
  375. else
  376. {
  377. // Drop client
  378. DropClient(id);
  379. }
  380. }
  381. else
  382. {
  383. // Drop client
  384. DropClient(id);
  385. }
  386. }
  387. else
  388. {
  389. // Process message
  390. switch(pmsg->msg.nothing.ucType)
  391. {
  392. case NetMsg::NOTHING:
  393. break;
  394. case NetMsg::STAT:
  395. break;
  396. case NetMsg::ERR:
  397. // If a local client has been registered, and if this error came from that client,
  398. // then we abort the game, because we can't continue without the local client
  399. // (it seems unlikely that the user would want to sit around watching a blank screen).
  400. // If no local client was registered, it will be invalid, and this compare will fail.
  401. // If it isn't a local client, then we just drop the client that reported the error.
  402. if (id == m_idLocalClient)
  403. AbortGame(NetMsg::ErrorAbortedGame);
  404. else
  405. DropClient(id);
  406. // Return this msg to caller
  407. bGotMsgForCaller = true;
  408. break;
  409. case NetMsg::LOGOUT:
  410. // The client will send a LOGOUT if, after having it's LOGIN request accepted, it
  411. // determines that the server's version number is not acceptable. It may also
  412. // send this if it needs to abort at any time after it has sent a JOIN_REQ but
  413. // before it has received a response. In all cases, we simply call DropClient(),
  414. // which knows how to handle any situation.
  415. DropClient(id);
  416. break;
  417. case NetMsg::JOIN_REQ:
  418. if (!m_bGameStarted)
  419. {
  420. // Upgrade client's state
  421. m_aClients[id].m_state = CClient::Joined;
  422. // Add client info to database. Note that client's "peer address" is the same
  423. // as the one we're connected to, but with a different port number.
  424. m_aClients[id].m_address = m_aClients[id].m_msgr.GetAddress();
  425. RSocket::SetAddressPort(m_usBasePort + Net::FirstPeerPortOffset + id, &m_aClients[id].m_address);
  426. memcpy(m_aClients[id].m_acName, pmsg->msg.joinReq.acName, sizeof(m_aClients[id].m_acName));
  427. m_aClients[id].m_ucColor = pmsg->msg.joinReq.ucColor;
  428. m_aClients[id].m_ucTeam = pmsg->msg.joinReq.ucTeam;
  429. m_aClients[id].m_sBandwidth = pmsg->msg.joinReq.sBandwidth;
  430. // Tell client he was accepted
  431. msg.msg.joinAccept.ucType = NetMsg::JOIN_ACCEPT;
  432. SendMsg(id, &msg);
  433. // Send all clients (including new one) info about the new client
  434. msg.msg.joined.ucType = NetMsg::JOINED;
  435. msg.msg.joined.id = id;
  436. msg.msg.joined.address = m_aClients[id].m_address;
  437. memcpy(msg.msg.joined.acName, m_aClients[id].m_acName, sizeof(msg.msg.joined.acName));
  438. msg.msg.joined.ucColor = m_aClients[id].m_ucColor;
  439. msg.msg.joined.ucTeam = m_aClients[id].m_ucTeam;
  440. msg.msg.joined.sBandwidth = m_aClients[id].m_sBandwidth;
  441. SendMsg(&msg);
  442. // Send new client info about other joined clients
  443. for (Net::ID id2 = 0; id2 < Net::MaxNumIDs; id2++)
  444. {
  445. if ((id2 != id) && (m_aClients[id2].m_state == CClient::Joined))
  446. {
  447. msg.msg.joined.ucType = NetMsg::JOINED;
  448. msg.msg.joined.id = id2;
  449. msg.msg.joined.address = m_aClients[id2].m_address;
  450. memcpy(msg.msg.joined.acName, m_aClients[id2].m_acName, sizeof(msg.msg.joined.acName));
  451. msg.msg.joined.ucColor = m_aClients[id2].m_ucColor;
  452. msg.msg.joined.ucTeam = m_aClients[id2].m_ucTeam;
  453. msg.msg.joined.sBandwidth = m_aClients[id2].m_sBandwidth;
  454. SendMsg(id, &msg);
  455. }
  456. }
  457. // Send new client info about current game setup (if we know it yet!)
  458. if (m_bSetupGameValid)
  459. SendMsg(id, &m_msgSetupGame);
  460. // Return this msg to caller
  461. bGotMsgForCaller = true;
  462. }
  463. else
  464. {
  465. // Deny join request because we don't allow joins after game has started
  466. msg.msg.joinDeny.ucType = NetMsg::JOIN_DENY;
  467. msg.msg.joinDeny.ucReason = NetMsg::GameAlreadyStarted;
  468. SendMsg(id, &msg);
  469. // Drop client
  470. DropClient(id);
  471. }
  472. break;
  473. case NetMsg::CHANGE_REQ:
  474. // Change client's info in database
  475. memcpy(m_aClients[id].m_acName, pmsg->msg.changed.acName, sizeof(m_aClients[id].m_acName));
  476. m_aClients[id].m_ucColor = pmsg->msg.changed.ucColor;
  477. m_aClients[id].m_ucTeam = pmsg->msg.changed.ucTeam;
  478. // Send CHANGED message to all clients, including the one that requested the change
  479. msg.msg.changed.ucType = NetMsg::CHANGED;
  480. msg.msg.changed.id = id;
  481. memcpy(msg.msg.changed.acName, m_aClients[id].m_acName, sizeof(msg.msg.changed.acName));
  482. msg.msg.changed.ucColor = m_aClients[id].m_ucColor;
  483. msg.msg.changed.ucTeam = m_aClients[id].m_ucTeam;
  484. SendMsg(&msg);
  485. // Return this msg to caller
  486. bGotMsgForCaller = true;
  487. break;
  488. case NetMsg::DROP_REQ:
  489. // Drop the client -- DropClient() knows how to handle every situation
  490. DropClient(id);
  491. break;
  492. case NetMsg::DROP_ACK:
  493. // If we're doing a drop, handle this, otherwise ignore it
  494. if (!m_qDropIDs.IsEmpty())
  495. {
  496. // Make sure we only get one per client
  497. ASSERT(!m_aClients[id].m_bSentDropAck);
  498. // Set flag indicating that this client sent the message
  499. m_aClients[id].m_bSentDropAck = true;
  500. // Save info from message
  501. m_aClients[id].m_seqHighestDropeeInput = pmsg->msg.dropAck.seqLastDropeeInput;
  502. m_aClients[id].m_seqLastDoneFrame = pmsg->msg.dropAck.seqLastDoneFrame;
  503. // Check if all joined clients sent a DROP_ACK
  504. Net::ID id2;
  505. for (id2 = 0; id2 < Net::MaxNumIDs; id2++)
  506. {
  507. if ((m_aClients[id2].m_state == CClient::Joined) && (!m_aClients[id2].m_bSentDropAck))
  508. break;
  509. }
  510. if (id2 == Net::MaxNumIDs)
  511. {
  512. // Do the messy work required to figure out if any clients needs inputs from
  513. // other clients. The end result of this function is that if it needed input
  514. // data from a client, it asked for it and returns true. If not, it returns
  515. // false, which means we can immediately go on to the final step.
  516. if (GotAllDropAcks() == false)
  517. {
  518. // Finish the process of dropping client. If there's more clients in the drop
  519. // queue, this could also start the dropping of the next victim
  520. FinishDroppingClientDuringGame();
  521. }
  522. }
  523. }
  524. break;
  525. case NetMsg::INPUT_DATA:
  526. ASSERT(m_bWaitingForInputData);
  527. if (m_bWaitingForInputData)
  528. {
  529. // Make sure it's for the correct ID
  530. ASSERT(m_qDropIDs.PeekAtFront() == pmsg->msg.inputData.id);
  531. // No longer waiting for input data
  532. m_bWaitingForInputData = false;
  533. // Go through all the clients and feed inputs to those that need it. Note that
  534. // we simply forward the message we received. It may contain more data than
  535. // each client needs, but what the hell. This could be tuned some day to
  536. // be a bit more efficient by only sending as much as each client needs.
  537. for (Net::ID id = 0; id < Net::MaxNumIDs; id++)
  538. {
  539. if (m_aClients[id].m_state == CClient::Joined)
  540. {
  541. // If this client's highest dropee input is <= the highest frame, then he needs inputs
  542. if (SEQ_LT(m_aClients[id].m_seqHighestDropeeInput, m_seqHighestDoneFrame))
  543. SendMsg(id, pmsg);
  544. }
  545. }
  546. // Finish the process of dropping client. If there's more clients in the drop
  547. // queue, this could also start the dropping of the next victim
  548. FinishDroppingClientDuringGame();
  549. }
  550. break;
  551. case NetMsg::CHAT_REQ:
  552. // Send chat text to the clients specified by the mask
  553. msg.msg.chat.ucType = NetMsg::CHAT;
  554. strncpy(msg.msg.chat.acText, pmsg->msg.chatReq.acText, sizeof(msg.msg.chat.acText) );
  555. SendMsg(pmsg->msg.chatReq.u16Mask, &msg);
  556. // Return this msg to caller
  557. bGotMsgForCaller = true;
  558. break;
  559. case NetMsg::ABORT_GAME:
  560. break;
  561. case NetMsg::READY_REALM:
  562. // If not waiting for realm status messages, then ignore this
  563. if (m_bWaitingForRealmStatus)
  564. {
  565. // Make sure we only get one per client
  566. ASSERT(!m_aClients[id].m_bSentReadyRealm);
  567. // Set flag indicating that this client sent the message
  568. m_aClients[id].m_bSentReadyRealm = true;
  569. // Check if all joined clients sent a READY_REALM. Along the way, we need to
  570. // count the number of clients that have sent the message so far and we need
  571. // to create a mask that includes only those clients that sent the message.
  572. // These values are used to generate the PROGRESS_REALM message afterwards.
  573. Net::ID id2;
  574. short sNumExpected = 0;
  575. short sNumReady = 0;
  576. U16 mask = 0;
  577. for (id2 = 0; id2 < Net::MaxNumIDs; id2++)
  578. {
  579. mask = (mask >> 1) & 0x7fff;
  580. if (m_aClients[id2].m_state == CClient::Joined)
  581. {
  582. sNumExpected++;
  583. if (m_aClients[id2].m_bSentReadyRealm)
  584. {
  585. sNumReady++;
  586. mask |= 0x8000;
  587. }
  588. }
  589. }
  590. // This had to be disabled. The idea was great, with one major flaw -- what if the server is
  591. // the slow machine, so while it's off loading a level or something, all the clients have already
  592. // sent their READY_REALM messages and haven't gotten heard anything back from the server!?!?!
  593. // Fixing this would require that the server be called at all times, and that's very hard since
  594. // much of what the server does occurs on the GetMsg() call, which is difficult for the app to
  595. // deal with at every level of the code. It would be slightly easier for the app if all this work
  596. // were done silently by the Update() function, which is possible, but certainly not a trival
  597. // change at this level. By the way, another problem is that once the server DOES start getting
  598. // called again, it will have to deal with ALL of these messages at once! Very sucky.
  599. #if 0
  600. // Send PROGRESS_REALM message to all joined clients that have already responded
  601. // with their own READY_REALM messages. We tell each of them how many other
  602. // clients we're still waiting on. The idea behind using the mask is that it
  603. // cuts down on the number of messages we sent. We don't really want to send
  604. // them to clients that haven't responded yet since they are obviously busy doing
  605. // something else, and besides, with 16 clients, we would send 16 * 16 = 256
  606. // messages, which is a lot, but by cutting it down using the mask, we end up
  607. // with only 16+15+14+...+3+2+1 = 136, which is much better.
  608. msg.msg.progressRealm.ucType = NetMsg::PROGRESS_REALM;
  609. msg.msg.progressRealm.sNumReady = sNumReady;
  610. msg.msg.progressRealm.sNumNotReady = sNumExpected - sNumReady;
  611. SendMsg(mask, &msg);
  612. #endif
  613. // If we got through the whole list, then we got all the READY_REALM messages we need
  614. if (sNumReady == sNumExpected)
  615. {
  616. // Send START_REALM message to all joined clients
  617. msg.msg.startRealm.ucType = NetMsg::START_REALM;
  618. SendMsg(&msg);
  619. // Reset all related flags
  620. m_bWaitingForRealmStatus = false;
  621. for (Net::ID id2 = 0; id2 < Net::MaxNumIDs; id2++)
  622. m_aClients[id2].m_bSentReadyRealm = false;
  623. }
  624. }
  625. break;
  626. case NetMsg::BAD_REALM:
  627. // If not waiting for realm status messages, then ignore this
  628. if (m_bWaitingForRealmStatus)
  629. {
  630. // Reset all related flags
  631. m_bWaitingForRealmStatus = false;
  632. for (Net::ID id2 = 0; id2 < Net::MaxNumIDs; id2++)
  633. m_aClients[id2].m_bSentReadyRealm = false;
  634. // Abort game due to error
  635. AbortGame(NetMsg::ErrorAbortedGame);
  636. }
  637. break;
  638. // case FINISH_REALM:
  639. // break;
  640. case NetMsg::PING:
  641. // Simply echo the ping right back, and record the latest result
  642. SendMsg(id, pmsg);
  643. // m_lLatestPingTime = pmsg->msg.ping.lLatestPingTime;
  644. break;
  645. default:
  646. break;
  647. }
  648. }
  649. }
  650. // If we don't already have a message for the caller, check for listen error
  651. // (this has lower priority than a client message because accepting new clients
  652. // isn't as important as servicing existing ones)
  653. if (!bGotMsgForCaller)
  654. {
  655. if (m_socketListen.IsError())
  656. {
  657. // Generate a listen error message
  658. pmsg->msg.err.ucType = NetMsg::ERR;
  659. pmsg->msg.err.error = NetMsg::ListenError;
  660. pmsg->ucSenderID = Net::InvalidID;
  661. bGotMsgForCaller = true;
  662. }
  663. }
  664. // If we don't already have a message for the caller, generate a "nothing"
  665. // (this has the lowest priority of all)
  666. if (!bGotMsgForCaller)
  667. {
  668. pmsg->msg.nothing.ucType = NetMsg::NOTHING;
  669. pmsg->ucSenderID = Net::InvalidID;
  670. }
  671. }
  672. ////////////////////////////////////////////////////////////////////////////////
  673. // Send message to specified client
  674. ////////////////////////////////////////////////////////////////////////////////
  675. void CNetServer::SendMsg(
  676. Net::ID id, // In: ID to send message to
  677. NetMsg* pmsg) // In: Message to send
  678. {
  679. ASSERT(id != Net::InvalidID);
  680. ASSERT(id < Net::MaxNumIDs);
  681. m_aClients[id].m_msgr.SendMsg(pmsg);
  682. }
  683. ////////////////////////////////////////////////////////////////////////////////
  684. // Send message to specified group of clients - only Joined clients are allowed!
  685. ////////////////////////////////////////////////////////////////////////////////
  686. void CNetServer::SendMsg(
  687. U16 mask, // In: Bit-mask indicating who to send to
  688. NetMsg* pmsg) // In: Message to send
  689. {
  690. // Bit-mask determines who to send the message to
  691. for (Net::ID id = 0; id < Net::MaxNumIDs; id++)
  692. {
  693. if ((mask & 1) && (m_aClients[id].m_state == CClient::Joined))
  694. SendMsg(id, pmsg);
  695. mask = mask >> 1;
  696. }
  697. }
  698. ////////////////////////////////////////////////////////////////////////////////
  699. // Send message to all joined clients
  700. ////////////////////////////////////////////////////////////////////////////////
  701. void CNetServer::SendMsg(
  702. NetMsg* pmsg) // In: Message to send
  703. {
  704. for (Net::ID id = 0; id < Net::MaxNumIDs; id++)
  705. {
  706. if (m_aClients[id].m_state == CClient::Joined)
  707. SendMsg(id, pmsg);
  708. }
  709. }
  710. ////////////////////////////////////////////////////////////////////////////////
  711. // Determine if there is more data waiting to be sent. If there is data to
  712. // to be sent AND there is a send error, then that data can't be sent, so we
  713. // return false to indicate "no more data".
  714. ////////////////////////////////////////////////////////////////////////////////
  715. bool CNetServer::IsMoreToSend(void) // Returns true if more to send, false otherwise
  716. {
  717. bool bResult = false;
  718. for (Net::ID id = 0; id < Net::MaxNumIDs; id++)
  719. {
  720. if (m_aClients[id].m_msgr.IsMoreToSend())
  721. {
  722. bResult = true;
  723. break;
  724. }
  725. }
  726. return bResult;
  727. }
  728. ////////////////////////////////////////////////////////////////////////////////
  729. // Drop specified client
  730. ////////////////////////////////////////////////////////////////////////////////
  731. void CNetServer::DropClient(
  732. Net::ID id) // In: Client to drop
  733. {
  734. ASSERT(id != Net::InvalidID);
  735. ASSERT(id < Net::MaxNumIDs);
  736. switch(m_aClients[id].m_state)
  737. {
  738. case CClient::Unused:
  739. // This doesn't really make sense because once we're connected we should
  740. // also be in a state other than "unused".
  741. ASSERT(0);
  742. m_aClients[id].m_msgr.Disconnect(false);
  743. break;
  744. case CClient::Used:
  745. m_aClients[id].m_state = CClient::Unused;
  746. m_aClients[id].m_msgr.Disconnect(true);
  747. break;
  748. case CClient::Joined:
  749. // Whether or not the game has started makes a huge difference in how this is handled
  750. if (m_bGameStarted)
  751. {
  752. // If the queue is empty, we can start the drop process. Otherwise, we need
  753. // to add the new drop client to the drop queue.
  754. if (m_qDropIDs.IsEmpty())
  755. {
  756. // Add to queue (we use this as an indicator that we're dropping someone)
  757. m_qDropIDs.PutAtBack(id);
  758. // Start the process of dropping a client during a game
  759. StartDroppingClientDuringGame(id);
  760. }
  761. else
  762. {
  763. // Add client's ID to drop queue
  764. m_qDropIDs.PutAtBack(id);
  765. }
  766. }
  767. else
  768. {
  769. // Tell all clients to drop this client (including the one being dropped)
  770. NetMsg msg;
  771. msg.msg.dropped.ucType = NetMsg::DROPPED;
  772. msg.msg.dropped.id = id;
  773. msg.msg.dropped.sContext = -1;
  774. SendMsg(&msg);
  775. // Change dropped client's state to "unused" (only AFTER message was sent)
  776. m_aClients[id].m_state = CClient::Unused;
  777. }
  778. m_aClients[id].m_msgr.Disconnect(true);
  779. break;
  780. case CClient::Dropped:
  781. // Nothing to do (game must have already started for it to be in this state)
  782. break;
  783. }
  784. // Clear client's "logged in" flag
  785. m_aClients[id].m_bLoggedIn = false;
  786. }
  787. ////////////////////////////////////////////////////////////////////////////////
  788. // Send the specified game settings to all joined clients
  789. ////////////////////////////////////////////////////////////////////////////////
  790. void CNetServer::SetupGame(
  791. short sRealmNum, // In: Realm number
  792. const char* pszRealmFile, // In: Realm file name
  793. short sDifficulty, // In: Difficulty
  794. short sRejuvenate, // In: Rejuvenate flag
  795. short sTimeLimit, // In: Time limit in minutes, or negative if none
  796. short sKillLimit, // In: Kill limit, or negative if none
  797. short sCoopLevels, // In: Zero for deathmatch levels, non-zero for cooperative levels.
  798. short sCoopMode) // In: Zero for deathmatch mode, non-zero for cooperative mode.
  799. {
  800. // Setup a special START_GAME message that we keep around so we can send
  801. // it to clients as soon as they join. That way, they get better feedback.
  802. // Otherwise, they would have to wait until the next time this function
  803. // is called, which may not be all that often.
  804. m_msgSetupGame.msg.setupGame.ucType = NetMsg::SETUP_GAME;
  805. m_msgSetupGame.msg.setupGame.sRealmNum = sRealmNum;
  806. memcpy(m_msgSetupGame.msg.setupGame.acRealmFile, pszRealmFile, sizeof(m_msgSetupGame.msg.setupGame.acRealmFile));
  807. m_msgSetupGame.msg.setupGame.acRealmFile[sizeof(m_msgSetupGame.msg.setupGame.acRealmFile)-1] = 0;
  808. m_msgSetupGame.msg.setupGame.sDifficulty = sDifficulty;
  809. m_msgSetupGame.msg.setupGame.sRejuvenate = sRejuvenate;
  810. m_msgSetupGame.msg.setupGame.sTimeLimit = sTimeLimit;
  811. m_msgSetupGame.msg.setupGame.sKillLimit = sKillLimit;
  812. m_msgSetupGame.msg.setupGame.sCoopLevels = sCoopLevels;
  813. m_msgSetupGame.msg.setupGame.sCoopMode = sCoopMode;
  814. // Mark message as valid
  815. m_bSetupGameValid = true;
  816. SendMsg(&m_msgSetupGame);
  817. }
  818. ////////////////////////////////////////////////////////////////////////////////
  819. // Start game using specified settings
  820. ////////////////////////////////////////////////////////////////////////////////
  821. void CNetServer::StartGame(
  822. Net::ID idServer, // In: Server's client's ID
  823. short sRealmNum, // In: Realm number
  824. char* pszRealmFile, // In: Realm file name
  825. short sDifficulty, // In: Difficulty
  826. short sRejuvenate, // In: Rejuvenate flag
  827. short sTimeLimit, // In: Time limit in minutes, or negative if none
  828. short sKillLimit, // In: Kill limit, or negative if none
  829. short sCoopLevels, // In: Zero for deathmatch levels, non-zero for cooperative levels.
  830. short sCoopMode, // In: Zero for deathmatch mode, non-zero for cooperative mode.
  831. short sFrameTime, // In: Time per frame (in milliseconds)
  832. Net::SEQ seqMaxAhead) // In: Initial max ahead for input versus frame seq
  833. {
  834. ASSERT(!m_bGameStarted);
  835. // Set flag
  836. m_bGameStarted = true;
  837. // Tell all joined clients to start game
  838. NetMsg msg;
  839. msg.msg.startGame.ucType = NetMsg::START_GAME;
  840. msg.msg.startGame.idServer = idServer;
  841. msg.msg.startGame.sRealmNum = sRealmNum;
  842. memcpy(msg.msg.startGame.acRealmFile, pszRealmFile, sizeof(msg.msg.startGame.acRealmFile));
  843. msg.msg.startGame.acRealmFile[sizeof(msg.msg.startGame.acRealmFile)-1] = 0;
  844. msg.msg.startGame.sDifficulty = sDifficulty;
  845. msg.msg.startGame.sRejuvenate = sRejuvenate;
  846. msg.msg.startGame.sTimeLimit = sTimeLimit;
  847. msg.msg.startGame.sKillLimit = sKillLimit;
  848. msg.msg.startGame.sCoopLevels = sCoopLevels;
  849. msg.msg.startGame.sCoopMode = sCoopMode;
  850. msg.msg.startGame.sFrameTime = sFrameTime;
  851. msg.msg.startGame.seqMaxAhead = seqMaxAhead;
  852. SendMsg(&msg);
  853. // We need to wait for clients to respond with realm status messages
  854. m_bWaitingForRealmStatus = true;
  855. }
  856. ////////////////////////////////////////////////////////////////////////////////
  857. // Abort game
  858. ////////////////////////////////////////////////////////////////////////////////
  859. void CNetServer::AbortGame(
  860. unsigned char ucReason) // In: Why game was aborted
  861. {
  862. // Tell players to abort game
  863. NetMsg msg;
  864. msg.msg.abortGame.ucType = NetMsg::ABORT_GAME;
  865. msg.msg.abortGame.ucReason = ucReason;
  866. SendMsg(&msg);
  867. }
  868. ////////////////////////////////////////////////////////////////////////////////
  869. // Tell clients to go to the next realm when they reach the specified frame seq.
  870. // It is okay to call this multiple times -- "extra" calls are ignored.
  871. //
  872. // The return value is true if a new "next realm" sequence was initiated, and
  873. // false if there was already one in progress.
  874. ////////////////////////////////////////////////////////////////////////////////
  875. bool CNetServer::NextRealm(
  876. Net::SEQ seq) // In: The seq on which to go to next realm
  877. {
  878. // If we're already waiting, then we don't send this message. There are
  879. // two situations this can come up. First, the caller could have already
  880. // called us once, and is merely calling us over and over, which, as the
  881. // the function header comment says, is allowed. The second possibility
  882. // is that not all clients have responded to a much older attempt to
  883. // start the game or go to the next realm, and now the caller wants to go
  884. // on to yet another realm. In that situation, we can't accomodate the
  885. // caller -- we have to wait for all the clients to catch up to the previous
  886. // realm before we can go to the next one. All in all, this is rather
  887. // involved explanation for what works out to a simple check of a flag...
  888. bool bResult = true;
  889. if (!m_bWaitingForRealmStatus)
  890. {
  891. // Tell clients to go to the next realm when they reach this frame seq
  892. NetMsg msg;
  893. msg.msg.nextRealm.ucType = NetMsg::NEXT_REALM;
  894. msg.msg.nextRealm.seqHalt = seq;
  895. SendMsg(&msg);
  896. // We need to wait for clients to respond with realm status messages
  897. m_bWaitingForRealmStatus = true;
  898. }
  899. else
  900. {
  901. // There was already a "next realm" sequence in effect
  902. bResult = false;
  903. }
  904. return bResult;
  905. }
  906. ////////////////////////////////////////////////////////////////////////////////
  907. // Tell clients to proceed. This is used when all players are at a point where
  908. // they need to be told it's time to move on. There is NO attempt to
  909. // syncrhonize the clients, so this must only be used in non-critical sections
  910. // or at a point prior to a syncrhonized section. For instance, if all players
  911. // are viewing a dialog, the local user on the server might hit a key to go
  912. // on, at which point this function would be called to tell all the other
  913. // players to proceed.
  914. ////////////////////////////////////////////////////////////////////////////////
  915. void CNetServer::Proceed(void)
  916. {
  917. // Send PROCEED message to all joined clients
  918. NetMsg msg;
  919. msg.msg.proceed.ucType = NetMsg::PROCEED;
  920. SendMsg(&msg);
  921. }
  922. ////////////////////////////////////////////////////////////////////////////////
  923. // Start the process of dropping a client during a game
  924. ////////////////////////////////////////////////////////////////////////////////
  925. void CNetServer::StartDroppingClientDuringGame(
  926. Net::ID id)
  927. {
  928. // Tell all clients to drop this client (including the one being dropped)
  929. // Because there's something in the drop queue, GetMsg() will know that
  930. // it should be exptecting DROP_ACK messages from the remaining clients.
  931. NetMsg msg;
  932. msg.msg.dropped.ucType = NetMsg::DROPPED;
  933. msg.msg.dropped.id = id;
  934. msg.msg.dropped.sContext = 1;
  935. SendMsg(&msg);
  936. // Change dropped client's state to "dropped" (only AFTER message was sent)
  937. m_aClients[id].m_state = CClient::Dropped;
  938. // Clear "sent drop ack" flags for all clients
  939. for (Net::ID id2 = 0; id2 < Net::MaxNumIDs; id2++)
  940. m_aClients[id2].m_bSentDropAck = false;
  941. }
  942. ////////////////////////////////////////////////////////////////////////////////
  943. // Got all drop acks, now figure out what to do next
  944. //
  945. // A return value of true indicates that one or more clients needed inputs,
  946. // so the drop process is not yet complete. A return of false indicates that
  947. // no clients needed inputs, so we can proceed directly to the next phase.
  948. ////////////////////////////////////////////////////////////////////////////////
  949. bool CNetServer::GotAllDropAcks(void)
  950. {
  951. // Go through all the responses and find
  952. // (1) the lowest frame seq,
  953. // (2) the highest frame seq
  954. // (3) the highest known dropee input seq
  955. // To do this, we need to start out with some valid values, which we
  956. // get from the first client we come across. We can't do a typical thing
  957. // where you set the values to a very high or very low value to initial
  958. // it, because when comparing seq's, it is very important that they be
  959. // withing a small range of one another, or all bets are off.
  960. bool bFirst = true;
  961. m_seqHighestDoneFrame = 0;
  962. Net::ID idHighestDoneFrame = Net::InvalidID;
  963. Net::SEQ seqHighestDropeeInput = 0; // Used purely for debugging/verification
  964. Net::SEQ seqLowestDropeeInput = 0;
  965. Net::ID id;
  966. for (id = 0; id < Net::MaxNumIDs; id++)
  967. {
  968. if (m_aClients[id].m_state == CClient::Joined)
  969. {
  970. if (bFirst)
  971. {
  972. // Fill in the values from the first client we get to
  973. m_seqHighestDoneFrame = m_aClients[id].m_seqLastDoneFrame;
  974. idHighestDoneFrame = id;
  975. seqHighestDropeeInput = m_aClients[id].m_seqHighestDropeeInput;
  976. seqLowestDropeeInput = m_aClients[id].m_seqHighestDropeeInput;
  977. bFirst = false;
  978. }
  979. else
  980. {
  981. // If client's frame is >= highest frame, then this is the new highest frame
  982. if (SEQ_GTE(m_aClients[id].m_seqLastDoneFrame, m_seqHighestDoneFrame))
  983. {
  984. m_seqHighestDoneFrame = m_aClients[id].m_seqLastDoneFrame;
  985. idHighestDoneFrame = id;
  986. }
  987. // If client's input is >= highest input, then this is the new highest input
  988. if (SEQ_GTE(m_aClients[id].m_seqHighestDropeeInput, seqHighestDropeeInput))
  989. {
  990. seqHighestDropeeInput = m_aClients[id].m_seqHighestDropeeInput;
  991. }
  992. // If client's input is <= lowest input, then this is the new lowest input
  993. if (SEQ_LTE(m_aClients[id].m_seqHighestDropeeInput, seqLowestDropeeInput))
  994. {
  995. seqLowestDropeeInput = m_aClients[id].m_seqHighestDropeeInput;
  996. }
  997. }
  998. }
  999. }
  1000. // If we don't come out of this with a valid ID, we're in deep shit
  1001. ASSERT(idHighestDoneFrame != Net::InvalidID);
  1002. // Make sure someone has the dropee's input up to and including the highest frame.
  1003. // This should always be the case because if someone did a frame, they must have
  1004. // had the dropee's input for that frame.
  1005. ASSERT(SEQ_GTE(seqHighestDropeeInput, m_seqHighestDoneFrame));
  1006. // Go through all the clients and see if any one of them needs inputs
  1007. bool bSomeoneNeedsInputs = false;
  1008. for (id = 0; id < Net::MaxNumIDs; id++)
  1009. {
  1010. if (m_aClients[id].m_state == CClient::Joined)
  1011. {
  1012. // If this client's highest dropee input is <= the highest frame, then he needs inputs
  1013. if (SEQ_LT(m_aClients[id].m_seqHighestDropeeInput, m_seqHighestDoneFrame))
  1014. {
  1015. bSomeoneNeedsInputs = true;
  1016. break;
  1017. }
  1018. }
  1019. }
  1020. // If someone needs inputs, get them from whoever had the highest done frame
  1021. if (bSomeoneNeedsInputs)
  1022. {
  1023. // We need the inputs starting at the lowest dropee input + 1 (they already
  1024. // have the lowest one) up to the highest done frame.
  1025. NetMsg msg;
  1026. msg.msg.inputReq.ucType = NetMsg::INPUT_REQ;
  1027. msg.msg.inputReq.id = m_qDropIDs.PeekAtFront();
  1028. msg.msg.inputReq.seqStart = (Net::SEQ)(seqLowestDropeeInput + (Net::SEQ)1);
  1029. msg.msg.inputReq.sNum = (Net::SEQ)(m_seqHighestDoneFrame - seqLowestDropeeInput);
  1030. SendMsg(idHighestDoneFrame, &msg);
  1031. // Set flag to indicate that we're waiting for inputs
  1032. m_bWaitingForInputData = true;
  1033. }
  1034. return bSomeoneNeedsInputs;
  1035. }
  1036. ////////////////////////////////////////////////////////////////////////////////
  1037. // Finish the process of dropping client. If there's more clients in the drop
  1038. // queue, this could also start the dropping of the next victim
  1039. ////////////////////////////////////////////////////////////////////////////////
  1040. void CNetServer::FinishDroppingClientDuringGame(void)
  1041. {
  1042. // Send INPUT_MARK message to all clients so they can mark the last active
  1043. // input seq of the dropped client.
  1044. NetMsg msg;
  1045. msg.msg.inputMark.ucType = NetMsg::INPUT_MARK;
  1046. msg.msg.inputMark.id = m_qDropIDs.PeekAtFront();
  1047. msg.msg.inputMark.seqMark = m_seqHighestDoneFrame;
  1048. SendMsg(&msg);
  1049. // This client is now fully dropped, so remove it from the drop queue
  1050. m_qDropIDs.GetFromFront();
  1051. // Check if there's any more clients in the queue. If not, everyone can
  1052. // resume playing. Otherwise, drop the next client in the queue.
  1053. if (m_qDropIDs.IsEmpty())
  1054. {
  1055. // Send START_REALM message to all joined clients
  1056. msg.msg.startRealm.ucType = NetMsg::START_REALM;
  1057. SendMsg(&msg);
  1058. // Reset all related flags
  1059. m_bWaitingForRealmStatus = false;
  1060. for (Net::ID id2 = 0; id2 < Net::MaxNumIDs; id2++)
  1061. m_aClients[id2].m_bSentReadyRealm = false;
  1062. }
  1063. else
  1064. {
  1065. // Start the process of dropping the next client in the drop queue.
  1066. StartDroppingClientDuringGame(m_qDropIDs.PeekAtFront());
  1067. }
  1068. }
  1069. ////////////////////////////////////////////////////////////////////////////////
  1070. // EOF
  1071. ////////////////////////////////////////////////////////////////////////////////