Network.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: Network.cpp ////////////////////////////////////////////////////
  24. // Implementation of Network singleton
  25. // Author: Matthew D. Campbell, July 2001
  26. ///////////////////////////////////////////////////////////////////////////////
  27. // SYSTEM INCLUDES ////////////////////////////////////////////////////////////
  28. // USER INCLUDES //////////////////////////////////////////////////////////////
  29. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  30. #include "Common/GameEngine.h"
  31. #include "Common/MessageStream.h"
  32. #include "Common/Player.h"
  33. #include "Common/PlayerList.h"
  34. #include "GameNetwork/NetworkInterface.h"
  35. #include "GameNetwork/Udp.h"
  36. #include "GameNetwork/Transport.h"
  37. #include "strtok_r.h"
  38. #include "GameClient/Shell.h"
  39. #include "Common/CRCDebug.h"
  40. #include "GameLogic/GameLogic.h"
  41. #include "Common/RandomValue.h"
  42. #include "GameLogic/ScriptActions.h"
  43. #include "GameLogic/ScriptEngine.h"
  44. #include "Common/Recorder.h"
  45. #include "GameClient/MessageBox.h"
  46. #ifdef _INTERNAL
  47. // for occasional debugging...
  48. //#pragma optimize("", off)
  49. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  50. #endif
  51. #if defined(DEBUG_CRC)
  52. Int NET_CRC_INTERVAL = 1;
  53. #else
  54. Int NET_CRC_INTERVAL = 100;
  55. #endif
  56. // DEFINES ////////////////////////////////////////////////////////////////////
  57. #define RESEND_INTERVAL 1
  58. // PRIVATE TYPES //////////////////////////////////////////////////////////////
  59. /**
  60. * Connection message - encapsulating info kept by the connection layer about each
  61. * packet. These structs make up the in/out buffers at the connection layer.
  62. */
  63. #pragma pack(push, 1)
  64. struct ConnectionMessage
  65. {
  66. Int id;
  67. NetMessageFlags flags;
  68. UnsignedByte data[MAX_MESSAGE_LEN];
  69. time_t lastSendTime;
  70. Int retries;
  71. Int length;
  72. };
  73. #pragma pack(pop)
  74. static const int CmdMsgLen = 6; //< Minimum size of a command packet (Int + Unsigned Short)
  75. // PRIVATE DATA ///////////////////////////////////////////////////////////////
  76. // PUBLIC DATA ////////////////////////////////////////////////////////////////
  77. /// The Network singleton instance
  78. NetworkInterface *TheNetwork = NULL;
  79. // PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
  80. /**
  81. * The Network class is used to instantiate a singleton which
  82. * implements the interface to all Network operations such as message stream processing and network communications.
  83. */
  84. class Network : public NetworkInterface
  85. {
  86. public:
  87. //---------------------------------------------------------------------------------------
  88. // Setup / Teardown functions
  89. Network();
  90. ~Network();
  91. void init( void ); ///< Initialize or re-initialize the instance
  92. void reset( void ); ///< Reinitialize the network
  93. void update( void ); ///< Process command list
  94. void liteupdate( void ); ///< Do a lightweight update to send packets and pass messages.
  95. Bool deinit( void ); ///< Shutdown connections, release memory
  96. void setLocalAddress(UnsignedInt ip, UnsignedInt port);
  97. inline UnsignedInt getRunAhead(void) { return m_runAhead; }
  98. inline UnsignedInt getFrameRate(void) { return m_frameRate; }
  99. UnsignedInt getPacketArrivalCushion(void); ///< Returns the smallest packet arrival cushion since this was last called.
  100. Bool isFrameDataReady( void );
  101. void parseUserList( const GameInfo *game );
  102. void startGame(void); ///< Sets the network game frame counter to -1
  103. void sendChat(UnicodeString text, Int playerMask);
  104. void sendDisconnectChat(UnicodeString text);
  105. void sendFile(AsciiString path, UnsignedByte playerMask, UnsignedShort commandID);
  106. UnsignedShort sendFileAnnounce(AsciiString path, UnsignedByte playerMask);
  107. Int getFileTransferProgress(Int playerID, AsciiString path);
  108. Bool areAllQueuesEmpty(void);
  109. void quitGame();
  110. virtual void selfDestructPlayer(Int index);
  111. void voteForPlayerDisconnect(Int slot);
  112. virtual Bool isPacketRouter( void );
  113. // Bandwidth metrics
  114. Real getIncomingBytesPerSecond( void );
  115. Real getIncomingPacketsPerSecond( void );
  116. Real getOutgoingBytesPerSecond( void );
  117. Real getOutgoingPacketsPerSecond( void );
  118. Real getUnknownBytesPerSecond( void );
  119. Real getUnknownPacketsPerSecond( void );
  120. // Multiplayer Load Progress Functions
  121. void updateLoadProgress( Int percent );
  122. void loadProgressComplete( void );
  123. void sendTimeOutGameStart( void );
  124. #if defined(_INTERNAL) || defined(_DEBUG)
  125. // Disconnect screen testing
  126. virtual void toggleNetworkOn();
  127. #endif
  128. // Exposing some info contained in the Connection Manager
  129. UnsignedInt getLocalPlayerID( void );
  130. UnicodeString getPlayerName(Int playerNum);
  131. Int getNumPlayers(void );
  132. Int getAverageFPS() { return m_conMgr->getAverageFPS(); }
  133. Int getSlotAverageFPS(Int slot);
  134. void attachTransport(Transport *transport);
  135. void initTransport();
  136. void setSawCRCMismatch( void );
  137. Bool sawCRCMismatch( void ) { return m_sawCRCMismatch; }
  138. Bool isPlayerConnected( Int playerID );
  139. void notifyOthersOfCurrentFrame(); ///< Tells all the other players what frame we are on.
  140. void notifyOthersOfNewFrame(UnsignedInt frame); ///< Tells all the other players that we are on a new frame.
  141. Int getExecutionFrame(); ///< Returns the next valid frame for simultaneous command execution.
  142. // For disconnect blame assignment
  143. UnsignedInt getPingFrame();
  144. Int getPingsSent();
  145. Int getPingsRecieved();
  146. protected:
  147. void GetCommandsFromCommandList(); ///< Remove commands from TheCommandList and put them on the Network command list.
  148. void SendCommandsToConnectionManager(); ///< Send the new commands to the ConnectionManager
  149. Bool AllCommandsReady(UnsignedInt frame); ///< Do we have all the commands for the given frame?
  150. void RelayCommandsToCommandList(UnsignedInt frame); ///< Put the commands for the given frame onto TheCommandList.
  151. Bool isTransferCommand(GameMessage *msg); ///< Is this a command that needs to be transfered to the other clients?
  152. Bool processCommand(GameMessage *msg); ///< Whatever needs to be done as a result of this command, do it now.
  153. void processFrameSynchronizedNetCommand(NetCommandRef *msg); ///< If there is a network command that needs to be executed at the same frame number on all clients, it happens here.
  154. void processRunAheadCommand(NetRunAheadCommandMsg *msg); ///< Do what needs to be done when we get a new run ahead command.
  155. void processDestroyPlayerCommand(NetDestroyPlayerCommandMsg *msg); ///< Do what needs to be done when we need to destroy a player.
  156. void endOfGameCheck(); ///< Checks to see if its ok to leave this game. If it is, send the apropriate command to the game logic.
  157. Bool timeForNewFrame();
  158. ConnectionManager *m_conMgr; ///< The connection manager object
  159. UnsignedInt m_lastFrame; ///< The last game logic frame that was processed.
  160. NetLocalStatus m_localStatus; ///< My local status as a player in this game.
  161. Int m_runAhead; ///< The current run ahead of the game.
  162. Int m_frameRate;
  163. Int m_lastExecutionFrame; ///< The highest frame number that a command could have been executed on.
  164. Int m_lastFrameCompleted;
  165. Bool m_didSelfSlug;
  166. __int64 m_perfCountFreq; ///< The frequency of the performance counter.
  167. __int64 m_nextFrameTime; ///< When did we execute the last frame? For slugging the GameLogic...
  168. Bool m_frameDataReady; ///< Is the frame data for the next frame ready to be executed by TheGameLogic?
  169. // CRC info
  170. Bool m_checkCRCsThisFrame;
  171. Bool m_sawCRCMismatch;
  172. std::vector<UnsignedInt> m_CRC[MAX_SLOTS];
  173. std::list<Int> m_playersToDisconnect;
  174. GameWindow *m_messageWindow;
  175. #if defined(_DEBUG) || defined(_INTERNAL)
  176. Bool m_networkOn;
  177. #endif
  178. };
  179. UnsignedInt Network::getPingFrame()
  180. {
  181. return (m_conMgr)?m_conMgr->getPingFrame():0;
  182. }
  183. Int Network::getPingsSent()
  184. {
  185. return (m_conMgr)?m_conMgr->getPingsSent():0;
  186. }
  187. Int Network::getPingsRecieved()
  188. {
  189. return (m_conMgr)?m_conMgr->getPingsRecieved():0;
  190. }
  191. Bool Network::isPlayerConnected( Int playerID ) {
  192. if (playerID == getLocalPlayerID()) {
  193. return m_localStatus == NETLOCALSTATUS_INGAME || m_localStatus == NETLOCALSTATUS_LEAVING;
  194. }
  195. return m_conMgr->isPlayerConnected(playerID);
  196. }
  197. // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
  198. ///////////////////////////////////////////////////////////////////////////////
  199. // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
  200. ///////////////////////////////////////////////////////////////////////////////
  201. /**
  202. * This creates a network object and returns it.
  203. */
  204. NetworkInterface *NetworkInterface::createNetwork()
  205. {
  206. return NEW Network;
  207. }
  208. ////////////////////////////////////////////////////////////////////////////////
  209. /**
  210. * The constructor.
  211. */
  212. Network::Network()
  213. {
  214. //Added By Sadullah Nader
  215. //Initializations inserted
  216. m_checkCRCsThisFrame = FALSE;
  217. m_didSelfSlug = FALSE;
  218. m_frameDataReady = FALSE;
  219. m_sawCRCMismatch = FALSE;
  220. //
  221. m_conMgr = NULL;
  222. m_messageWindow = NULL;
  223. #if defined(_DEBUG) || defined(_INTERNAL)
  224. m_networkOn = TRUE;
  225. #endif
  226. }
  227. /**
  228. * The destructor.
  229. */
  230. Network::~Network()
  231. {
  232. deinit();
  233. }
  234. /**
  235. * This basically releases all the memory.
  236. */
  237. Bool Network::deinit( void )
  238. {
  239. if (m_conMgr)
  240. {
  241. m_conMgr->destroyGameMessages();
  242. delete m_conMgr;
  243. m_conMgr = NULL;
  244. }
  245. if (m_messageWindow) {
  246. TheWindowManager->winDestroy(m_messageWindow);
  247. m_messageWindow = NULL;
  248. }
  249. return true;
  250. }
  251. /**
  252. * Takes the network back to the initial state.
  253. */
  254. void Network::reset() {
  255. init();
  256. }
  257. /**
  258. * Initializes all the network subsystems.
  259. */
  260. void Network::init()
  261. {
  262. if (!deinit())
  263. {
  264. DEBUG_LOG(("Could not deinit network prior to init!\n"));
  265. return;
  266. }
  267. m_conMgr = NEW ConnectionManager;
  268. m_conMgr->init();
  269. m_lastFrame = 0;
  270. m_runAhead = min(max(30, MIN_RUNAHEAD), MAX_FRAMES_AHEAD/2); ///< @todo: don't hard-code the run-ahead.
  271. m_frameRate = 30;
  272. m_lastExecutionFrame = m_runAhead - 1; // subtract 1 since we're starting on frame 0
  273. m_lastFrameCompleted = m_runAhead - 1; // subtract 1 since we're starting on frame 0
  274. m_frameDataReady = FALSE;
  275. m_didSelfSlug = FALSE;
  276. m_localStatus = NETLOCALSTATUS_PREGAME;
  277. QueryPerformanceFrequency((LARGE_INTEGER *)&m_perfCountFreq);
  278. m_nextFrameTime = 0;
  279. m_sawCRCMismatch = FALSE;
  280. m_checkCRCsThisFrame = FALSE;
  281. DEBUG_LOG(("Network timing values:\n"));
  282. DEBUG_LOG(("NetworkFPSHistoryLength: %d\n", TheGlobalData->m_networkFPSHistoryLength));
  283. DEBUG_LOG(("NetworkLatencyHistoryLength: %d\n", TheGlobalData->m_networkLatencyHistoryLength));
  284. DEBUG_LOG(("NetworkRunAheadMetricsTime: %d\n", TheGlobalData->m_networkRunAheadMetricsTime));
  285. DEBUG_LOG(("NetworkCushionHistoryLength: %d\n", TheGlobalData->m_networkCushionHistoryLength));
  286. DEBUG_LOG(("NetworkRunAheadSlack: %d\n", TheGlobalData->m_networkRunAheadSlack));
  287. DEBUG_LOG(("NetworkKeepAliveDelay: %d\n", TheGlobalData->m_networkKeepAliveDelay));
  288. DEBUG_LOG(("NetworkDisconnectTime: %d\n", TheGlobalData->m_networkDisconnectTime));
  289. DEBUG_LOG(("NetworkPlayerTimeoutTime: %d\n", TheGlobalData->m_networkPlayerTimeoutTime));
  290. DEBUG_LOG(("NetworkDisconnectScreenNotifyTime: %d\n", TheGlobalData->m_networkDisconnectScreenNotifyTime));
  291. DEBUG_LOG(("Other network stuff:\n"));
  292. DEBUG_LOG(("FRAME_DATA_LENGTH = %d\n", FRAME_DATA_LENGTH));
  293. DEBUG_LOG(("FRAMES_TO_KEEP = %d\n", FRAMES_TO_KEEP));
  294. #if defined(_DEBUG) || defined(_INTERNAL)
  295. m_networkOn = TRUE;
  296. #endif
  297. return;
  298. }
  299. void Network::setSawCRCMismatch( void )
  300. {
  301. m_sawCRCMismatch = TRUE;
  302. TheScriptActions->closeWindows( TRUE );
  303. m_messageWindow = TheWindowManager->winCreateFromScript("Menus/CRCMismatch.wnd");
  304. TheScriptEngine->startEndGameTimer();
  305. TheRecorder->logCRCMismatch();
  306. // dump GameLogic random seed
  307. DEBUG_LOG(("GameLogic frame = %d\n", TheGameLogic->getFrame()));
  308. DEBUG_LOG(("GetGameLogicRandomSeedCRC() = %d\n", GetGameLogicRandomSeedCRC()));
  309. // dump CRCs
  310. {
  311. DEBUG_LOG(("--- GameState Dump ---\n"));
  312. #ifdef DEBUG_CRC
  313. outputCRCDumpLines();
  314. #endif
  315. DEBUG_LOG(("------ End Dump ------\n"));
  316. }
  317. {
  318. DEBUG_LOG(("--- DebugInfo Dump ---\n"));
  319. #ifdef DEBUG_CRC
  320. outputCRCDebugLines();
  321. #endif
  322. DEBUG_LOG(("------ End Dump ------\n"));
  323. }
  324. }
  325. /**
  326. * Take a user list and build the connection queues and player lists and stuff like that.
  327. */
  328. void Network::parseUserList( const GameInfo *game )
  329. {
  330. if (!game)
  331. {
  332. DEBUG_LOG(("FAILED parseUserList with a NULL game\n"));
  333. return;
  334. }
  335. m_conMgr->parseUserList(game);
  336. // Now that we have the players in this game, we need to reset the FrameData stuff.
  337. m_conMgr->destroyGameMessages();
  338. m_conMgr->zeroFrames(1, m_runAhead-1); ///< we zero out m_runAhead frames +1 because the game actually starts at frame 1.
  339. }
  340. /**
  341. * Guess what, we're starting a game!
  342. */
  343. void Network::startGame() {
  344. }
  345. /**
  346. * Tell the network which ip address the user has chosen to use. Well ok, they probably didn't choose
  347. * it explicitly, but regardless, this is the one we're going to use.
  348. */
  349. void Network::setLocalAddress(UnsignedInt ip, UnsignedInt port) {
  350. DEBUG_ASSERTCRASH(m_conMgr != NULL, ("Connection manager does not exist."));
  351. if (m_conMgr != NULL) {
  352. m_conMgr->setLocalAddress(ip, port);
  353. }
  354. }
  355. /**
  356. * Tell the network to initialize the transport object
  357. */
  358. void Network::initTransport() {
  359. DEBUG_ASSERTCRASH(m_conMgr != NULL, ("Connection manager does not exist."));
  360. if (m_conMgr != NULL) {
  361. m_conMgr->initTransport();
  362. }
  363. }
  364. void Network::attachTransport(Transport *transport) {
  365. DEBUG_ASSERTCRASH(m_conMgr != NULL, ("Connection manager does not exist."));
  366. if (m_conMgr != NULL) {
  367. m_conMgr->attachTransport(transport);
  368. }
  369. }
  370. /**
  371. * Does this command need to be transfered to the other game clients?
  372. */
  373. Bool Network::isTransferCommand(GameMessage *msg) {
  374. if ((msg != NULL) && ((msg->getType() > GameMessage::MSG_BEGIN_NETWORK_MESSAGES) && (msg->getType() < GameMessage::MSG_END_NETWORK_MESSAGES))) {
  375. return TRUE;
  376. }
  377. return FALSE;
  378. }
  379. /**
  380. * Take commands from TheCommandList and give them to the connection manager for transport.
  381. */
  382. void Network::GetCommandsFromCommandList() {
  383. GameMessage *msg = TheCommandList->getFirstMessage();
  384. GameMessage *next = NULL;
  385. while (msg != NULL) {
  386. next = msg->next();
  387. if (isTransferCommand(msg)) { // Is this something we should be sending to the other players?
  388. if (m_localStatus == NETLOCALSTATUS_INGAME) {
  389. m_conMgr->sendLocalGameMessage(msg, getExecutionFrame());
  390. }
  391. TheCommandList->removeMessage(msg); // This does not destroy msg's prev and next pointers, so they should still be valid.
  392. msg->deleteInstance();
  393. } else {
  394. if (processCommand(msg)) {
  395. TheCommandList->removeMessage(msg);
  396. msg->deleteInstance();
  397. }
  398. }
  399. msg = next;
  400. }
  401. }
  402. Int Network::getExecutionFrame() {
  403. Int logicFrame = TheGameLogic->getFrame() + m_runAhead;
  404. if (logicFrame > m_lastExecutionFrame) {
  405. m_lastExecutionFrame = logicFrame;
  406. return (logicFrame);
  407. }
  408. return m_lastExecutionFrame;
  409. }
  410. /**
  411. * This is where any processing that needs to be done for specific game messages.
  412. * Also check here to see if the logic frame number has changed to see if we need to
  413. * send our info for the last frame to the other players.
  414. * Return true if the message should be "eaten" by the network.
  415. */
  416. Bool Network::processCommand(GameMessage *msg)
  417. {
  418. if ((m_lastFrame != TheGameLogic->getFrame()) || (m_localStatus == NETLOCALSTATUS_PREGAME)) {
  419. // If this is the start of a new game logic frame, then tell the connection manager that the last
  420. // frame is over and that it should now produce a frame info packet for the other players.
  421. if (m_localStatus == NETLOCALSTATUS_PREGAME) {
  422. // a sort-of-hack that prevents extraneous frames from being executed before the game actually starts.
  423. // Idealy this shouldn't be necessary, but I don't think its hurting anything by being here.
  424. if (TheGameLogic->getFrame() == 1) {
  425. m_localStatus = NETLOCALSTATUS_INGAME;
  426. NetCommandList *netcmdlist = m_conMgr->getFrameCommandList(0); // clear out frame 0 since we skipped it
  427. netcmdlist->deleteInstance();
  428. } else {
  429. return FALSE;
  430. }
  431. }
  432. // Only send frame info packets for frames where we are actually going to be in the game.
  433. // The reason is so we don't have to wait for frame info packets to be sent that aren't going to
  434. // matter anyways when we actually try to leave the game ourselves.
  435. if (m_localStatus == NETLOCALSTATUS_INGAME) {
  436. Int executionFrame = getExecutionFrame();
  437. // Send command counts for all the frames we can.
  438. for (Int i = m_lastFrameCompleted + 1; i < executionFrame; ++i) {
  439. m_conMgr->processFrameTick(i);
  440. //DEBUG_LOG(("Network::processCommand - calling processFrameTick for frame %d\n", i));
  441. m_lastFrameCompleted = i;
  442. }
  443. }
  444. //DEBUG_LOG(("Next Execution Frame - %d, last frame completed - %d\n", getExecutionFrame(), m_lastFrameCompleted));
  445. m_lastFrame = TheGameLogic->getFrame();
  446. }
  447. // Are we leaving the game?
  448. // This has to happen after the check to see if this is the start of a new logic frame.
  449. // The reason is that we have to send all the frame info packets necessary to get to the
  450. // frame where everyone else is going to see that we left.
  451. if ((msg->getType() == GameMessage::MSG_CLEAR_GAME_DATA) && (m_localStatus == NETLOCALSTATUS_INGAME)) {
  452. Int executionFrame = getExecutionFrame();
  453. DEBUG_LOG(("Network::processCommand - local player leaving, executionFrame = %d, player leaving on frame %d\n", executionFrame, executionFrame+1));
  454. m_conMgr->handleLocalPlayerLeaving(executionFrame+1);
  455. m_conMgr->processFrameTick(executionFrame); // This is the last command we will execute, so send the command count.
  456. // Also, we are guaranteed not to send any more commands for this frame
  457. // since the local status will change to "Leaving" so we don't have to
  458. // worry about messing up the other players.
  459. m_conMgr->processFrameTick(executionFrame+1); // since we send it for executionFrame+1, we need to process both ticks
  460. m_lastFrameCompleted = executionFrame;
  461. DEBUG_LOG(("Network::processCommand - player leaving on frame %d\n", executionFrame));
  462. m_localStatus = NETLOCALSTATUS_LEAVING;
  463. return TRUE;
  464. }
  465. return FALSE;
  466. }
  467. /**
  468. * returns true if all the commands are ready for the given frame.
  469. */
  470. Bool Network::AllCommandsReady(UnsignedInt frame) {
  471. if (m_conMgr == NULL) {
  472. return TRUE;
  473. }
  474. if (m_localStatus == NETLOCALSTATUS_PREGAME) {
  475. return TRUE;
  476. }
  477. if (m_localStatus == NETLOCALSTATUS_POSTGAME) {
  478. return TRUE;
  479. }
  480. return m_conMgr->allCommandsReady(frame);// && m_conMgr->allCRCsReady(frame);
  481. }
  482. /**
  483. * Take commands from the connection manager and put them on TheCommandList.
  484. * The commands need to be put on in the same order across all clients.
  485. */
  486. void Network::RelayCommandsToCommandList(UnsignedInt frame) {
  487. if ((m_conMgr == NULL) || (m_localStatus == NETLOCALSTATUS_PREGAME)) {
  488. return;
  489. }
  490. m_checkCRCsThisFrame = FALSE;
  491. NetCommandList *netcmdlist = m_conMgr->getFrameCommandList(frame);
  492. NetCommandRef *msg = netcmdlist->getFirstMessage();
  493. while (msg != NULL) {
  494. NetCommandType cmdType = msg->getCommand()->getNetCommandType();
  495. if (cmdType == NETCOMMANDTYPE_GAMECOMMAND) {
  496. //DEBUG_LOG(("Network::RelayCommandsToCommandList - appending command %d of type %s to command list on frame %d\n", msg->getCommand()->getID(), ((NetGameCommandMsg *)msg->getCommand())->constructGameMessage()->getCommandAsAsciiString().str(), TheGameLogic->getFrame()));
  497. TheCommandList->appendMessage(((NetGameCommandMsg *)msg->getCommand())->constructGameMessage());
  498. } else {
  499. processFrameSynchronizedNetCommand(msg);
  500. }
  501. msg = msg->getNext();
  502. }
  503. for (std::list<Int>::iterator selfDestructIt = m_playersToDisconnect.begin(); selfDestructIt != m_playersToDisconnect.end(); ++selfDestructIt)
  504. {
  505. //Int playerToDisconnect = *selfDestructIt;
  506. //GameMessage *msg = newInstance(GameMessage)( GameMessage::MSG_SELF_DESTRUCT );
  507. //msg->friend_setPlayerIndex(playerToDisconnect);
  508. //msg->appendBooleanArgument(TRUE);
  509. //TheCommandList->appendMessage(msg);
  510. }
  511. m_playersToDisconnect.clear();
  512. netcmdlist->deleteInstance();
  513. }
  514. /**
  515. * This is where network commands that need to be executed on the same frame should be executed.
  516. */
  517. void Network::processFrameSynchronizedNetCommand(NetCommandRef *msg) {
  518. NetCommandMsg *cmdMsg = msg->getCommand();
  519. if (cmdMsg->getNetCommandType() == NETCOMMANDTYPE_PLAYERLEAVE) {
  520. PlayerLeaveCode retval = m_conMgr->processPlayerLeave((NetPlayerLeaveCommandMsg *)cmdMsg);
  521. if (retval == PLAYERLEAVECODE_LOCAL) {
  522. DEBUG_LOG(("Network::processFrameSynchronizedNetCommand - Local player left the game on frame %d.\n", TheGameLogic->getFrame()));
  523. m_localStatus = NETLOCALSTATUS_LEFT;
  524. } else if (retval == PLAYERLEAVECODE_PACKETROUTER) {
  525. DEBUG_LOG(("Network::processFrameSynchronizedNetCommand - Packet router left the game on frame %d\n", TheGameLogic->getFrame()));
  526. } else {
  527. DEBUG_LOG(("Network::processFrameSynchronizedNetCommand - Client left the game on frame %d\n", TheGameLogic->getFrame()));
  528. }
  529. }
  530. else if (cmdMsg->getNetCommandType() == NETCOMMANDTYPE_RUNAHEAD) {
  531. NetRunAheadCommandMsg *netmsg = (NetRunAheadCommandMsg *)cmdMsg;
  532. processRunAheadCommand(netmsg);
  533. DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command to set run ahead to %d and frame rate to %d on frame %d actually executed on frame %d\n", netmsg->getRunAhead(), netmsg->getFrameRate(), netmsg->getExecutionFrame(), TheGameLogic->getFrame()));
  534. }
  535. else if (cmdMsg->getNetCommandType() == NETCOMMANDTYPE_DESTROYPLAYER) {
  536. NetDestroyPlayerCommandMsg *netmsg = (NetDestroyPlayerCommandMsg *)cmdMsg;
  537. processDestroyPlayerCommand(netmsg);
  538. //DEBUG_LOG(("CRC command (%8.8X) on frame %d actually executed on frame %d\n", netmsg->getCRC(), netmsg->getExecutionFrame(), TheGameLogic->getFrame()));
  539. }
  540. }
  541. void Network::processRunAheadCommand(NetRunAheadCommandMsg *msg) {
  542. m_runAhead = msg->getRunAhead();
  543. m_frameRate = msg->getFrameRate();
  544. time_t frameGrouping = (1000 * m_runAhead) / m_frameRate; // number of miliseconds between packet sends
  545. frameGrouping = frameGrouping / 2; // since we only want the latency for one way to be a factor.
  546. // DEBUG_LOG(("Network::processRunAheadCommand - trying to set frame grouping to %d. run ahead = %d, m_frameRate = %d\n", frameGrouping, m_runAhead, m_frameRate));
  547. if (frameGrouping < 1) {
  548. frameGrouping = 1; // Having a value less than 1 doesn't make sense.
  549. }
  550. if (frameGrouping > 500) {
  551. frameGrouping = 500; // Max of a half a second.
  552. }
  553. m_conMgr->setFrameGrouping(frameGrouping);
  554. }
  555. void Network::processDestroyPlayerCommand(NetDestroyPlayerCommandMsg *msg)
  556. {
  557. UnsignedInt playerIndex = msg->getPlayerIndex();
  558. DEBUG_ASSERTCRASH(playerIndex < MAX_SLOTS, ("Bad player index"));
  559. if (playerIndex >= MAX_SLOTS)
  560. return;
  561. AsciiString playerName;
  562. playerName.format("player%d", playerIndex);
  563. Player *pPlayer = ThePlayerList->findPlayerWithNameKey(NAMEKEY(playerName));
  564. if (pPlayer)
  565. {
  566. GameMessage *msg = newInstance(GameMessage)(GameMessage::MSG_SELF_DESTRUCT);
  567. msg->appendBooleanArgument(FALSE);
  568. msg->friend_setPlayerIndex(pPlayer->getPlayerIndex());
  569. TheCommandList->appendMessage(msg);
  570. }
  571. DEBUG_LOG(("Saw DestroyPlayer from %d about %d for frame %d on frame %d\n", msg->getPlayerID(), msg->getPlayerIndex(),
  572. msg->getExecutionFrame(), TheGameLogic->getFrame()));
  573. }
  574. /**
  575. * Service queues, process message stream, etc
  576. */
  577. void Network::update( void )
  578. {
  579. //
  580. // 1. Take Commands off TheCommandList, hand them off to the ConnectionManager.
  581. // 2. Call ConnectionManager->update;
  582. // 3. Check to see if all the commands for the next frame are there.
  583. // 4. If all commands are there, put that frame's commands on TheCommandList.
  584. //
  585. m_frameDataReady = FALSE;
  586. #if defined(_DEBUG) || defined(_INTERNAL)
  587. if (m_networkOn == FALSE) {
  588. return;
  589. }
  590. #endif
  591. GetCommandsFromCommandList(); // Remove commands from TheCommandList and send them to the connection manager.
  592. if (m_conMgr != NULL) {
  593. if (m_localStatus == NETLOCALSTATUS_INGAME) {
  594. m_conMgr->updateRunAhead(m_runAhead, m_frameRate, m_didSelfSlug, getExecutionFrame());
  595. m_didSelfSlug = FALSE;
  596. }
  597. //m_conMgr->update(); // Do the priority thing, packetize thing. This also calls the Transport::update function.
  598. // depacketizes the incoming packets and puts them on the Network command list.
  599. }
  600. liteupdate();
  601. if ((m_localStatus == NETLOCALSTATUS_LEFT)) {// || (m_localStatus == NETLOCALSTATUS_LEAVING)) {
  602. endOfGameCheck();
  603. }
  604. if (AllCommandsReady(TheGameLogic->getFrame())) { // If all the commands are ready for the next frame...
  605. m_conMgr->handleAllCommandsReady();
  606. // DEBUG_LOG(("Network::update - frame %d is ready\n", TheGameLogic->getFrame()));
  607. if (timeForNewFrame()) { // This needs to come after any other pre-frame execution checks as this changes the timing variables.
  608. RelayCommandsToCommandList(TheGameLogic->getFrame()); // Put the commands for the next frame on TheCommandList.
  609. m_frameDataReady = TRUE; // Tell the GameEngine to run the commands for the new frame.
  610. }
  611. }
  612. }
  613. void Network::liteupdate() {
  614. #if defined(_DEBUG) || defined(_INTERNAL)
  615. if (m_networkOn == FALSE) {
  616. return;
  617. }
  618. #endif
  619. if (m_conMgr != NULL) {
  620. if (m_localStatus == NETLOCALSTATUS_PREGAME) {
  621. m_conMgr->update(FALSE);
  622. } else {
  623. m_conMgr->update(TRUE);
  624. }
  625. }
  626. }
  627. void Network::endOfGameCheck() {
  628. if (m_conMgr != NULL) {
  629. if (m_conMgr->canILeave()) {
  630. m_conMgr->disconnectLocalPlayer();
  631. TheMessageStream->appendMessage(GameMessage::MSG_CLEAR_GAME_DATA);
  632. m_localStatus = NETLOCALSTATUS_POSTGAME;
  633. DEBUG_LOG(("Network::endOfGameCheck - about to show the shell\n"));
  634. }
  635. #if defined(_DEBUG) || defined(_INTERNAL)
  636. else {
  637. m_conMgr->debugPrintConnectionCommands();
  638. }
  639. #endif
  640. }
  641. }
  642. Bool Network::timeForNewFrame() {
  643. __int64 curTime;
  644. QueryPerformanceCounter((LARGE_INTEGER *)&curTime);
  645. __int64 frameDelay = m_perfCountFreq / m_frameRate;
  646. /*
  647. * If we're pushing up against the edge of our run ahead, we should slow the framerate down a bit
  648. * to avoid being frozen by spikes in network lag. This will happen if another user's computer is
  649. * running too far behind us, so we need to slow down to let them catch up.
  650. */
  651. if (m_conMgr != NULL) {
  652. Real cushion = m_conMgr->getMinimumCushion();
  653. Real runAheadPercentage = m_runAhead * (TheGlobalData->m_networkRunAheadSlack / (Real)100.0); // If we are at least 50% into our slack, we need to slow down.
  654. if (cushion < runAheadPercentage) {
  655. // DEBUG_LOG(("Average cushion = %f, run ahead percentage = %f. Adjusting frameDelay from %I64d to ", cushion, runAheadPercentage, frameDelay));
  656. frameDelay += frameDelay / 10; // temporarily decrease the frame rate by 20%.
  657. // DEBUG_LOG(("%I64d\n", frameDelay));
  658. m_didSelfSlug = TRUE;
  659. // } else {
  660. // DEBUG_LOG(("Average cushion = %f, run ahead percentage = %f\n", cushion, runAheadPercentage));
  661. }
  662. }
  663. // Check to see if we can run another frame.
  664. if (curTime >= m_nextFrameTime) {
  665. // DEBUG_LOG(("Allowing a new frame, frameDelay = %I64d, curTime - m_nextFrameTime = %I64d\n", frameDelay, curTime - m_nextFrameTime));
  666. // if (m_nextFrameTime + frameDelay < curTime) {
  667. if ((m_nextFrameTime + (2 * frameDelay)) < curTime) {
  668. // If we get too far behind on our framerate we need to reset the nextFrameTime thing.
  669. m_nextFrameTime = curTime;
  670. // DEBUG_LOG(("Initializing m_nextFrameTime to %I64d\n", m_nextFrameTime));
  671. } else {
  672. // Set the soonest possible starting time for the next frame.
  673. m_nextFrameTime += frameDelay;
  674. // DEBUG_LOG(("m_nextFrameTime = %I64d\n", m_nextFrameTime));
  675. }
  676. return TRUE;
  677. }
  678. // DEBUG_LOG(("Slowing down frame rate. frame rate = %d, frame delay = %I64d, curTime - m_nextFrameTime = %I64d\n", m_frameRate, frameDelay, curTime - m_nextFrameTime));
  679. return FALSE;
  680. }
  681. /**
  682. * Returns true if the game commands for the next frame have been put on the command list.
  683. */
  684. Bool Network::isFrameDataReady() {
  685. return (m_frameDataReady || (m_localStatus == NETLOCALSTATUS_LEFT));
  686. }
  687. /**
  688. * returns the number of incoming bytes per second averaged over the last 30 sec.
  689. */
  690. Real Network::getIncomingBytesPerSecond( void )
  691. {
  692. if (m_conMgr)
  693. return m_conMgr->getIncomingBytesPerSecond();
  694. else
  695. return 0.0;
  696. }
  697. /**
  698. * returns the number of incoming packets per second averaged over the last 30 sec.
  699. */
  700. Real Network::getIncomingPacketsPerSecond( void )
  701. {
  702. if (m_conMgr)
  703. return m_conMgr->getIncomingPacketsPerSecond();
  704. else
  705. return 0.0;
  706. }
  707. /**
  708. * returns the number of outgoing bytes per second averaged over the last 30 sec.
  709. */
  710. Real Network::getOutgoingBytesPerSecond( void )
  711. {
  712. if (m_conMgr)
  713. return m_conMgr->getOutgoingBytesPerSecond();
  714. else
  715. return 0.0;
  716. }
  717. /**
  718. * returns the number of outgoing packets per second averaged over the last 30 sec.
  719. */
  720. Real Network::getOutgoingPacketsPerSecond( void )
  721. {
  722. if (m_conMgr)
  723. return m_conMgr->getOutgoingPacketsPerSecond();
  724. else
  725. return 0.0;
  726. }
  727. /**
  728. * returns the number of bytes received per second that are not from a generals client averaged over 30 sec.
  729. */
  730. Real Network::getUnknownBytesPerSecond( void )
  731. {
  732. if (m_conMgr)
  733. return m_conMgr->getUnknownBytesPerSecond();
  734. else
  735. return 0.0;
  736. }
  737. /**
  738. * returns the number of packets received per second that are not from a generals client averaged over 30 sec.
  739. */
  740. Real Network::getUnknownPacketsPerSecond( void )
  741. {
  742. if (m_conMgr)
  743. return m_conMgr->getUnknownPacketsPerSecond();
  744. else
  745. return 0.0;
  746. }
  747. /**
  748. * returns the smallest packet arrival cushion since this was last called.
  749. */
  750. UnsignedInt Network::getPacketArrivalCushion( void )
  751. {
  752. if (m_conMgr)
  753. return m_conMgr->getPacketArrivalCushion();
  754. else
  755. return 0;
  756. }
  757. /**
  758. * Sends a line of chat to the other players
  759. */
  760. void Network::sendChat(UnicodeString text, Int playerMask) {
  761. Int executionFrame = getExecutionFrame();
  762. m_conMgr->sendChat(text, playerMask, executionFrame);
  763. }
  764. /**
  765. * Sends a line of chat to the other players using the disconnect manager.
  766. */
  767. void Network::sendDisconnectChat(UnicodeString text) {
  768. m_conMgr->sendDisconnectChat(text);
  769. }
  770. // send a file. woohoo.
  771. void Network::sendFile(AsciiString path, UnsignedByte playerMask, UnsignedShort commandID)
  772. {
  773. m_conMgr->sendFile(path, playerMask, commandID);
  774. }
  775. // send a file. woohoo.
  776. UnsignedShort Network::sendFileAnnounce(AsciiString path, UnsignedByte playerMask)
  777. {
  778. return m_conMgr->sendFileAnnounce(path, playerMask);
  779. }
  780. Int Network::getFileTransferProgress(Int playerID, AsciiString path)
  781. {
  782. return m_conMgr->getFileTransferProgress(playerID, path);
  783. }
  784. Bool Network::areAllQueuesEmpty(void)
  785. {
  786. return m_conMgr->canILeave();
  787. }
  788. /**
  789. * Quit the game now. This should only be called from the disconnect screen.
  790. */
  791. void Network::quitGame() {
  792. if (m_conMgr != NULL) {
  793. m_conMgr->quitGame();
  794. }
  795. TheMessageStream->appendMessage(GameMessage::MSG_CLEAR_GAME_DATA);
  796. m_localStatus = NETLOCALSTATUS_POSTGAME;
  797. DEBUG_LOG(("Network::quitGame - quitting game..."));
  798. }
  799. void Network::selfDestructPlayer(Int index)
  800. {
  801. m_playersToDisconnect.push_back(index);
  802. }
  803. Bool Network::isPacketRouter( void )
  804. {
  805. return m_conMgr && m_conMgr->isPacketRouter();
  806. }
  807. /**
  808. * Register a vote towards a player being disconnected.
  809. */
  810. void Network::voteForPlayerDisconnect(Int slot) {
  811. if (m_conMgr != NULL) {
  812. m_conMgr->voteForPlayerDisconnect(slot);
  813. }
  814. }
  815. void Network::updateLoadProgress( Int percent )
  816. {
  817. if (m_conMgr != NULL) {
  818. m_conMgr->updateLoadProgress( percent );
  819. }
  820. }
  821. void Network::loadProgressComplete( void )
  822. {
  823. if (m_conMgr != NULL) {
  824. m_conMgr->loadProgressComplete();
  825. }
  826. }
  827. void Network::sendTimeOutGameStart( void )
  828. {
  829. if (m_conMgr != NULL) {
  830. m_conMgr->sendTimeOutGameStart();
  831. }
  832. }
  833. UnsignedInt Network::getLocalPlayerID()
  834. {
  835. if (m_conMgr != NULL) {
  836. return m_conMgr->getLocalPlayerID();
  837. }
  838. return 49;
  839. }
  840. UnicodeString Network::getPlayerName(Int playerNum)
  841. {
  842. if (playerNum == m_conMgr->getLocalPlayerID()) {
  843. if (m_localStatus != NETLOCALSTATUS_INGAME) {
  844. return UnicodeString::TheEmptyString;
  845. }
  846. }
  847. if (m_conMgr != NULL) {
  848. return m_conMgr->getPlayerName( playerNum );
  849. }
  850. return UnicodeString::TheEmptyString;
  851. }
  852. Int Network::getNumPlayers()
  853. {
  854. if (m_conMgr != NULL) {
  855. return m_conMgr->getNumPlayers();
  856. }
  857. return -1;
  858. }
  859. Int Network::getSlotAverageFPS(Int slot) {
  860. if (m_conMgr != NULL) {
  861. return m_conMgr->getSlotAverageFPS(slot);
  862. }
  863. return -1;
  864. }
  865. #if defined(_DEBUG) || defined(_INTERNAL)
  866. void Network::toggleNetworkOn() {
  867. if (m_networkOn == TRUE) {
  868. m_networkOn = FALSE;
  869. } else {
  870. m_networkOn = TRUE;
  871. }
  872. }
  873. #endif
  874. void Network::notifyOthersOfCurrentFrame() {
  875. if (m_conMgr != NULL) {
  876. m_conMgr->notifyOthersOfCurrentFrame(TheGameLogic->getFrame());
  877. }
  878. }
  879. void Network::notifyOthersOfNewFrame(UnsignedInt frame) {
  880. if (m_conMgr != NULL) {
  881. m_conMgr->notifyOthersOfNewFrame(frame);
  882. }
  883. }