Network.cpp 83 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "StdH.h"
  13. #include <Engine/Build.h>
  14. #include <Engine/Base/Console.h>
  15. #include <Engine/Base/CRCTable.h>
  16. #include <Engine/Base/Shell.h>
  17. #include <Engine/Base/ProgressHook.h>
  18. #include <Engine/Network/Server.h>
  19. #include <Engine/Network/SessionState.h>
  20. #include <Engine/Network/Network.h>
  21. #include <Engine/Network/PlayerSource.h>
  22. #include <Engine/Network/PlayerBuffer.h>
  23. #include <Engine/Network/PlayerTarget.h>
  24. #include <Engine/Entities/InternalClasses.h>
  25. #include <Engine/Entities/Precaching.h>
  26. #include <Engine/Network/CommunicationInterface.h>
  27. #include <Engine/Templates/Stock_CModelData.h>
  28. #include <Engine/Templates/Stock_CAnimData.h>
  29. #include <Engine/Templates/Stock_CTextureData.h>
  30. #include <Engine/Templates/Stock_CSoundData.h>
  31. #include <Engine/Templates/Stock_CEntityClass.h>
  32. #include <Engine/Base/Statistics_internal.h>
  33. #include <Engine/Graphics/DrawPort.h>
  34. #include <Engine/Sound/SoundLibrary.h>
  35. #include <Engine/Sound/SoundListener.h>
  36. #include <Engine/Rendering/Render.h>
  37. #include <Engine/Rendering/Render_internal.h>
  38. #include <Engine/Base/ListIterator.inl>
  39. #include <Engine/Math/Float.h>
  40. #include <Engine/Rendering/RenderProfile.h>
  41. #include <Engine/Network/NetworkProfile.h>
  42. #include <Engine/Network/LevelChange.h>
  43. #include <Engine/Brushes/BrushArchive.h>
  44. #include <Engine/Entities/Entity.h>
  45. #include <Engine/Models/ModelObject.h>
  46. #include <Engine/Ska/ModelInstance.h>
  47. #include <Engine/Entities/ShadingInfo.h>
  48. #include <Engine/Entities/EntityCollision.h>
  49. #include <Engine/Entities/LastPositions.h>
  50. #include <Engine/Templates/DynamicContainer.cpp>
  51. #include <Engine/Templates/DynamicArray.cpp>
  52. #include <Engine/Templates/StaticArray.cpp>
  53. #include <Engine/Templates/StaticStackArray.cpp>
  54. #include <Engine/Templates/Stock_CAnimData.h>
  55. #include <Engine/Templates/Stock_CTextureData.h>
  56. #include <Engine/Templates/Stock_CSoundData.h>
  57. #include <Engine/Templates/Stock_CEntityClass.h>
  58. #include <Engine/Templates/Stock_CModelData.h>
  59. #include <Engine/Templates/Stock_CAnimSet.h>
  60. #include <Engine/Templates/Stock_CMesh.h>
  61. #include <Engine/Templates/Stock_CShader.h>
  62. #include <Engine/Templates/Stock_CSkeleton.h>
  63. #include <Engine/GameAgent/GameAgent.h>
  64. // pointer to global instance of the only game object in the application
  65. CNetworkLibrary *_pNetwork= NULL;
  66. extern BOOL _bNeedPretouch;
  67. extern BOOL _bMultiPlayer = FALSE;
  68. extern INDEX _ctEntities = 0;
  69. extern INDEX _ctPredictorEntities = 0;
  70. extern LevelChangePhase _lphCurrent = LCP_NOCHANGE;
  71. extern BOOL _bTempNetwork = FALSE; // set while using temporary second network object
  72. extern BOOL con_bCapture;
  73. extern CTString con_strCapture;
  74. static CWorld *_pwoCurrentWorld = NULL;
  75. static FLOAT _bStartDemoRecordingNextTime = FALSE;
  76. static FLOAT _bStopDemoRecordingNextTime = FALSE;
  77. static INDEX dem_iRecordedNumber = 0;
  78. // network control
  79. extern INDEX ser_bReportSyncOK = FALSE;
  80. extern INDEX ser_bReportSyncBad = TRUE;
  81. extern INDEX ser_bReportSyncLate = FALSE;
  82. extern INDEX ser_bReportSyncEarly = FALSE;
  83. extern INDEX ser_bPauseOnSyncBad = FALSE;
  84. extern INDEX ser_iKickOnSyncBad = 10;
  85. extern INDEX ser_bKickOnSyncLate = 1;
  86. extern INDEX ser_iRememberBehind = 3000;
  87. extern INDEX ser_iExtensiveSyncCheck = 0;
  88. extern INDEX ser_bClientsMayPause = TRUE;
  89. extern FLOAT ser_tmSyncCheckFrequency = 1.0f;
  90. extern INDEX ser_iSyncCheckBuffer = 60;
  91. extern INDEX ser_bEnumeration = TRUE;
  92. extern INDEX ser_bPingGameAgent = TRUE;
  93. extern FLOAT ser_tmKeepAlive = 0.1f;
  94. extern FLOAT ser_tmPingUpdate = 3.0f;
  95. extern INDEX ser_bWaitFirstPlayer = 0;
  96. extern INDEX ser_iMaxAllowedBPS = 8000;
  97. extern CTString ser_strIPMask = "";
  98. extern CTString ser_strNameMask = "";
  99. extern INDEX ser_bInverseBanning = FALSE;
  100. extern CTString ser_strMOTD = "";
  101. extern INDEX cli_bEmulateDesync = FALSE;
  102. extern INDEX cli_bDumpSync = FALSE;
  103. extern INDEX cli_bDumpSyncEachTick = FALSE;
  104. extern INDEX cli_bAutoAdjustSettings = FALSE;
  105. extern FLOAT cli_tmAutoAdjustThreshold = 2.0f;
  106. extern INDEX cli_bPrediction = FALSE;
  107. extern INDEX cli_iMaxPredictionSteps = 10;
  108. extern INDEX cli_bPredictIfServer = FALSE;
  109. extern INDEX cli_bPredictLocalPlayers = TRUE;
  110. extern INDEX cli_bPredictRemotePlayers = FALSE;
  111. extern FLOAT cli_fPredictEntitiesRange = 20.0f;
  112. extern INDEX cli_bLerpActions = FALSE;
  113. extern INDEX cli_bReportPredicted = FALSE;
  114. extern INDEX cli_iSendBehind = 3;
  115. extern INDEX cli_iPredictionFlushing = 1;
  116. extern INDEX cli_iBufferActions = 1;
  117. extern INDEX cli_iMaxBPS = 4000;
  118. extern INDEX cli_iMinBPS = 0;
  119. extern INDEX net_iCompression = 1;
  120. extern INDEX net_bLookupHostNames = FALSE;
  121. extern INDEX net_bReportPackets = FALSE;
  122. extern INDEX net_iMaxSendRetries = 10;
  123. extern FLOAT net_fSendRetryWait = 0.5f;
  124. extern INDEX net_bReportTraffic = FALSE;
  125. extern INDEX net_bReportICMPErrors = FALSE;
  126. extern INDEX net_bReportMiscErrors = FALSE;
  127. extern INDEX net_bLerping = TRUE;
  128. extern INDEX net_iGraphBuffer = 100;
  129. extern INDEX net_iExactTimer = 2;
  130. extern INDEX net_bDumpStreamBlocks = 0;
  131. extern INDEX net_bDumpConnectionInfo = 0;
  132. extern INDEX net_iPort = 25600;
  133. extern CTString net_strLocalHost = "";
  134. extern CTString net_strLocationCode = "";
  135. extern CTString net_strConnectPassword = "";
  136. extern CTString net_strAdminPassword = "";
  137. extern CTString net_strVIPPassword = "";
  138. extern CTString net_strObserverPassword = "";
  139. extern INDEX net_iVIPReserve = 0;
  140. extern INDEX net_iMaxObservers = 16;
  141. extern INDEX net_iMaxClients = 0;
  142. extern FLOAT net_tmConnectionTimeout = 30.0f;
  143. extern FLOAT net_tmProblemsTimeout = 5.0f;
  144. extern FLOAT net_tmDisconnectTimeout = 300.0f; // must be higher for level changing
  145. extern INDEX net_bReportCRC = FALSE;
  146. extern FLOAT net_fDropPackets = 0.0f;
  147. extern FLOAT net_tmLatency = 0.0f;
  148. extern INDEX ent_bReportSpawnInWall = FALSE;
  149. extern FLOAT cmd_tmTick = 0.0f;
  150. extern CTString cmd_cmdOnTick = "";
  151. extern CTString cmd_strChatSender = "";
  152. extern CTString cmd_strChatMessage = "";
  153. extern CTString cmd_cmdOnChat = "";
  154. extern INDEX net_ctChatMessages = 0; // counter for incoming chat messages
  155. extern CPacketBufferStats _pbsSend;
  156. extern CPacketBufferStats _pbsRecv;
  157. extern BOOL _bPredictionActive = FALSE;
  158. class CGatherCRC {
  159. public:
  160. BOOL bOld;
  161. CGatherCRC();
  162. ~CGatherCRC();
  163. };
  164. CGatherCRC::CGatherCRC() {
  165. bOld = CRCT_bGatherCRCs;
  166. }
  167. CGatherCRC::~CGatherCRC() {
  168. CRCT_bGatherCRCs = bOld;
  169. }
  170. // precache control
  171. extern INDEX _precache_NONE = PRECACHE_NONE;
  172. extern INDEX _precache_SMART = PRECACHE_SMART;
  173. extern INDEX _precache_ALL = PRECACHE_ALL;
  174. extern INDEX _precache_PARANOIA = PRECACHE_PARANOIA;
  175. extern INDEX gam_iPrecachePolicy = _precache_SMART;
  176. extern INDEX _precache_bNowPrecaching = FALSE;
  177. extern INDEX dbg_bBreak = FALSE;
  178. extern INDEX gam_bPretouch = FALSE;
  179. extern FLOAT phy_fCollisionCacheAhead = 5.0f;
  180. extern FLOAT phy_fCollisionCacheAround = 1.5f;
  181. extern FLOAT cli_fPredictionFilter = 0.5f;
  182. extern INDEX shd_bCacheAll;
  183. // input
  184. extern INDEX inp_iKeyboardReadingMethod = 2; // 0=getasynckey, 1=virtkeytrap, 2=scancodetrap
  185. extern INDEX inp_bAllowMouseAcceleration = TRUE;
  186. extern FLOAT inp_fMouseSensitivity = 1.0f;
  187. extern INDEX inp_bMousePrecision = FALSE;
  188. extern FLOAT inp_fMousePrecisionFactor = 4.0f;
  189. extern FLOAT inp_fMousePrecisionThreshold = 10.0f;
  190. extern FLOAT inp_fMousePrecisionTimeout = 0.25f;
  191. extern FLOAT inp_bInvertMouse = FALSE;
  192. extern INDEX inp_bFilterMouse = FALSE;
  193. extern INDEX inp_bAllowPrescan = TRUE;
  194. extern INDEX inp_i2ndMousePort = 0; // COM no (0=disable)
  195. extern FLOAT inp_f2ndMouseSensitivity = 1.0f;
  196. extern INDEX inp_b2ndMousePrecision = FALSE;
  197. extern FLOAT inp_f2ndMousePrecisionFactor = 4.0f;
  198. extern FLOAT inp_f2ndMousePrecisionThreshold = 10.0f;
  199. extern FLOAT inp_f2ndMousePrecisionTimeout = 0.25f;
  200. extern INDEX inp_bInvert2ndMouse = FALSE;
  201. extern INDEX inp_bFilter2ndMouse = FALSE;
  202. extern INDEX inp_iMButton4Up;
  203. extern INDEX inp_iMButton4Dn;
  204. extern INDEX inp_iMButton5Up;
  205. extern INDEX inp_iMButton5Dn;
  206. extern INDEX inp_bMsgDebugger;
  207. extern INDEX inp_ctJoysticksAllowed;
  208. extern INDEX inp_bForceJoystickPolling;
  209. extern INDEX inp_bAutoDisableJoysticks;
  210. extern INDEX wed_bUseGenericTextureReplacement = FALSE;
  211. extern void RendererInfo(void);
  212. extern void ClearRenderer(void);
  213. // cache all shadowmaps now
  214. extern void CacheShadows(void)
  215. {
  216. // mute all sounds
  217. _pSound->Mute();
  218. CWorld *pwo = (CWorld*)_pShell->GetINDEX("pwoCurrentWorld");
  219. if( pwo!=NULL) {
  220. pwo->wo_baBrushes.CacheAllShadowmaps();
  221. CPrintF( TRANS("All shadows recached"));
  222. if( shd_bCacheAll) CPrintF(".\n");
  223. else CPrintF( TRANS(", but not for long.\n(precache all shadows function is disabled)\n"));
  224. }
  225. // mark that we need pretouching
  226. _bNeedPretouch = TRUE;
  227. }
  228. // check if a name or IP matches a mask
  229. extern BOOL MatchesBanMask(const CTString &strString, const CTString &strMask)
  230. {
  231. CTString strRest = strMask;
  232. CTString strLine;
  233. while(strRest!="") {
  234. strLine = strRest;
  235. strLine.OnlyFirstLine();
  236. strRest.RemovePrefix(strLine);
  237. strRest.DeleteChar(0);
  238. if (strString.Matches(strLine)) {
  239. return TRUE;
  240. }
  241. }
  242. return FALSE;
  243. }
  244. extern CTString RemoveSubstring(const CTString &strFull, const CTString &strSub);
  245. static void AddIPMask(void* pArgs)
  246. {
  247. CTString strIP = *NEXTARGUMENT(CTString*);
  248. ser_strIPMask+= strIP+"\n";
  249. }
  250. static void RemIPMask(void* pArgs)
  251. {
  252. CTString strIP = *NEXTARGUMENT(CTString*);
  253. ser_strIPMask = RemoveSubstring(ser_strIPMask, strIP+"\n");
  254. }
  255. static void AddNameMask(void* pArgs)
  256. {
  257. CTString strName = *NEXTARGUMENT(CTString*);
  258. ser_strNameMask += strName+"\n";
  259. }
  260. static void RemNameMask(void* pArgs)
  261. {
  262. CTString strName = *NEXTARGUMENT(CTString*);
  263. ser_strNameMask = RemoveSubstring(ser_strNameMask, strName+"\n");
  264. }
  265. static void StartDemoRecording(void)
  266. {
  267. _bStartDemoRecordingNextTime = TRUE;
  268. }
  269. static void StopDemoRecording(void)
  270. {
  271. _bStopDemoRecordingNextTime = TRUE;
  272. }
  273. static void NetworkInfo(void)
  274. {
  275. CPrintF("*Network library information:\n");
  276. CPrintF("Entities existing: %d\n", _ctEntities);
  277. CPrintF("Predictor entities existing: %d\n", _ctPredictorEntities);
  278. CPrintF("Server:\n");
  279. if (_pNetwork->ga_srvServer.srv_bActive) {
  280. CPrintF(" last processed tick: %g\n", _pNetwork->ga_srvServer.srv_tmLastProcessedTick);
  281. CPrintF(" last processed sequence: %d\n", _pNetwork->ga_srvServer.srv_iLastProcessedSequence);
  282. CPrintF(" players:\n");
  283. for(INDEX iplb=0; iplb<_pNetwork->ga_srvServer.srv_aplbPlayers.Count(); iplb++) {
  284. CPlayerBuffer &plb = _pNetwork->ga_srvServer.srv_aplbPlayers[iplb];
  285. if (plb.plb_Active) {
  286. CPrintF(" %2d(%2d):'%s'@client%2d: (%dact)\n",
  287. iplb, plb.plb_Index, plb.plb_pcCharacter.GetNameForPrinting(),
  288. plb.plb_iClient, plb.plb_abReceived.GetCount());
  289. }
  290. }
  291. CPrintF(" clients:\n");
  292. for(INDEX iSession=0; iSession<_pNetwork->ga_srvServer.srv_assoSessions.Count(); iSession++) {
  293. CSessionSocket &sso = _pNetwork->ga_srvServer.srv_assoSessions[iSession];
  294. if (sso.sso_bActive) {
  295. CPrintF(" %2d:'%s'\n", iSession, _cmiComm.Server_GetClientName(iSession)),
  296. CPrintF(" buffer: %dblk=%dk\n",
  297. sso.sso_nsBuffer.GetUsedBlocks(),
  298. sso.sso_nsBuffer.GetUsedMemory()/1024);
  299. CPrintF(" state:");
  300. if (sso.sso_iDisconnectedState>0) {
  301. CPrintF(" disconnecting");
  302. } else if (sso.sso_bSendStream) {
  303. CPrintF(" connected");
  304. } else {
  305. CPrintF(" connecting");
  306. }
  307. CPrintF("\n");
  308. }
  309. }
  310. } else {
  311. CPrintF(" not a server\n");
  312. }
  313. CPrintF("Session state:\n");
  314. CPrintF(" buffer: (%dblk)%dk\n",
  315. _pNetwork->ga_sesSessionState.ses_nsGameStream.GetUsedBlocks(),
  316. _pNetwork->ga_sesSessionState.ses_nsGameStream.GetUsedMemory()/1024);
  317. CPrintF(" last processed tick: %g\n", _pNetwork->ga_sesSessionState.ses_tmLastProcessedTick);
  318. CPrintF(" last processed sequence: %d\n", _pNetwork->ga_sesSessionState.ses_iLastProcessedSequence);
  319. CPrintF(" level change: %d\n", _pNetwork->ga_sesSessionState.ses_iLevel);
  320. for(INDEX iplt=0; iplt<_pNetwork->ga_sesSessionState.ses_apltPlayers.Count(); iplt++) {
  321. CPlayerTarget &plt = _pNetwork->ga_sesSessionState.ses_apltPlayers[iplt];
  322. if (plt.plt_bActive) {
  323. ULONG ulID = -1;
  324. if (plt.plt_penPlayerEntity!=NULL) {
  325. ulID = plt.plt_penPlayerEntity->en_ulID;
  326. }
  327. CPrintF(" player %2d (ID:%d): (%dact)\n", iplt, ulID, plt.plt_abPrediction.GetCount());
  328. }
  329. }
  330. if (TIMER_PROFILING) {
  331. CTString strNetProfile;
  332. _pfNetworkProfile.Report(strNetProfile);
  333. CPrintF(strNetProfile);
  334. }
  335. }
  336. static void ListPlayers(void)
  337. {
  338. CPrintF("player list:\n");
  339. if (!_pNetwork->ga_srvServer.srv_bActive) {
  340. CPrintF(" <not a server>\n");
  341. return;
  342. }
  343. CPrintF(" client# name\n");
  344. CPrintF(" ----------------------\n");
  345. for(INDEX iplb=0; iplb<_pNetwork->ga_srvServer.srv_aplbPlayers.Count(); iplb++) {
  346. CPlayerBuffer &plb = _pNetwork->ga_srvServer.srv_aplbPlayers[iplb];
  347. if (plb.plb_Active) {
  348. CPrintF(" %-2d %s\n", plb.plb_iClient, plb.plb_pcCharacter.GetNameForPrinting());
  349. }
  350. }
  351. CPrintF(" ----------------------\n");
  352. }
  353. static void KickClient(INDEX iClient, const CTString &strReason)
  354. {
  355. if (!_pNetwork->IsServer()) {
  356. CPrintF( TRANS("Only server can kick people!\n"));
  357. return;
  358. }
  359. iClient = Clamp(iClient, INDEX(0), INDEX(NET_MAXGAMECOMPUTERS));
  360. if (!_pNetwork->ga_srvServer.srv_assoSessions[iClient].IsActive()) {
  361. CPrintF(TRANS("Client not connected!\n"));
  362. return;
  363. }
  364. if (iClient == 0) {
  365. CPrintF(TRANS("Can't kick local client!\n"));
  366. return;
  367. }
  368. CPrintF( TRANS("Kicking %d with explanation '%s'...\n"), iClient, strReason);
  369. _pNetwork->ga_srvServer.SendDisconnectMessage(iClient, "Admin: "+strReason);
  370. }
  371. static void KickClientCfunc(void* pArgs)
  372. {
  373. INDEX iClient = NEXTARGUMENT(INDEX);
  374. CTString strReason = *NEXTARGUMENT(CTString*);
  375. KickClient(iClient, strReason);
  376. }
  377. static void KickByName(const CTString &strName, const CTString &strReason)
  378. {
  379. if (!_pNetwork->IsServer()) {
  380. CPrintF( TRANS("Only server can kick people!\n"));
  381. return;
  382. }
  383. for(INDEX iplb=0; iplb<_pNetwork->ga_srvServer.srv_aplbPlayers.Count(); iplb++) {
  384. CPlayerBuffer &plb = _pNetwork->ga_srvServer.srv_aplbPlayers[iplb];
  385. if (plb.plb_Active && plb.plb_pcCharacter.GetNameForPrinting().Undecorated().Matches(strName)) {
  386. KickClient(plb.plb_iClient, strReason);
  387. }
  388. }
  389. }
  390. static void KickByNameCfunc(void* pArgs)
  391. {
  392. CTString strName = *NEXTARGUMENT(CTString*);
  393. CTString strReason = *NEXTARGUMENT(CTString*);
  394. KickByName(strName, strReason);
  395. }
  396. static void Admin(void* pArgs)
  397. {
  398. CTString strCommand = *NEXTARGUMENT(CTString*);
  399. CNetworkMessage nm(MSG_ADMIN_COMMAND);
  400. nm<<net_strAdminPassword<<strCommand;
  401. _pNetwork->SendToServerReliable(nm);
  402. }
  403. static void StockInfo(void)
  404. {
  405. // find memory used by shadowmap (both cached and uploaded)
  406. INDEX ctCachedShadows=0, ctDynamicShadows=0, ctFlatShadows=0;
  407. SLONG slStaticMemory=0, slDynamicMemory=0, slUploadMemory=0;
  408. SLONG slShdBytes=0, slSlackMemory=0, slFlatMemory=0;
  409. INDEX ct256=0, ct128=0, ct64=0, ct32=0, ct16=0;
  410. SLONG sl256Memory=0, sl128Memory=0, sl64Memory=0, sl32Memory=0, sl16Memory=0;
  411. if( _pGfx!=NULL)
  412. {
  413. FLOAT fSlackRatio;
  414. FOREACHINLIST( CShadowMap, sm_lnInGfx, _pGfx->gl_lhCachedShadows, itsm)
  415. { // get polygon size in pixels (used portion of shadowmap)
  416. SLONG slStaticSize, slDynamicSize, slUploadSize;
  417. BOOL bIsFlat = itsm->GetUsedMemory( slStaticSize, slDynamicSize, slUploadSize, fSlackRatio);
  418. SLONG slTotalSize = slDynamicSize+slUploadSize;
  419. if( bIsFlat) {
  420. slStaticMemory += 4;
  421. slTotalSize += 4;
  422. slFlatMemory += slStaticSize;
  423. ctFlatShadows++;
  424. } else {
  425. slStaticMemory += slStaticSize;
  426. slTotalSize += slStaticSize;
  427. if( slTotalSize>0) ctCachedShadows++;
  428. }
  429. if( slDynamicSize>0) {
  430. slDynamicMemory += slDynamicSize;
  431. ctDynamicShadows++;
  432. }
  433. slUploadMemory += slUploadSize;
  434. slShdBytes += slTotalSize + sizeof(CShadowMap);
  435. slSlackMemory += slTotalSize*fSlackRatio;
  436. if( !bIsFlat) { // by size ...
  437. if( slStaticSize>128*1024) { ct256++; sl256Memory+=slTotalSize; }
  438. else if( slStaticSize> 64*1024) { ct128++; sl128Memory+=slTotalSize; }
  439. else if( slStaticSize> 32*1024) { ct64++; sl64Memory +=slTotalSize; }
  440. else if( slStaticSize> 16*1024) { ct32++; sl32Memory +=slTotalSize; }
  441. else if( slStaticSize> 0) { ct16++; sl16Memory +=slTotalSize; }
  442. }
  443. }
  444. // report shadowmap memory usage (if any)
  445. if( slShdBytes>0) {
  446. CPrintF( "\nCached shadowmaps:\n");
  447. CPrintF( " Total: %d in %d KB with %d%% (%d KB) of slack space\n", ctCachedShadows, slShdBytes/1024, slSlackMemory*100/slShdBytes, slSlackMemory/1024);
  448. CPrintF( " Static: %d KB\n", slStaticMemory/1024);
  449. CPrintF( " Upload: %d KB\n", slUploadMemory/1024);
  450. CPrintF( " Dynamic: %d in %d KB\n", ctDynamicShadows, slDynamicMemory/1024);
  451. if( ctCachedShadows<1) ctCachedShadows=1; // for percentage calc
  452. CPrintF( " Flats: %d (%d%%) with %d KB saved\n", ctFlatShadows, ctFlatShadows*100/ctCachedShadows, slFlatMemory/1024);
  453. CPrintF("of size:\n");
  454. CPrintF( " >128K: %4d in %d KB\n", ct256, sl256Memory/1024);
  455. CPrintF( " 128-64K: %4d in %d KB\n", ct128, sl128Memory/1024);
  456. CPrintF( " 64-32K: %4d in %d KB\n", ct64, sl64Memory /1024);
  457. CPrintF( " 32-16K: %4d in %d KB\n", ct32, sl32Memory /1024);
  458. CPrintF( " <=16K: %4d in %d KB\n", ct16, sl16Memory /1024);
  459. }
  460. }
  461. // report world stats
  462. INDEX ctEntities=0, ctShadowLayers=0, ctPolys=0, ctPlanes=0, ctEdges=0, ctVertices=0, ctSectors=0;
  463. SLONG slEntBytes=0, slLyrBytes=0, slPlyBytes=0, slPlnBytes=0, slEdgBytes=0, slVtxBytes=0, slSecBytes=0;
  464. SLONG slCgrBytes=0;
  465. CWorld *pwo = (CWorld*)_pShell->GetINDEX("pwoCurrentWorld");
  466. if( pwo!=NULL)
  467. {
  468. // report count of and memory used by entities
  469. FOREACHINDYNAMICCONTAINER( pwo->wo_cenEntities, CEntity, iten) {
  470. ctEntities++;
  471. slEntBytes += iten->GetUsedMemory();
  472. }
  473. // report shadow layers and world geometry memory usage
  474. FOREACHINDYNAMICARRAY( pwo->wo_baBrushes.ba_abrBrushes, CBrush3D, itbr) // for all brush entities in the world
  475. {
  476. // skip brush without entity
  477. if( itbr->br_penEntity==NULL) continue;
  478. // for each mip
  479. FOREACHINLIST( CBrushMip, bm_lnInBrush, itbr->br_lhBrushMips, itbm)
  480. {
  481. // for each sector in the brush mip
  482. FOREACHINDYNAMICARRAY( itbm->bm_abscSectors, CBrushSector, itbsc)
  483. {
  484. // add sector class memory usage to polygons memory
  485. ctSectors++;
  486. slSecBytes += itbsc->GetUsedMemory();
  487. // add each vertex and working vertex in sector
  488. ctVertices += itbsc->bsc_abvxVertices.Count();
  489. FOREACHINSTATICARRAY( itbsc->bsc_abvxVertices, CBrushVertex, itbvx) slVtxBytes += itbvx->GetUsedMemory();
  490. FOREACHINSTATICARRAY( itbsc->bsc_awvxVertices, CWorkingVertex, itwvx) slVtxBytes += 32; // aligned to 32 bytes!
  491. // add each plane and working plane in sector
  492. ctPlanes += itbsc->bsc_abplPlanes.Count();
  493. FOREACHINSTATICARRAY( itbsc->bsc_abplPlanes, CBrushPlane, itbpl) slPlnBytes += itbpl->GetUsedMemory();
  494. FOREACHINSTATICARRAY( itbsc->bsc_awplPlanes, CWorkingPlane, itwpl) slPlnBytes += sizeof(CWorkingPlane);
  495. // add each edge and working edge in sector
  496. ctEdges += itbsc->bsc_abedEdges.Count();
  497. FOREACHINSTATICARRAY( itbsc->bsc_abedEdges, CBrushEdge, itbed) slEdgBytes += itbed->GetUsedMemory();
  498. FOREACHINSTATICARRAY( itbsc->bsc_awedEdges, CWorkingEdge, itwed) slEdgBytes += sizeof(CWorkingEdge);
  499. // for each polygon in sector
  500. ctPolys += itbsc->bsc_abpoPolygons.Count();
  501. FOREACHINSTATICARRAY( itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo) {
  502. CBrushPolygon &bpo = *itbpo;
  503. slPlyBytes += bpo.GetUsedMemory();
  504. // count in the shadow layers (if any)
  505. if( bpo.bpo_smShadowMap.bsm_lhLayers.IsEmpty()) continue; // skip polygon without shadowmap
  506. ctShadowLayers += bpo.bpo_smShadowMap.GetShadowLayersCount();
  507. slLyrBytes += bpo.bpo_smShadowMap.GetUsedMemory();
  508. }
  509. }
  510. }
  511. } // add in memory used by collision grid
  512. extern SLONG GetCollisionGridMemory( CCollisionGrid *pcg);
  513. slCgrBytes += GetCollisionGridMemory( pwo->wo_pcgCollisionGrid);
  514. }
  515. // stock info
  516. const DOUBLE dToMB = 1.0/1024.0/1024.0;
  517. const FLOAT fTexBytes = dToMB * _pTextureStock->CalculateUsedMemory();
  518. const FLOAT fMdlBytes = dToMB * _pModelStock->CalculateUsedMemory();
  519. const FLOAT fSndBytes = dToMB * _pSoundStock->CalculateUsedMemory();
  520. const FLOAT fMshBytes = dToMB * _pMeshStock->CalculateUsedMemory();
  521. const FLOAT fAstBytes = dToMB * _pAnimSetStock->CalculateUsedMemory();
  522. const FLOAT fShaBytes = dToMB * _pShaderStock->CalculateUsedMemory();
  523. const FLOAT fSkaBytes = dToMB * _pSkeletonStock->CalculateUsedMemory();
  524. CPrintF("\nStock information:\n");
  525. CPrintF(" Textures: %5d (%5.2f MB)\n", _pTextureStock->GetTotalCount(), fTexBytes);
  526. CPrintF(" ShadowMaps: %5d (%5.2f MB)\n", ctCachedShadows, slShdBytes*dToMB);
  527. CPrintF(" Entities: %5d (%5.2f MB)\n", ctEntities, slEntBytes*dToMB);
  528. CPrintF(" Sounds: %5d (%5.2f MB)\n", _pSoundStock->GetTotalCount(), fSndBytes);
  529. CPrintF("\n");
  530. CPrintF(" Sectors: %5d (%5.2f MB)\n", ctSectors, slSecBytes*dToMB);
  531. CPrintF(" Planes: %5d (%5.2f MB)\n", ctPlanes, slPlnBytes*dToMB);
  532. CPrintF(" Edges: %5d (%5.2f MB)\n", ctEdges, slEdgBytes*dToMB);
  533. CPrintF(" Polygons: %5d (%5.2f MB)\n", ctPolys, slPlyBytes*dToMB);
  534. CPrintF(" Vertices: %5d (%5.2f MB)\n", ctVertices, slVtxBytes*dToMB);
  535. CPrintF(" ShadowLayers: %5d (%5.2f MB)\n", ctShadowLayers, slLyrBytes*dToMB);
  536. CPrintF("\n");
  537. CPrintF(" Models: %5d (%5.2f MB)\n", _pModelStock->GetTotalCount(), fMdlBytes);
  538. CPrintF(" Meshes: %5d (%5.2f MB)\n", _pMeshStock->GetTotalCount(), fMshBytes);
  539. CPrintF(" Skeletons: %5d (%5.2f MB)\n", _pSkeletonStock->GetTotalCount(), fSkaBytes);
  540. CPrintF(" AnimSets: %5d (%5.2f MB)\n", _pAnimSetStock->GetTotalCount(), fAstBytes);
  541. CPrintF(" Shaders: %5d (%5.2f MB)\n", _pShaderStock->GetTotalCount(), fShaBytes);
  542. CPrintF("\n");
  543. CPrintF("CollisionGrid: %.2f MB\n", slCgrBytes*dToMB);
  544. CPrintF("--------------\n");
  545. CPrintF(" Total: %.2f MB\n", fTexBytes+fSndBytes+fMdlBytes+fMshBytes+fSkaBytes+fAstBytes+fShaBytes
  546. + (slShdBytes+slEntBytes+slSecBytes+slPlnBytes+slEdgBytes+slPlyBytes+slVtxBytes+slLyrBytes+slCgrBytes)*dToMB);
  547. CPrintF("\n");
  548. }
  549. static void StockDump(void)
  550. {
  551. try {
  552. CTFileStream strm;
  553. CTFileName fnm = CTString("Temp\\StockDump.txt");
  554. strm.Create_t(fnm);
  555. strm.PutLine_t("Animations:");
  556. _pAnimStock->DumpMemoryUsage_t(strm);
  557. strm.PutLine_t("Textures:");
  558. _pTextureStock->DumpMemoryUsage_t(strm);
  559. strm.PutLine_t("Models:");
  560. _pModelStock->DumpMemoryUsage_t(strm);
  561. strm.PutLine_t("Sounds:");
  562. _pSoundStock->DumpMemoryUsage_t(strm);
  563. strm.PutLine_t("Classes:");
  564. _pEntityClassStock->DumpMemoryUsage_t(strm);
  565. CPrintF("Dumped to '%s'\n", CTString(fnm));
  566. } catch (char *strError) {
  567. CPrintF("Error: %s\n", strError);
  568. }
  569. }
  570. // free all unused stocks
  571. extern void FreeUnusedStock(void)
  572. {
  573. // free all unused stocks
  574. _pEntityClassStock->FreeUnused();
  575. _pModelStock->FreeUnused();
  576. _pSoundStock->FreeUnused();
  577. _pTextureStock->FreeUnused();
  578. _pAnimStock->FreeUnused();
  579. }
  580. /*
  581. * This is called every TickQuantum seconds.
  582. */
  583. void CNetworkTimerHandler::HandleTimer(void)
  584. {
  585. if (this==NULL || _bTempNetwork) {
  586. return; // this can happen during NET_MakeDefaultState_t()!
  587. }
  588. // enable stream handling during timer
  589. CTSTREAM_BEGIN {
  590. // do the timer loop
  591. _pNetwork->TimerLoop();
  592. } CTSTREAM_END;
  593. }
  594. /*
  595. * Default constructor.
  596. */
  597. CNetworkLibrary::CNetworkLibrary(void) :
  598. ga_IsServer(FALSE), // is not server
  599. ga_bDemoRec(FALSE), // not recording demo
  600. ga_bDemoPlay(FALSE), // not playing demo
  601. ga_bDemoPlayFinished(FALSE), // demo not finished
  602. ga_srvServer(*new CServer),
  603. ga_sesSessionState(*new CSessionState)
  604. {
  605. ga_aplsPlayers.New(NET_MAXLOCALPLAYERS);
  606. // default demo syncronization is real-time, with 1:1 playback speed
  607. ga_fDemoSyncRate = DEMOSYNC_REALTIME;
  608. ga_fDemoRealTimeFactor = 1.0f;
  609. ga_fGameRealTimeFactor = 1.0f;
  610. ga_pubDefaultState = NULL;
  611. ga_slDefaultStateSize = 0;
  612. memset(ga_aubDefaultProperties, 0, sizeof(ga_aubDefaultProperties));
  613. ga_pubCRCList = NULL;
  614. ga_slCRCList = 0;
  615. ga_ulDemoMinorVersion = _SE_BUILD_MINOR;
  616. ga_csNetwork.cs_iIndex = 2000;
  617. ga_ctTimersPending = -1;
  618. ga_fEnumerationProgress = 0;
  619. ga_bEnumerationChange = FALSE;
  620. }
  621. /*
  622. * Destructor.
  623. */
  624. CNetworkLibrary::~CNetworkLibrary(void)
  625. {
  626. // clear the global world
  627. ga_World.DeletePredictors();
  628. ga_World.Clear();
  629. // free renderer info to free pointers to entities etc.
  630. if (!_bTempNetwork) {
  631. extern void ClearRenderer(void);
  632. ClearRenderer();
  633. }
  634. delete &ga_sesSessionState;
  635. delete &ga_srvServer;
  636. }
  637. /*
  638. * Initialize game management.
  639. */
  640. void CNetworkLibrary::Init(const CTString &strGameID)
  641. {
  642. // remember the game ID
  643. CMessageDispatcher::Init(strGameID);
  644. // add shell symbols
  645. _pShell->DeclareSymbol("user INDEX dbg_bBreak;", &dbg_bBreak);
  646. _pShell->DeclareSymbol("persistent user INDEX gam_bPretouch;", &gam_bPretouch);
  647. _pShell->DeclareSymbol("user INDEX dem_iRecordedNumber;", &dem_iRecordedNumber);
  648. _pShell->DeclareSymbol("user void StartDemoRecording(void);", &StartDemoRecording);
  649. _pShell->DeclareSymbol("user void StopDemoRecording(void);", &StopDemoRecording);
  650. _pShell->DeclareSymbol("user void NetworkInfo(void);", &NetworkInfo);
  651. _pShell->DeclareSymbol("user void StockInfo(void);", &StockInfo);
  652. _pShell->DeclareSymbol("user void StockDump(void);", &StockDump);
  653. _pShell->DeclareSymbol("user void RendererInfo(void);", &RendererInfo);
  654. _pShell->DeclareSymbol("user void ClearRenderer(void);", &ClearRenderer);
  655. _pShell->DeclareSymbol("user void CacheShadows(void);", &CacheShadows);
  656. _pShell->DeclareSymbol("user void KickClient(INDEX, CTString);", &KickClientCfunc);
  657. _pShell->DeclareSymbol("user void KickByName(CTString, CTString);", &KickByNameCfunc);
  658. _pShell->DeclareSymbol("user void ListPlayers(void);", &ListPlayers);
  659. _pShell->DeclareSymbol("user void Admin(CTString);", &Admin);
  660. _pShell->DeclareSymbol("user void AddIPMask(CTString);", &AddIPMask);
  661. _pShell->DeclareSymbol("user void RemIPMask(CTString);", &RemIPMask);
  662. _pShell->DeclareSymbol("user void AddNameMask(CTString);", &AddNameMask);
  663. _pShell->DeclareSymbol("user void RemNameMask(CTString);", &RemNameMask);
  664. _pShell->DeclareSymbol("user FLOAT dem_tmTimer;", &ga_fDemoTimer);
  665. _pShell->DeclareSymbol("user FLOAT dem_fSyncRate;", &ga_fDemoSyncRate);
  666. _pShell->DeclareSymbol("user FLOAT dem_fRealTimeFactor;", &ga_fDemoRealTimeFactor);
  667. _pShell->DeclareSymbol("user FLOAT gam_fRealTimeFactor;", &ga_fGameRealTimeFactor);
  668. _pShell->DeclareSymbol("user const FLOAT net_tmLatency;", &net_tmLatency);
  669. _pShell->DeclareSymbol("user const FLOAT cmd_tmTick;", &cmd_tmTick);
  670. _pShell->DeclareSymbol("persistent user CTString cmd_cmdOnTick;", &cmd_cmdOnTick);
  671. _pShell->DeclareSymbol("user CTString cmd_strChatSender ;", &cmd_strChatSender );
  672. _pShell->DeclareSymbol("user CTString cmd_strChatMessage;", &cmd_strChatMessage);
  673. _pShell->DeclareSymbol("persistent user CTString cmd_cmdOnChat;", &cmd_cmdOnChat);
  674. _pShell->DeclareSymbol("user INDEX net_ctChatMessages;", &net_ctChatMessages);
  675. _pShell->DeclareSymbol("persistent user INDEX ent_bReportSpawnInWall;", &ent_bReportSpawnInWall);
  676. _pShell->DeclareSymbol("user INDEX ser_bReportSyncOK;", &ser_bReportSyncOK);
  677. _pShell->DeclareSymbol("user INDEX ser_bReportSyncBad;", &ser_bReportSyncBad);
  678. _pShell->DeclareSymbol("user INDEX ser_bReportSyncLate;", &ser_bReportSyncLate);
  679. _pShell->DeclareSymbol("user INDEX ser_bReportSyncEarly;", &ser_bReportSyncEarly);
  680. _pShell->DeclareSymbol("user INDEX ser_bPauseOnSyncBad;", &ser_bPauseOnSyncBad);
  681. _pShell->DeclareSymbol("user INDEX ser_iKickOnSyncBad;", &ser_iKickOnSyncBad);
  682. _pShell->DeclareSymbol("user INDEX ser_bKickOnSyncLate;", &ser_bKickOnSyncLate);
  683. _pShell->DeclareSymbol("persistent user FLOAT ser_tmSyncCheckFrequency;", &ser_tmSyncCheckFrequency);
  684. _pShell->DeclareSymbol("persistent user INDEX ser_iSyncCheckBuffer;", &ser_iSyncCheckBuffer);
  685. _pShell->DeclareSymbol("persistent user INDEX cli_bLerpActions;", &cli_bLerpActions);
  686. _pShell->DeclareSymbol("persistent user INDEX cli_bReportPredicted;", &cli_bReportPredicted);
  687. _pShell->DeclareSymbol("persistent user INDEX net_iExactTimer;", &net_iExactTimer);
  688. _pShell->DeclareSymbol("user INDEX net_bDumpStreamBlocks;", &net_bDumpStreamBlocks);
  689. _pShell->DeclareSymbol("user INDEX net_bDumpConnectionInfo;", &net_bDumpConnectionInfo);
  690. _pShell->DeclareSymbol("user INDEX net_iPort;", &net_iPort);
  691. _pShell->DeclareSymbol("persistent user CTString net_strLocalHost;", &net_strLocalHost);
  692. _pShell->DeclareSymbol("persistent user CTString net_strLocationCode;", &net_strLocationCode);
  693. _pShell->DeclareSymbol("user CTString net_strVIPPassword;", &net_strVIPPassword);
  694. _pShell->DeclareSymbol("user CTString net_strObserverPassword;", &net_strObserverPassword);
  695. _pShell->DeclareSymbol("user INDEX net_iVIPReserve;", &net_iVIPReserve);
  696. _pShell->DeclareSymbol("user INDEX net_iMaxObservers;", &net_iMaxObservers);
  697. _pShell->DeclareSymbol("user INDEX net_iMaxClients;", &net_iMaxClients);
  698. _pShell->DeclareSymbol("user CTString net_strConnectPassword;", &net_strConnectPassword);
  699. _pShell->DeclareSymbol("user CTString net_strAdminPassword;", &net_strAdminPassword);
  700. _pShell->DeclareSymbol("user FLOAT net_tmConnectionTimeout;", &net_tmConnectionTimeout);
  701. _pShell->DeclareSymbol("user FLOAT net_tmProblemsTimeout;", &net_tmProblemsTimeout);
  702. _pShell->DeclareSymbol("user FLOAT net_tmDisconnectTimeout;", &net_tmDisconnectTimeout);
  703. _pShell->DeclareSymbol("user INDEX net_bReportCRC;", &net_bReportCRC);
  704. _pShell->DeclareSymbol("user INDEX ser_iRememberBehind;", &ser_iRememberBehind);
  705. _pShell->DeclareSymbol("user INDEX cli_bEmulateDesync;", &cli_bEmulateDesync);
  706. _pShell->DeclareSymbol("user INDEX cli_bDumpSync;", &cli_bDumpSync);
  707. _pShell->DeclareSymbol("user INDEX cli_bDumpSyncEachTick;",&cli_bDumpSyncEachTick);
  708. _pShell->DeclareSymbol("persistent user INDEX ser_iExtensiveSyncCheck;", &ser_iExtensiveSyncCheck);
  709. _pShell->DeclareSymbol("persistent user INDEX net_bLookupHostNames;", &net_bLookupHostNames);
  710. _pShell->DeclareSymbol("persistent user INDEX net_iCompression ;", &net_iCompression);
  711. _pShell->DeclareSymbol("persistent user INDEX net_bReportPackets;", &net_bReportPackets);
  712. _pShell->DeclareSymbol("persistent user INDEX net_iMaxSendRetries;", &net_iMaxSendRetries);
  713. _pShell->DeclareSymbol("persistent user FLOAT net_fSendRetryWait;", &net_fSendRetryWait);
  714. _pShell->DeclareSymbol("persistent user INDEX net_bReportTraffic;", &net_bReportTraffic);
  715. _pShell->DeclareSymbol("persistent user INDEX net_bReportICMPErrors;", &net_bReportICMPErrors);
  716. _pShell->DeclareSymbol("persistent user INDEX net_bReportMiscErrors;", &net_bReportMiscErrors);
  717. _pShell->DeclareSymbol("persistent user INDEX net_bLerping;", &net_bLerping);
  718. _pShell->DeclareSymbol("persistent user INDEX ser_bClientsMayPause;", &ser_bClientsMayPause);
  719. _pShell->DeclareSymbol("persistent user INDEX ser_bEnumeration;", &ser_bEnumeration);
  720. _pShell->DeclareSymbol("persistent user INDEX ser_bPingGameAgent;", &ser_bPingGameAgent);
  721. _pShell->DeclareSymbol("persistent user FLOAT ser_tmKeepAlive;", &ser_tmKeepAlive);
  722. _pShell->DeclareSymbol("persistent user FLOAT ser_tmPingUpdate;", &ser_tmPingUpdate);
  723. _pShell->DeclareSymbol("persistent user INDEX ser_bWaitFirstPlayer;", &ser_bWaitFirstPlayer);
  724. _pShell->DeclareSymbol("persistent user INDEX ser_iMaxAllowedBPS;", &ser_iMaxAllowedBPS);
  725. _pShell->DeclareSymbol("persistent user INDEX ser_iMaxAllowedBPS;", &ser_iMaxAllowedBPS);
  726. _pShell->DeclareSymbol("persistent user CTString ser_strIPMask;", &ser_strIPMask);
  727. _pShell->DeclareSymbol("persistent user CTString ser_strNameMask;", &ser_strNameMask);
  728. _pShell->DeclareSymbol("persistent user INDEX ser_bInverseBanning;", &ser_bInverseBanning);
  729. _pShell->DeclareSymbol("persistent user CTString ser_strMOTD;", &ser_strMOTD);
  730. _pShell->DeclareSymbol("persistent user INDEX cli_bAutoAdjustSettings;", &cli_bAutoAdjustSettings);
  731. _pShell->DeclareSymbol("persistent user FLOAT cli_tmAutoAdjustThreshold;", &cli_tmAutoAdjustThreshold);
  732. _pShell->DeclareSymbol("persistent user INDEX cli_bPrediction;", &cli_bPrediction);
  733. _pShell->DeclareSymbol("persistent user INDEX cli_iMaxPredictionSteps;", &cli_iMaxPredictionSteps);
  734. _pShell->DeclareSymbol("persistent user INDEX cli_bPredictIfServer;", &cli_bPredictIfServer);
  735. _pShell->DeclareSymbol("persistent user INDEX cli_bPredictLocalPlayers;", &cli_bPredictLocalPlayers);
  736. _pShell->DeclareSymbol("persistent user INDEX cli_bPredictRemotePlayers;", &cli_bPredictRemotePlayers);
  737. _pShell->DeclareSymbol("persistent user FLOAT cli_fPredictEntitiesRange;", &cli_fPredictEntitiesRange);
  738. _pShell->DeclareSymbol("persistent user FLOAT cli_fPredictionFilter;", &cli_fPredictionFilter);
  739. _pShell->DeclareSymbol("persistent user INDEX cli_iSendBehind;", &cli_iSendBehind);
  740. _pShell->DeclareSymbol("persistent user INDEX cli_iPredictionFlushing;", &cli_iPredictionFlushing);
  741. _pShell->DeclareSymbol("persistent user INDEX cli_iBufferActions;", &cli_iBufferActions);
  742. _pShell->DeclareSymbol("persistent user INDEX cli_iMaxBPS;", &cli_iMaxBPS);
  743. _pShell->DeclareSymbol("persistent user INDEX cli_iMinBPS;", &cli_iMinBPS);
  744. _pShell->DeclareSymbol("user FLOAT net_fLimitLatencySend;", &_pbsSend.pbs_fLatencyLimit);
  745. _pShell->DeclareSymbol("user FLOAT net_fLimitLatencyRecv;", &_pbsRecv.pbs_fLatencyLimit);
  746. _pShell->DeclareSymbol("user FLOAT net_fLatencyVariationSend;", &_pbsSend.pbs_fLatencyVariation);
  747. _pShell->DeclareSymbol("user FLOAT net_fLatencyVariationRecv;", &_pbsRecv.pbs_fLatencyVariation);
  748. _pShell->DeclareSymbol("user FLOAT net_fLimitBandwidthSend;", &_pbsSend.pbs_fBandwidthLimit);
  749. _pShell->DeclareSymbol("user FLOAT net_fLimitBandwidthRecv;", &_pbsRecv.pbs_fBandwidthLimit);
  750. _pShell->DeclareSymbol("user FLOAT net_fDropPackets;", &net_fDropPackets);
  751. _pShell->DeclareSymbol("persistent user INDEX net_iGraphBuffer;", &net_iGraphBuffer);
  752. _pShell->DeclareSymbol("user const INDEX precache_NONE;", &_precache_NONE);
  753. _pShell->DeclareSymbol("user const INDEX precache_SMART;", &_precache_SMART);
  754. _pShell->DeclareSymbol("user const INDEX precache_ALL;", &_precache_ALL);
  755. _pShell->DeclareSymbol("user const INDEX precache_PARANOIA;", &_precache_PARANOIA);
  756. _pShell->DeclareSymbol("persistent user INDEX gam_iPrecachePolicy;", &gam_iPrecachePolicy);
  757. _pShell->DeclareSymbol("user FLOAT phy_fCollisionCacheAhead;", &phy_fCollisionCacheAhead);
  758. _pShell->DeclareSymbol("user FLOAT phy_fCollisionCacheAround;", &phy_fCollisionCacheAround);
  759. _pShell->DeclareSymbol("persistent user INDEX inp_iKeyboardReadingMethod;", &inp_iKeyboardReadingMethod);
  760. _pShell->DeclareSymbol("persistent user INDEX inp_bAllowMouseAcceleration;", &inp_bAllowMouseAcceleration);
  761. _pShell->DeclareSymbol("persistent user FLOAT inp_fMouseSensitivity;", &inp_fMouseSensitivity);
  762. _pShell->DeclareSymbol("persistent user INDEX inp_bMousePrecision;", &inp_bMousePrecision);
  763. _pShell->DeclareSymbol("persistent user FLOAT inp_fMousePrecisionFactor;", &inp_fMousePrecisionFactor);
  764. _pShell->DeclareSymbol("persistent user FLOAT inp_fMousePrecisionThreshold;", &inp_fMousePrecisionThreshold);
  765. _pShell->DeclareSymbol("persistent user FLOAT inp_fMousePrecisionTimeout;", &inp_fMousePrecisionTimeout);
  766. _pShell->DeclareSymbol("persistent user INDEX inp_bInvertMouse;", &inp_bInvertMouse);
  767. _pShell->DeclareSymbol("persistent user INDEX inp_bFilterMouse;", &inp_bFilterMouse);
  768. _pShell->DeclareSymbol("persistent user INDEX inp_bAllowPrescan;", &inp_bAllowPrescan);
  769. _pShell->DeclareSymbol("persistent user INDEX inp_i2ndMousePort;", &inp_i2ndMousePort);
  770. _pShell->DeclareSymbol("persistent user INDEX inp_bInvert2ndMouse;", &inp_bInvert2ndMouse);
  771. _pShell->DeclareSymbol("persistent user INDEX inp_bFilter2ndMouse;", &inp_bFilter2ndMouse);
  772. _pShell->DeclareSymbol("persistent user FLOAT inp_f2ndMouseSensitivity;", &inp_f2ndMouseSensitivity);
  773. _pShell->DeclareSymbol("persistent user INDEX inp_b2ndMousePrecision;", &inp_b2ndMousePrecision);
  774. _pShell->DeclareSymbol("persistent user FLOAT inp_f2ndMousePrecisionFactor;", &inp_f2ndMousePrecisionFactor);
  775. _pShell->DeclareSymbol("persistent user FLOAT inp_f2ndMousePrecisionThreshold;", &inp_f2ndMousePrecisionThreshold);
  776. _pShell->DeclareSymbol("persistent user FLOAT inp_f2ndMousePrecisionTimeout;", &inp_f2ndMousePrecisionTimeout);
  777. _pShell->DeclareSymbol("persistent user INDEX inp_bMsgDebugger;", &inp_bMsgDebugger);
  778. _pShell->DeclareSymbol("persistent user INDEX inp_iMButton4Up;", &inp_iMButton4Up);
  779. _pShell->DeclareSymbol("persistent user INDEX inp_iMButton4Dn;", &inp_iMButton4Dn);
  780. _pShell->DeclareSymbol("persistent user INDEX inp_iMButton5Up;", &inp_iMButton5Up);
  781. _pShell->DeclareSymbol("persistent user INDEX inp_iMButton5Dn;", &inp_iMButton5Dn);
  782. _pShell->DeclareSymbol("persistent user INDEX inp_ctJoysticksAllowed;", &inp_ctJoysticksAllowed);
  783. _pShell->DeclareSymbol("persistent user INDEX inp_bForceJoystickPolling;", &inp_bForceJoystickPolling);
  784. _pShell->DeclareSymbol("persistent user INDEX inp_bAutoDisableJoysticks;", &inp_bAutoDisableJoysticks);
  785. _pShell->DeclareSymbol("persistent user INDEX wed_bUseGenericTextureReplacement;", &wed_bUseGenericTextureReplacement);
  786. _pShell->DeclareSymbol("persistent user CTString ga_strServer;", &ga_strServer);
  787. _pShell->DeclareSymbol("persistent user CTString ga_strMSLegacy;", &ga_strMSLegacy);
  788. _pShell->DeclareSymbol("persistent user INDEX ga_bMSLegacy;", &ga_bMSLegacy);
  789. _pShell->DeclareSymbol("INDEX pwoCurrentWorld;", &_pwoCurrentWorld);
  790. }
  791. /*
  792. * Add the timer handler.
  793. */
  794. void CNetworkLibrary::AddTimerHandler(void)
  795. {
  796. if (this==NULL || _bTempNetwork) {
  797. return; // this can happen during NET_MakeDefaultState_t()!
  798. }
  799. _pTimer->AddHandler(&ga_thTimerHandler);
  800. }
  801. /*
  802. * Remove the timer handler.
  803. */
  804. void CNetworkLibrary::RemoveTimerHandler(void)
  805. {
  806. if (this==NULL || _bTempNetwork) {
  807. return; // this can happen during NET_MakeDefaultState_t()!
  808. }
  809. _pTimer->RemHandler(&ga_thTimerHandler);
  810. }
  811. /*
  812. // set settings to prediction-off
  813. void AdjustPredictionOff(void)
  814. {
  815. if (!cli_bAutoAdjustSettings) {
  816. return;
  817. }
  818. if (cli_bPrediction) {
  819. CPrintF("AutoAdjustment: prediction off, buffer 1\n");
  820. }
  821. cli_bPrediction = 0;
  822. cli_iBufferActions = 1;
  823. }
  824. // set settings to prediction-on
  825. void AdjustPredictionOn(void)
  826. {
  827. if (!cli_bAutoAdjustSettings) {
  828. return;
  829. }
  830. if (!cli_bPrediction) {
  831. CPrintF("AutoAdjustment: prediction on, buffer 3\n");
  832. }
  833. cli_bPrediction = 1;
  834. cli_iBufferActions = 3;
  835. }
  836. // automatically adjust network settings
  837. void CNetworkLibrary::AutoAdjustSettings(void)
  838. {
  839. // if server and not debugging prediction
  840. if (IsServer() && !cli_bPredictIfServer) {
  841. // just turn it all off
  842. AdjustPredictionOff();
  843. return;
  844. }
  845. static TIME _tmLastTimeNoPredictionSteps = -1;
  846. // get network lag in terms of ticks
  847. INDEX ctLagTicks = ga_sesSessionState.GetPredictionStepsCount()-(cli_iBufferActions-1);
  848. // if no significant lag
  849. if (ctLagTicks<=1) {
  850. // set settings to prediction-off
  851. AdjustPredictionOff();
  852. _tmLastTimeNoPredictionSteps = _pTimer->CurrentTick();
  853. // if there is lag now for some time
  854. } else if (_pTimer->CurrentTick()-_tmLastTimeNoPredictionSteps>=cli_tmAutoAdjustThreshold) {
  855. // set settings to prediction-on
  856. AdjustPredictionOn();
  857. }
  858. }
  859. */
  860. /*
  861. * Start a peer-to-peer game session.
  862. *
  863. * remember to keep this routine up to date with CNetworkLibrary::Read()
  864. */
  865. void CNetworkLibrary::StartPeerToPeer_t(const CTString &strSessionName,
  866. const CTFileName &fnmWorld, ULONG ulSpawnFlags,
  867. INDEX ctMaxPlayers, BOOL bWaitAllPlayers,
  868. void *pvSessionProperties) // throw char *
  869. {
  870. // mute all sounds
  871. _pSound->Mute();
  872. // go on
  873. CPrintF( TRANS("Starting session: '%s'\n"), strSessionName);
  874. CPrintF( TRANS(" level: '%s'\n"), (const char*) fnmWorld);
  875. CPrintF( TRANS(" spawnflags: %08x\n"), ulSpawnFlags);
  876. CPrintF( TRANS(" max players: %d\n"), ctMaxPlayers);
  877. CPrintF( TRANS(" waiting: %d\n"), bWaitAllPlayers);
  878. CGatherCRC gc;
  879. // if starting in network
  880. if (_cmiComm.IsNetworkEnabled()) {
  881. CPrintF( TRANS(" network is on\n"));
  882. // start gathering CRCs
  883. InitCRCGather();
  884. // make default state data for creating deltas
  885. MakeDefaultState(fnmWorld, ulSpawnFlags, pvSessionProperties);
  886. } else {
  887. CPrintF( TRANS(" network is off\n"));
  888. }
  889. // access to the list of handlers must be locked
  890. CTSingleLock slHooks(&_pTimer->tm_csHooks, TRUE);
  891. // synchronize access to network
  892. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  893. ga_ctTimersPending = -1; // disable timer pending
  894. ga_strSessionName = strSessionName;
  895. ga_bLocalPause = FALSE;
  896. ga_sesSessionState.ses_iLevel+=1;
  897. ga_sesSessionState.ses_ulSpawnFlags = ulSpawnFlags;
  898. ga_sesSessionState.ses_tmSyncCheckFrequency = ser_tmSyncCheckFrequency;
  899. ga_sesSessionState.ses_iExtensiveSyncCheck = ser_iExtensiveSyncCheck;
  900. memcpy(ga_aubProperties, pvSessionProperties, NET_MAXSESSIONPROPERTIES);
  901. // remember the world filename
  902. ga_fnmWorld = fnmWorld;
  903. ga_fnmNextLevel = CTString("");
  904. try {
  905. // load the world
  906. _pTimer->SetCurrentTick(0.0f); // must have timer at 0 while loading
  907. ga_World.Load_t(fnmWorld);
  908. // delete all entities that don't fit given spawn flags
  909. ga_World.FilterEntitiesBySpawnFlags(ga_sesSessionState.ses_ulSpawnFlags);
  910. } catch(char *) {
  911. ga_fnmWorld = CTString("");
  912. _cmiComm.Server_Close();
  913. _cmiComm.Client_Close();
  914. throw;
  915. }
  916. // remember the world pointer
  917. _pShell->SetINDEX("pwoCurrentWorld", (INDEX)&ga_World);
  918. SetProgressDescription(TRANS("starting server"));
  919. CallProgressHook_t(0.0f);
  920. // initialize server
  921. try {
  922. ga_srvServer.Start_t();
  923. } catch (char *) {
  924. ga_World.DeletePredictors();
  925. ga_World.Clear();
  926. throw;
  927. }
  928. ga_IsServer = TRUE;
  929. ga_ulDemoMinorVersion = _SE_BUILD_MINOR;
  930. CallProgressHook_t(1.0f);
  931. // start the timer loop
  932. AddTimerHandler();
  933. SetProgressDescription(TRANS("starting session"));
  934. CallProgressHook_t(0.0f);
  935. // initialize session state
  936. try {
  937. ga_sesSessionState.Start_t(-1);
  938. } catch (char *strError) {
  939. (void)strError;
  940. RemoveTimerHandler();
  941. ga_srvServer.Stop();
  942. ga_World.DeletePredictors();
  943. ga_World.Clear();
  944. throw;
  945. }
  946. CallProgressHook_t(1.0f);
  947. // remember maximum number of players
  948. ga_sesSessionState.ses_ctMaxPlayers = ctMaxPlayers;
  949. ga_sesSessionState.ses_bWaitAllPlayers = bWaitAllPlayers;
  950. // time speed is normal by default
  951. ga_sesSessionState.ses_fRealTimeFactor = 1.0f;
  952. // eventually cache all shadowmaps in world (memory eater!)
  953. if( shd_bCacheAll) ga_World.wo_baBrushes.CacheAllShadowmaps();
  954. // flush stale caches
  955. FreeUnusedStock();
  956. // mark that pretouching is required
  957. _bNeedPretouch = TRUE;
  958. // start timer sync anew
  959. ga_ctTimersPending = 0;
  960. FinishCRCGather();
  961. CPrintF( TRANS(" started.\n"));
  962. }
  963. /*
  964. * Save the game.
  965. */
  966. void CNetworkLibrary::Save_t(const CTFileName &fnmGame) // throw char *
  967. {
  968. // synchronize access to network
  969. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  970. // must be server
  971. if (!ga_IsServer) {
  972. throw TRANS("Cannot save game - not a server!\n");
  973. }
  974. // create the file
  975. CTFileStream strmFile;
  976. strmFile.Create_t(fnmGame);
  977. // write game to stream
  978. strmFile.WriteID_t("GAME");
  979. ga_sesSessionState.Write_t(&strmFile);
  980. strmFile.WriteID_t("GEND"); // game end
  981. }
  982. /*
  983. * Load the game.
  984. *
  985. * remember to keep this routine up to date with CNetworkLibrary::StartPeerToPeer()
  986. */
  987. void CNetworkLibrary::Load_t(const CTFileName &fnmGame) // throw char *
  988. {
  989. // mute all sounds
  990. _pSound->Mute();
  991. // access to the list of handlers must be locked
  992. CTSingleLock slHooks(&_pTimer->tm_csHooks, TRUE);
  993. // synchronize access to network
  994. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  995. ga_ctTimersPending = -1; // disable timer pending
  996. CGatherCRC gc;
  997. ga_bLocalPause = FALSE;
  998. // open the file
  999. CTFileStream strmFile;
  1000. strmFile.Open_t(fnmGame);
  1001. // if starting in network
  1002. if (_cmiComm.IsNetworkEnabled()) {
  1003. // start gathering CRCs
  1004. InitCRCGather();
  1005. }
  1006. // initialize server
  1007. ga_srvServer.Start_t();
  1008. ga_IsServer = TRUE;
  1009. ga_ulDemoMinorVersion = _SE_BUILD_MINOR;
  1010. ga_fnmNextLevel = CTString("");
  1011. memset(ga_aubProperties, 0, NET_MAXSESSIONPROPERTIES);
  1012. // start the timer loop
  1013. AddTimerHandler();
  1014. strmFile.ExpectID_t("GAME");
  1015. // read session state
  1016. try {
  1017. ga_sesSessionState.Start_t(-1);
  1018. ga_sesSessionState.Read_t(&strmFile);
  1019. // if starting in network
  1020. if (_cmiComm.IsNetworkEnabled()) {
  1021. // make default state data for creating deltas
  1022. MakeDefaultState(ga_fnmWorld, ga_sesSessionState.ses_ulSpawnFlags,
  1023. ga_aubProperties);
  1024. }
  1025. // players will be connected later
  1026. ga_sesSessionState.ses_apltPlayers.Clear();
  1027. ga_sesSessionState.ses_apltPlayers.New(NET_MAXGAMEPLAYERS);
  1028. strmFile.ExpectID_t("GEND"); // game end
  1029. } catch(char *) {
  1030. RemoveTimerHandler();
  1031. ga_srvServer.Stop();
  1032. ga_IsServer = FALSE;
  1033. throw;
  1034. }
  1035. // set time and pause for server from the saved game
  1036. ga_sesSessionState.ses_iLevel+=1;
  1037. ga_srvServer.srv_tmLastProcessedTick = ga_sesSessionState.ses_tmLastProcessedTick;
  1038. ga_srvServer.srv_iLastProcessedSequence = ga_sesSessionState.ses_iLastProcessedSequence;
  1039. ga_srvServer.srv_bPause = ga_sesSessionState.ses_bPause;
  1040. ga_srvServer.srv_bGameFinished = ga_sesSessionState.ses_bGameFinished;
  1041. ga_sesSessionState.ses_tmPredictionHeadTick = ga_sesSessionState.ses_tmLastProcessedTick;
  1042. // start sending stream to local state
  1043. ga_srvServer.srv_assoSessions[0].sso_bSendStream = TRUE;
  1044. ga_srvServer.srv_assoSessions[0].sso_iLastSentSequence = ga_srvServer.srv_iLastProcessedSequence;
  1045. // eventually cache all shadowmaps in world (memory eater!)
  1046. if( shd_bCacheAll) ga_World.wo_baBrushes.CacheAllShadowmaps();
  1047. // flush stale caches
  1048. FreeUnusedStock();
  1049. // mark that pretouching is required
  1050. _bNeedPretouch = TRUE;
  1051. // start timer sync anew
  1052. ga_ctTimersPending = 0;
  1053. FinishCRCGather();
  1054. }
  1055. /*
  1056. * Save a debugging game.
  1057. */
  1058. void CNetworkLibrary::DebugSave(void)
  1059. {
  1060. // try to save game
  1061. try {
  1062. Save_t(CTString("Save\\Debug.sav"));
  1063. // if not successful
  1064. } catch (char *strError){
  1065. FatalError("Cannot save debug game:\n%s", strError);
  1066. }
  1067. }
  1068. /* Enumerate existing sessions. */
  1069. void CNetworkLibrary::EnumSessions(BOOL bInternet)
  1070. {
  1071. // clear old list
  1072. FORDELETELIST(CNetworkSession, ns_lnNode, ga_lhEnumeratedSessions, itns) {
  1073. delete &*itns;
  1074. }
  1075. // make sure network is on
  1076. if (!_cmiComm.IsNetworkEnabled()) {
  1077. _cmiComm.PrepareForUse(/*network*/TRUE, /*client*/FALSE); // have to enumerate as server
  1078. }
  1079. // request enumeration
  1080. GameAgent_EnumTrigger(bInternet);
  1081. }
  1082. /*
  1083. * Join a running multi-player game.
  1084. */
  1085. void CNetworkLibrary::JoinSession_t(const CNetworkSession &nsSesssion, INDEX ctLocalPlayers) // throw char *
  1086. {
  1087. // mute all sounds
  1088. _pSound->Mute();
  1089. // report session addres
  1090. CPrintF( TRANS("Joining session at: '%s'\n"), nsSesssion.ns_strAddress);
  1091. ga_bLocalPause = FALSE;
  1092. // access to the list of handlers must be locked
  1093. CTSingleLock slHooks(&_pTimer->tm_csHooks, TRUE);
  1094. // synchronize access to network
  1095. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  1096. ga_ctTimersPending = -1; // disable timer pending
  1097. // start gathering CRCs
  1098. CGatherCRC gc;
  1099. InitCRCGather();
  1100. // set session name and server address
  1101. ga_strSessionName = nsSesssion.ns_strSession;
  1102. ga_strServerAddress = nsSesssion.ns_strAddress;
  1103. ga_fnmNextLevel = CTString("");
  1104. ga_fnmWorld = CTString("");
  1105. memset(ga_aubProperties, 0, NET_MAXSESSIONPROPERTIES);
  1106. ga_IsServer = FALSE;
  1107. ga_ulDemoMinorVersion = _SE_BUILD_MINOR;
  1108. // start the timer loop
  1109. AddTimerHandler();
  1110. SetProgressDescription(TRANS("connecting"));
  1111. CallProgressHook_t(0.0f);
  1112. // initialize session state
  1113. try {
  1114. ga_sesSessionState.Start_t(ctLocalPlayers);
  1115. } catch(char *) {
  1116. RemoveTimerHandler();
  1117. throw;
  1118. }
  1119. // remember the world pointer
  1120. _pShell->SetINDEX("pwoCurrentWorld", (INDEX)&ga_World);
  1121. // eventually cache all shadowmaps in world (memory eater!)
  1122. if( shd_bCacheAll) ga_World.wo_baBrushes.CacheAllShadowmaps();
  1123. // flush stale caches
  1124. FreeUnusedStock();
  1125. // mark that pretouching is required
  1126. _bNeedPretouch = TRUE;
  1127. // run main loop to let session state process messages from server
  1128. MainLoop();
  1129. // start timer sync anew
  1130. ga_ctTimersPending = 0;
  1131. // initially auto adjust prediction on
  1132. // AdjustPredictionOn();
  1133. CPrintF(" joined\n");
  1134. }
  1135. /* Start playing a demo. */
  1136. void CNetworkLibrary::StartDemoPlay_t(const CTFileName &fnDemo) // throw char *
  1137. {
  1138. // mute all sounds
  1139. _pSound->Mute();
  1140. // access to the list of handlers must be locked
  1141. CTSingleLock slHooks(&_pTimer->tm_csHooks, TRUE);
  1142. // synchronize access to network
  1143. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  1144. ga_ctTimersPending = -1; // disable timer pending
  1145. ga_bLocalPause = FALSE;
  1146. // open the file
  1147. ga_strmDemoPlay.Open_t(fnDemo);
  1148. // remember that playing demo
  1149. ga_bDemoPlay = TRUE;
  1150. ga_bDemoPlayFinished = FALSE;
  1151. // create session name from demo name
  1152. CTString strSessionName = CTString("Demo: ")+fnDemo;
  1153. ga_strSessionName = strSessionName;
  1154. ga_IsServer = FALSE;
  1155. // start the timer loop
  1156. AddTimerHandler();
  1157. // initialize server
  1158. try {
  1159. // read initial info to stream
  1160. ga_strmDemoPlay.ExpectID_t("DEMO");
  1161. if (ga_strmDemoPlay.PeekID_t()==CChunkID("MVER")) {
  1162. ga_strmDemoPlay.ExpectID_t("MVER");
  1163. ga_strmDemoPlay>>ga_ulDemoMinorVersion;
  1164. } else {
  1165. ga_ulDemoMinorVersion = 2;
  1166. }
  1167. ga_sesSessionState.Read_t(&ga_strmDemoPlay);
  1168. } catch(char *) {
  1169. RemoveTimerHandler();
  1170. ga_strmDemoPlay.Close();
  1171. ga_bDemoPlay = FALSE;
  1172. throw;
  1173. }
  1174. // eventually cache all shadowmaps in world (memory eater!)
  1175. if( shd_bCacheAll) ga_World.wo_baBrushes.CacheAllShadowmaps();
  1176. // flush stale caches
  1177. FreeUnusedStock();
  1178. // mark that pretouching is required
  1179. _bNeedPretouch = TRUE;
  1180. // remember the world pointer
  1181. _pShell->SetINDEX("pwoCurrentWorld", (INDEX)&ga_World);
  1182. // demo synchronization starts at the beginning initially
  1183. ga_fDemoTimer = 0.0f;
  1184. ga_tvDemoTimerLastTime = _pTimer->GetHighPrecisionTimer();
  1185. // demo sync seuqence must be initialized first time in ProcessGameStream()
  1186. ga_sesSessionState.ses_tmLastDemoSequence = -1.0f;
  1187. // run main loop to let server process messages from host
  1188. MainLoop();
  1189. // start timer sync anew
  1190. ga_ctTimersPending = 0;
  1191. }
  1192. /* Test if currently playing demo has finished. */
  1193. BOOL CNetworkLibrary::IsDemoPlayFinished(void)
  1194. {
  1195. return ga_bDemoPlay && ga_bDemoPlayFinished;
  1196. }
  1197. /* Test if currently playing a demo. */
  1198. BOOL CNetworkLibrary::IsPlayingDemo(void)
  1199. {
  1200. return ga_bDemoPlay;
  1201. }
  1202. /* Test if currently recording a demo. */
  1203. BOOL CNetworkLibrary::IsRecordingDemo(void)
  1204. {
  1205. return ga_bDemoRec;
  1206. }
  1207. BOOL CNetworkLibrary::IsNetworkEnabled(void)
  1208. {
  1209. return _cmiComm.IsNetworkEnabled();
  1210. }
  1211. // pause/unpause game
  1212. void CNetworkLibrary::TogglePause(void)
  1213. {
  1214. ga_sesSessionState.ses_bWantPause = !ga_sesSessionState.ses_bWantPause;
  1215. }
  1216. // test if game is paused
  1217. BOOL CNetworkLibrary::IsPaused(void)
  1218. {
  1219. if (this==NULL || _bTempNetwork) {
  1220. return TRUE; // this can happen during NET_MakeDefaultState_t()!
  1221. }
  1222. return ga_sesSessionState.ses_bPause;
  1223. }
  1224. // test if having connnection problems (not getting messages from server regulary)
  1225. BOOL CNetworkLibrary::IsConnectionStable(void)
  1226. {
  1227. // if network is not enabled
  1228. if (!_cmiComm.IsNetworkEnabled()) {
  1229. // it is always stable
  1230. return TRUE;
  1231. }
  1232. // check when last message was received.
  1233. return (_pTimer->GetHighPrecisionTimer()-ga_sesSessionState.ses_tvMessageReceived).GetSeconds()<net_tmProblemsTimeout;
  1234. }
  1235. // test if completely disconnected and why
  1236. BOOL CNetworkLibrary::IsDisconnected(void)
  1237. {
  1238. return ga_sesSessionState.ses_strDisconnected!="";
  1239. }
  1240. const CTString &CNetworkLibrary::WhyDisconnected(void)
  1241. {
  1242. return ga_sesSessionState.ses_strDisconnected;
  1243. }
  1244. // set/get server side pause (for single player only)
  1245. void CNetworkLibrary::SetLocalPause(BOOL bPause)
  1246. {
  1247. ga_bLocalPause = bPause;
  1248. }
  1249. BOOL CNetworkLibrary::GetLocalPause(void)
  1250. {
  1251. if (this==NULL || _bTempNetwork) {
  1252. return TRUE; // this can happen during NET_MakeDefaultState_t()!
  1253. }
  1254. return ga_bLocalPause;
  1255. }
  1256. // get server/client name and address
  1257. void CNetworkLibrary::GetHostName(CTString &strName, CTString &strAddress)
  1258. {
  1259. _cmiComm.GetHostName(strName, strAddress);
  1260. }
  1261. // mark that the game has finished -- called from AI
  1262. void CNetworkLibrary::SetGameFinished(void)
  1263. {
  1264. ga_sesSessionState.ses_bGameFinished = TRUE;
  1265. if (IsServer()) {
  1266. ga_srvServer.srv_bGameFinished = TRUE;
  1267. }
  1268. }
  1269. BOOL CNetworkLibrary::IsGameFinished(void)
  1270. {
  1271. return ga_sesSessionState.ses_bGameFinished;
  1272. }
  1273. // manipulation with realtime factor for slower/faster time -- called from AI
  1274. void CNetworkLibrary::SetRealTimeFactor(FLOAT fSpeed)
  1275. {
  1276. ga_sesSessionState.ses_fRealTimeFactor = fSpeed;
  1277. }
  1278. FLOAT CNetworkLibrary::GetRealTimeFactor(void)
  1279. {
  1280. return ga_sesSessionState.ses_fRealTimeFactor;
  1281. }
  1282. // test if game is waiting for more players to connect
  1283. BOOL CNetworkLibrary::IsWaitingForPlayers(void)
  1284. {
  1285. // if game mode does not include waiting for players
  1286. if (!ga_sesSessionState.ses_bWaitAllPlayers) {
  1287. // not waiting
  1288. return FALSE;
  1289. }
  1290. // if server
  1291. if (IsServer()) {
  1292. // check number of players on server
  1293. return ga_srvServer.GetPlayersCount()<ga_sesSessionState.ses_ctMaxPlayers;
  1294. // if not server
  1295. } else {
  1296. // check number of players in session
  1297. return ga_sesSessionState.GetPlayersCount()<ga_sesSessionState.ses_ctMaxPlayers;
  1298. }
  1299. }
  1300. // test if game is waiting for server
  1301. BOOL CNetworkLibrary::IsWaitingForServer(void)
  1302. {
  1303. return ga_sesSessionState.ses_bWaitingForServer;
  1304. }
  1305. // test if game session is currently doing prediction
  1306. BOOL CNetworkLibrary::IsPredicting(void)
  1307. {
  1308. return ga_sesSessionState.ses_bPredicting;
  1309. }
  1310. /*
  1311. * Stop currently running game.
  1312. */
  1313. void CNetworkLibrary::StopGame(void)
  1314. {
  1315. // mute all sounds
  1316. _pSound->Mute();
  1317. CPrintF( TRANS("stopping game.\n"));
  1318. // access to the list of handlers must be locked
  1319. CTSingleLock slHooks(&_pTimer->tm_csHooks, TRUE);
  1320. // synchronize access to network
  1321. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  1322. ga_ctTimersPending = -1; // disable timer pending
  1323. // stop demo recording if active
  1324. StopDemoRec();
  1325. // if playing demo
  1326. if (ga_bDemoPlay) {
  1327. // close the demo file
  1328. ga_strmDemoPlay.Close();
  1329. // remember that not playing demo
  1330. ga_bDemoPlay = FALSE;
  1331. ga_bDemoPlayFinished = FALSE;
  1332. }
  1333. // stop the timer loop
  1334. RemoveTimerHandler();
  1335. // stop session
  1336. ga_sesSessionState.Stop();
  1337. // stop server
  1338. if (ga_IsServer) {
  1339. ga_srvServer.Stop();
  1340. ga_IsServer = FALSE;
  1341. }
  1342. ga_ulDemoMinorVersion = _SE_BUILD_MINOR;
  1343. ga_strSessionName = "";
  1344. ga_World.DeletePredictors();
  1345. ga_World.Clear();
  1346. // free default state if existing
  1347. if (ga_pubDefaultState!=NULL) {
  1348. FreeMemory(ga_pubDefaultState);
  1349. ga_pubDefaultState = NULL;
  1350. ga_slDefaultStateSize = 0;
  1351. memset(ga_aubDefaultProperties, 0, sizeof(ga_aubDefaultProperties));
  1352. }
  1353. if (ga_pubCRCList!=NULL) {
  1354. FreeMemory(ga_pubCRCList);
  1355. ga_pubCRCList = NULL;
  1356. ga_slCRCList = 0;
  1357. }
  1358. ga_aplsPlayers.Clear();
  1359. ga_aplsPlayers.New(NET_MAXLOCALPLAYERS);
  1360. // remember the world pointer
  1361. _pShell->SetINDEX("pwoCurrentWorld", (INDEX)NULL);
  1362. // rewind the timer
  1363. _pTimer->SetCurrentTick(0.0f);
  1364. }
  1365. // initiate level change
  1366. void CNetworkLibrary::ChangeLevel(
  1367. const CTFileName &fnmNextLevel, BOOL bRemember, INDEX iUserData)
  1368. {
  1369. // synchronize access to network
  1370. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  1371. ASSERT(!IsPredicting());
  1372. // if not currently changing
  1373. if (_lphCurrent==LCP_NOCHANGE) {
  1374. // initiate change
  1375. ga_fnmNextLevel = fnmNextLevel;
  1376. ga_bNextRemember = bRemember;
  1377. ga_iNextLevelUserData = iUserData;
  1378. _lphCurrent = LCP_INITIATED;
  1379. }
  1380. }
  1381. // really do the level change
  1382. void CNetworkLibrary::ChangeLevel_internal(void)
  1383. {
  1384. CSetFPUPrecision FPUPrecision(FPT_24BIT);
  1385. extern BOOL _bReinitEntitiesWhileCopying;
  1386. _bReinitEntitiesWhileCopying = FALSE;
  1387. // mute all sounds
  1388. _pSound->Mute();
  1389. // cancel all predictions before crossing levels
  1390. _pNetwork->ga_World.DeletePredictors();
  1391. // find all entities that are to cross to next level
  1392. CEntitySelection senToCross;
  1393. {FOREACHINDYNAMICCONTAINER(ga_World.wo_cenEntities, CEntity, iten) {
  1394. if (iten->en_ulFlags&ENF_CROSSESLEVELS) {
  1395. senToCross.Select(*iten);
  1396. }
  1397. }}
  1398. // copy them to a temporary world
  1399. CWorld wldTemp;
  1400. CEntitySelection senInTemp;
  1401. wldTemp.CopyEntities(ga_World, senToCross,
  1402. senInTemp, CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0)));
  1403. // remember characters for all player targets and disable them
  1404. CPlayerCharacter apc[NET_MAXGAMEPLAYERS];
  1405. BOOL abWasActive[NET_MAXGAMEPLAYERS];
  1406. CPlayerAction apaActions[NET_MAXGAMEPLAYERS][2];
  1407. {for(INDEX i=0; i<NET_MAXGAMEPLAYERS; i++) {
  1408. CPlayerTarget &plt = ga_sesSessionState.ses_apltPlayers[i];
  1409. abWasActive[i] = plt.IsActive();
  1410. if (plt.IsActive()) {
  1411. apc[i] = plt.plt_penPlayerEntity->en_pcCharacter;
  1412. apaActions[i][0] = plt.plt_paLastAction;
  1413. apaActions[i][1] = plt.plt_paPreLastAction;
  1414. plt.plt_penPlayerEntity = NULL;
  1415. plt.Deactivate();
  1416. }
  1417. }}
  1418. // destroy all entities that will cross level
  1419. ga_World.DestroyEntities(senToCross);
  1420. // if should remember old levels
  1421. if (ga_bNextRemember) {
  1422. // remember current level
  1423. ga_sesSessionState.RememberCurrentLevel(ga_fnmWorld);
  1424. }
  1425. CGatherCRC gc;
  1426. // if starting in network
  1427. if (_cmiComm.IsNetworkEnabled()) {
  1428. // start gathering CRCs
  1429. InitCRCGather();
  1430. // make default state data for creating deltas
  1431. MakeDefaultState(ga_fnmNextLevel, ga_sesSessionState.ses_ulSpawnFlags, ga_aubProperties);
  1432. }
  1433. // if the new level is not remembered
  1434. if (ga_sesSessionState.FindRememberedLevel(ga_fnmNextLevel)==NULL) {
  1435. // remember original world filename
  1436. CTFileName fnmOldWorld = ga_fnmWorld;
  1437. // try to
  1438. try {
  1439. // load the new world
  1440. _pTimer->SetCurrentTick(0.0f); // must have timer at 0 while loading
  1441. ga_World.Load_t(ga_fnmNextLevel);
  1442. // delete all entities that don't fit given spawn flags
  1443. ga_World.FilterEntitiesBySpawnFlags(ga_sesSessionState.ses_ulSpawnFlags);
  1444. // if failed
  1445. } catch(char *strError) {
  1446. // report error
  1447. CPrintF(TRANS("Cannot change level:\n%s"), strError);
  1448. // try to
  1449. try {
  1450. // load the old world
  1451. ga_fnmNextLevel = fnmOldWorld;
  1452. ga_World.Load_t(ga_fnmNextLevel);
  1453. // delete all entities that don't fit given spawn flags
  1454. ga_World.FilterEntitiesBySpawnFlags(ga_sesSessionState.ses_ulSpawnFlags);
  1455. // if that fails
  1456. } catch (char *strError2) {
  1457. // fatal error
  1458. FatalError(
  1459. TRANS("Cannot change level because:\n%s\n"
  1460. "and cannot go back to original one because:\n%s"), strError, strError2);
  1461. return;
  1462. }
  1463. }
  1464. // remember the world filename
  1465. ga_fnmWorld = ga_fnmNextLevel;
  1466. // remember the world pointer
  1467. _pShell->SetINDEX("pwoCurrentWorld", (INDEX)&ga_World);
  1468. // if there is remembered level
  1469. } else {
  1470. // restore it
  1471. ga_sesSessionState.RestoreOldLevel(ga_fnmNextLevel);
  1472. }
  1473. // set overdue timers in just loaded world to be due in current time
  1474. ga_World.AdjustLateTimers(ga_sesSessionState.ses_tmLastProcessedTick);
  1475. // copy entities from temporary world into new one
  1476. CEntitySelection senCrossed;
  1477. ga_World.CopyEntities(wldTemp, senInTemp,
  1478. senCrossed, CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0)));
  1479. // restore pointers to entities for all active player targets
  1480. {for(INDEX i=0; i<NET_MAXGAMEPLAYERS; i++) {
  1481. CPlayerTarget &plt = ga_sesSessionState.ses_apltPlayers[i];
  1482. if (abWasActive[i]) {
  1483. plt.Activate();
  1484. plt.plt_paLastAction = apaActions[i][0];
  1485. plt.plt_paPreLastAction = apaActions[i][1];
  1486. plt.AttachEntity(ga_World.FindEntityWithCharacter(apc[i]));
  1487. }
  1488. }}
  1489. _bReinitEntitiesWhileCopying = TRUE;
  1490. // if should not remember old levels
  1491. if (!ga_bNextRemember) {
  1492. // clear them all
  1493. ga_sesSessionState.ForgetOldLevels();
  1494. }
  1495. // if not server
  1496. if (!IsServer()) {
  1497. // start waiting for server
  1498. ga_sesSessionState.ses_bWaitingForServer = TRUE;
  1499. // if server
  1500. } else {
  1501. // flush sync check buffer
  1502. ga_srvServer.srv_ascChecks.Clear();
  1503. // for each client
  1504. {for( INDEX iClient=0; iClient<NET_MAXGAMECOMPUTERS; iClient++) {
  1505. CSessionSocket &sso = ga_srvServer.srv_assoSessions[iClient];
  1506. // reset message timer
  1507. sso.sso_tvMessageReceived = -1I64;
  1508. // reset sync timer
  1509. sso.sso_tmLastSyncReceived = -1.0f;
  1510. }}
  1511. // for each player
  1512. {for( INDEX iPlayer=0; iPlayer<NET_MAXGAMEPLAYERS; iPlayer++) {
  1513. CPlayerBuffer &plb = _pNetwork->ga_srvServer.srv_aplbPlayers[iPlayer];
  1514. if (plb.plb_Active) {
  1515. // add one dummy action
  1516. CPlayerAction pa;
  1517. pa.Clear();
  1518. pa.pa_aRotation = plb.plb_paLastAction.pa_aRotation;
  1519. pa.pa_aViewRotation = plb.plb_paLastAction.pa_aViewRotation;
  1520. plb.plb_abReceived.AddAction(pa);
  1521. }
  1522. }}
  1523. }
  1524. ga_sesSessionState.ses_iLevel+=1;
  1525. // flush stale caches
  1526. FreeUnusedStock();
  1527. // mark that pretouching is required
  1528. _bNeedPretouch = TRUE;
  1529. // start timer sync anew
  1530. ga_ctTimersPending = 0;
  1531. FinishCRCGather();
  1532. }
  1533. /* Start recording a demo. */
  1534. void CNetworkLibrary::StartDemoRec_t(const CTFileName &fnDemo) // throw char *
  1535. {
  1536. // synchronize access to network
  1537. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  1538. // if already recording
  1539. if (ga_bDemoRec) {
  1540. // error
  1541. throw TRANS("Already recording a demo!");
  1542. }
  1543. // create the file
  1544. ga_strmDemoRec.Create_t(fnDemo);
  1545. // write initial info to stream
  1546. ga_strmDemoRec.WriteID_t("DEMO");
  1547. ga_strmDemoRec.WriteID_t("MVER");
  1548. ga_strmDemoRec<<ULONG(_SE_BUILD_MINOR);
  1549. ga_sesSessionState.Write_t(&ga_strmDemoRec);
  1550. // remember that recording demo
  1551. ga_bDemoRec = TRUE;
  1552. }
  1553. /* Stop recording a demo. */
  1554. void CNetworkLibrary::StopDemoRec(void)
  1555. {
  1556. // synchronize access to network
  1557. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  1558. // if not recording
  1559. if (!ga_bDemoRec) {
  1560. // do nothing
  1561. return;
  1562. }
  1563. // write terminal info to the stream
  1564. ga_strmDemoRec.WriteID_t("DEND"); // game end
  1565. // close the file
  1566. ga_strmDemoRec.Close();
  1567. // remember that not recording demo
  1568. ga_bDemoRec = FALSE;
  1569. }
  1570. // split the rcon response string into lines and send one by one to the client
  1571. static void SendAdminResponse(ULONG ulAdr, UWORD uwPort, ULONG ulCode, const CTString &strResponse)
  1572. {
  1573. CTString str = strResponse;
  1574. INDEX iLineCt = 0;
  1575. while (str!="") {
  1576. CTString strLine = str;
  1577. strLine.OnlyFirstLine();
  1578. str.RemovePrefix(strLine);
  1579. str.DeleteChar(0);
  1580. if (strLine.Length()>0) {
  1581. CNetworkMessage nm(MSG_EXTRA);
  1582. nm<<CTString(0, "log %u %d %s\n", ulCode, iLineCt++, strLine);
  1583. _pNetwork->SendBroadcast(nm, ulAdr, uwPort);
  1584. }
  1585. }
  1586. }
  1587. /*
  1588. * Main loop.
  1589. */
  1590. void CNetworkLibrary::MainLoop(void)
  1591. {
  1592. // synchronize access to network
  1593. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  1594. // update network state variable (to control usage of some cvars that cannot be altered in mulit-player mode)
  1595. _bMultiPlayer = (_pNetwork->ga_sesSessionState.GetPlayersCount() > 1);
  1596. // if should change world
  1597. if (_lphCurrent==LCP_SIGNALLED) {
  1598. // really do the level change here
  1599. ChangeLevel_internal();
  1600. _lphCurrent=LCP_CHANGED;
  1601. }
  1602. if (_bStartDemoRecordingNextTime) {
  1603. _bStartDemoRecordingNextTime = 0.0f;
  1604. if (!ga_bDemoRec) {
  1605. try {
  1606. CTString strName;
  1607. strName.PrintF("Temp\\Recorded%02d.dem", (INDEX)dem_iRecordedNumber);
  1608. StartDemoRec_t(strName);
  1609. dem_iRecordedNumber+=1;
  1610. } catch(char *strError) {
  1611. CPrintF(TRANS("Demo recording error: %s\n"), strError);
  1612. }
  1613. }
  1614. }
  1615. if (_bStopDemoRecordingNextTime) {
  1616. _bStopDemoRecordingNextTime = 0.0f;
  1617. if (ga_bDemoRec) {
  1618. StopDemoRec();
  1619. }
  1620. }
  1621. _sfStats.StartTimer(CStatForm::STI_MAINLOOP);
  1622. _pfNetworkProfile.StartTimer(CNetworkProfile::PTI_MAINLOOP);
  1623. // handle messages for session state
  1624. if (!ga_bDemoPlay) {
  1625. if (_cmiComm.Client_Update() == FALSE) {
  1626. ga_sesSessionState.Stop();
  1627. return;
  1628. }
  1629. ga_sesSessionState.SessionStateLoop();
  1630. if (_cmiComm.Client_Update() == FALSE) {
  1631. ga_sesSessionState.Stop();
  1632. return;
  1633. }
  1634. }
  1635. // if this is server computer
  1636. if (ga_IsServer) {
  1637. // handle server messages
  1638. _cmiComm.Server_Update();
  1639. }
  1640. // let server process game stream
  1641. TIME tmBefore = _pTimer->GetRealTimeTick();
  1642. _pTimer->SetLerp(0.0f);
  1643. /*
  1644. // automatically adjust network settings
  1645. if (cli_bAutoAdjustSettings) {
  1646. AutoAdjustSettings();
  1647. }
  1648. */
  1649. // determine whether to use prediction
  1650. BOOL bUsePrediction = cli_bPrediction && (cli_bPredictIfServer || !IsServer());
  1651. _bPredictionActive = bUsePrediction; // memeber this for other misc code
  1652. // mark all predictable entities that will be predicted using user-set criterions
  1653. if (bUsePrediction) {
  1654. ga_World.MarkForPrediction();
  1655. }
  1656. // process the game stream coming from the server
  1657. ga_sesSessionState.ProcessGameStream();
  1658. // flush actions that don't need to be predicted any more
  1659. ga_sesSessionState.FlushProcessedPredictions();
  1660. // process additional prediction steps
  1661. if (bUsePrediction) {
  1662. // mark all new predictable entities that might have been spawned
  1663. ga_World.UnmarkForPrediction();
  1664. ga_World.MarkForPrediction();
  1665. ga_sesSessionState.ProcessPrediction();
  1666. // unmark all predictable entities marked for prediction
  1667. ga_World.UnmarkForPrediction();
  1668. }
  1669. ga_sesSessionState.ses_tmLastUpdated = _pTimer->GetRealTimeTick();
  1670. TIME tmAfter = _pTimer->GetRealTimeTick();
  1671. ga_sesSessionState.ses_bKeepingUpWithTime = (tmAfter-tmBefore)<=_pTimer->TickQuantum*2.01f;
  1672. CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
  1673. // set the lerping factor for current frame
  1674. if (!ga_bDemoPlay) {
  1675. ga_sesSessionState.SetLerpFactor(tvNow);
  1676. } else {
  1677. ga_sesSessionState.SetLerpFactor(CTimerValue(ga_fDemoTimer));
  1678. }
  1679. // if playing a demo
  1680. if (ga_bDemoPlay) {
  1681. // if synchronizing by real time
  1682. if (ga_fDemoSyncRate==DEMOSYNC_REALTIME) {
  1683. // if server is keeping up
  1684. if (ga_sesSessionState.ses_bKeepingUpWithTime) {
  1685. // add passed time with slow/fast factor
  1686. ga_fDemoTimer += FLOAT((tvNow-ga_tvDemoTimerLastTime).GetSeconds())
  1687. *ga_fDemoRealTimeFactor*ga_sesSessionState.ses_fRealTimeFactor;
  1688. }
  1689. // if synchronizing is stopped
  1690. } else if (ga_fDemoSyncRate==DEMOSYNC_STOP) {
  1691. // don't step
  1692. NOTHING;
  1693. // if synchronizing by given steps
  1694. } else {
  1695. // just add the step
  1696. ga_fDemoTimer += 1.0f/ga_fDemoSyncRate;
  1697. }
  1698. }
  1699. // remember the demo timer
  1700. ga_tvDemoTimerLastTime = tvNow;
  1701. // if network
  1702. if (_cmiComm.IsNetworkEnabled()) {
  1703. // do services for gameagent querying
  1704. GameAgent_ServerUpdate();
  1705. // _cmiComm.Broadcast_Update();
  1706. // repeat
  1707. FOREVER {
  1708. CNetworkMessage nmReceived;
  1709. // _cmiComm.Broadcast_Update();
  1710. ULONG ulFrom;
  1711. UWORD uwPort;
  1712. BOOL bHasMsg = ReceiveBroadcast(nmReceived, ulFrom, uwPort);
  1713. // if there are no more messages
  1714. if (!bHasMsg) {
  1715. // finish
  1716. break;
  1717. }
  1718. // if this message is not valid rcon message
  1719. if (nmReceived.GetType()!=MSG_EXTRA) {
  1720. // skip it
  1721. continue;
  1722. }
  1723. // get the string from the message
  1724. CTString strMsg;
  1725. nmReceived>>strMsg;
  1726. // if this is server
  1727. if (IsServer()) {
  1728. // accept requests
  1729. if (!strMsg.RemovePrefix("rcmd ")) {
  1730. continue;
  1731. }
  1732. ULONG ulCode;
  1733. char strPass[80];
  1734. char strCmd[256];
  1735. strMsg.ScanF("%u \"%80[^\"]\"%256[^\n]", &ulCode, strPass, strCmd);
  1736. CTString strAdr = AddressToString(ulFrom);
  1737. if (net_strAdminPassword=="" || net_strAdminPassword!=strPass) {
  1738. CPrintF(TRANS("Server: Client '%s', Wrong password for remote administration.\n"), (const char*)strAdr);
  1739. continue;
  1740. }
  1741. CPrintF(TRANS("Server: Client '%s', Admin cmd: %s\n"), (const char*)strAdr, strCmd);
  1742. con_bCapture = TRUE;
  1743. con_strCapture = "";
  1744. _pShell->Execute(CTString(strCmd)+";");
  1745. CTString strResponse = CTString(">")+strCmd+"\n"+con_strCapture;
  1746. SendAdminResponse(ulFrom, uwPort, ulCode, strResponse);
  1747. con_bCapture = FALSE;
  1748. con_strCapture = "";
  1749. }
  1750. }
  1751. }
  1752. _pfNetworkProfile.StopTimer(CNetworkProfile::PTI_MAINLOOP);
  1753. _sfStats.StopTimer(CStatForm::STI_MAINLOOP);
  1754. }
  1755. // make actions packet for local players and send to server
  1756. void CNetworkLibrary::SendActionsToServer(void)
  1757. {
  1758. // make the packet
  1759. CNetworkMessage nmAction(MSG_ACTION);
  1760. // for all local players on this machine
  1761. for(INDEX ipls=0; ipls<ga_aplsPlayers.Count(); ipls++) {
  1762. CPlayerSource &pls = ga_aplsPlayers[ipls];
  1763. // create action packet if the player exists
  1764. pls.WriteActionPacket(nmAction);
  1765. }
  1766. // send the packet
  1767. SendToServer(nmAction);
  1768. }
  1769. /*
  1770. * Client loop.
  1771. */
  1772. void CNetworkLibrary::TimerLoop(void)
  1773. {
  1774. if (this==NULL || _bTempNetwork) {
  1775. return; // this can happen during NET_MakeDefaultState_t()!
  1776. }
  1777. _pfNetworkProfile.StartTimer(CNetworkProfile::PTI_TIMERLOOP);
  1778. // count number of timer interrupts that happened
  1779. if (ga_ctTimersPending>=0) {
  1780. ga_ctTimersPending++;
  1781. }
  1782. // if can synchronize access to network
  1783. CTSingleLock slNetwork(&ga_csNetwork, FALSE);
  1784. // initially, no timer functions needed
  1785. INDEX ct = 0;
  1786. // if timer exactness level is full
  1787. if (net_iExactTimer==2) {
  1788. // lock network mutex
  1789. slNetwork.Lock();
  1790. // execute exactly one
  1791. ct = 1;
  1792. // if timer exactness level is partial
  1793. } else if (net_iExactTimer==1) {
  1794. // if network mutex can be locked
  1795. if (slNetwork.TryToLock()) {
  1796. // execute all pending
  1797. ct = ga_ctTimersPending;
  1798. }
  1799. // if timer exactness level is low
  1800. } else if (net_iExactTimer==0) {
  1801. // if network mutex can be locked
  1802. if (slNetwork.TryToLock()) {
  1803. // execute exactly one
  1804. ct = 1;
  1805. }
  1806. }
  1807. // for each pending interrupt
  1808. while(ct) {
  1809. ct--;
  1810. ga_ctTimersPending--;
  1811. // if not disconnected
  1812. // if (!IsDisconnected()) {
  1813. if (_cmiComm.cci_bClientInitialized) {
  1814. // make actions packet for all local players and send to server
  1815. SendActionsToServer();
  1816. _cmiComm.Client_Update();
  1817. }
  1818. // if this is server computer
  1819. if (ga_IsServer) {
  1820. // handle server messages
  1821. _cmiComm.Server_Update();
  1822. ga_srvServer.ServerLoop();
  1823. _cmiComm.Server_Update();
  1824. }
  1825. }
  1826. _pfNetworkProfile.StopTimer(CNetworkProfile::PTI_TIMERLOOP);
  1827. }
  1828. /* Get player entity for a given local player. */
  1829. CEntity *CNetworkLibrary::GetLocalPlayerEntity(CPlayerSource *ppls)
  1830. {
  1831. // synchronize access to network
  1832. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  1833. // get the index of the player target in game state
  1834. INDEX iPlayerTarget = ppls->pls_Index;
  1835. // if player is not added
  1836. if (iPlayerTarget<0) {
  1837. // no entity
  1838. return NULL;
  1839. // if player is added
  1840. } else {
  1841. // get the entity from player target
  1842. CPlayerTarget &plt = ga_sesSessionState.ses_apltPlayers[iPlayerTarget];
  1843. CPlayerEntity *pen = plt.plt_penPlayerEntity;
  1844. return pen;
  1845. }
  1846. }
  1847. /* Get player entity for a given player by name. */
  1848. CEntity *CNetworkLibrary::GetPlayerEntityByName(const CTString &strName)
  1849. {
  1850. // synchronize access to network
  1851. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  1852. // for each player in game
  1853. CStaticArray<CPlayerTarget> &aplt = ga_sesSessionState.ses_apltPlayers;
  1854. for(INDEX iplt = 0; iplt<aplt.Count(); iplt++) {
  1855. // if it is active and has that name
  1856. if (aplt[iplt].IsActive()
  1857. &&aplt[iplt].plt_penPlayerEntity->en_pcCharacter.GetName()==strName) {
  1858. // return it
  1859. return aplt[iplt].plt_penPlayerEntity;
  1860. }
  1861. }
  1862. // else not found
  1863. return NULL;
  1864. }
  1865. /* Get number of entities with given name. */
  1866. INDEX CNetworkLibrary::GetNumberOfEntitiesWithName(const CTString &strName)
  1867. {
  1868. INDEX ctEntities = 0;
  1869. {FOREACHINDYNAMICCONTAINER(ga_World.wo_cenEntities, CEntity, iten) {
  1870. if (iten->GetName()==strName) {
  1871. ctEntities++;
  1872. }
  1873. }}
  1874. return ctEntities;
  1875. }
  1876. /* Get n-th entity with given name. */
  1877. CEntity *CNetworkLibrary::GetEntityWithName(const CTString &strName, INDEX iEntityWithThatName)
  1878. {
  1879. INDEX ctEntities = 0;
  1880. CEntity *pen = NULL;
  1881. {FOREACHINDYNAMICCONTAINER(ga_World.wo_cenEntities, CEntity, iten) {
  1882. if (iten->GetName()==strName) {
  1883. pen = iten;
  1884. if (ctEntities==iEntityWithThatName) {
  1885. break;
  1886. }
  1887. ctEntities++;
  1888. }
  1889. }}
  1890. return pen;
  1891. }
  1892. /* Test if a given player is local to this computer. */
  1893. BOOL CNetworkLibrary::IsPlayerLocal(CEntity *pen)
  1894. {
  1895. return GetPlayerSource(pen)!=NULL;
  1896. }
  1897. // get player source for a given player if it is local to this computer
  1898. CPlayerSource *CNetworkLibrary::GetPlayerSource(CEntity *pen)
  1899. {
  1900. // synchronize access to network
  1901. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  1902. // for all local player on this machine
  1903. {FOREACHINSTATICARRAY(ga_aplsPlayers, CPlayerSource, itpls) {
  1904. // get the index of the player target in game state
  1905. INDEX iPlayerTarget = itpls->pls_Index;
  1906. // if player is added
  1907. if (iPlayerTarget>=0) {
  1908. // get the player target
  1909. CPlayerTarget &plt = ga_sesSessionState.ses_apltPlayers[iPlayerTarget];
  1910. // if it is that one
  1911. if (plt.plt_penPlayerEntity == pen) {
  1912. // return it
  1913. return itpls;
  1914. }
  1915. }
  1916. }}
  1917. // if not found, it is not local
  1918. return NULL;
  1919. }
  1920. // get game time in currently running game
  1921. TIME CNetworkLibrary::GetGameTime(void)
  1922. {
  1923. return ga_sesSessionState.ses_tmLastProcessedTick;
  1924. }
  1925. /*
  1926. * Add a new client to game.
  1927. */
  1928. CPlayerSource *CNetworkLibrary::AddPlayer_t(CPlayerCharacter &pcCharacter) // throw char *
  1929. {
  1930. // synchronize access to network
  1931. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  1932. CPrintF( TRANS("Adding player: '%s'\n"), pcCharacter.GetNameForPrinting());
  1933. // for all local clients on this machine
  1934. FOREACHINSTATICARRAY(ga_aplsPlayers, CPlayerSource, itcls) {
  1935. // if client is not active
  1936. if (!itcls->IsActive()) {
  1937. // activate it
  1938. itcls->Start_t(pcCharacter);
  1939. CPrintF( TRANS(" done.\n"));
  1940. return &itcls.Current();
  1941. }
  1942. }
  1943. // number of local clients is limited with NET_MAXLOCALCLIENTS
  1944. ASSERTALWAYS("Adding too much local clients!");
  1945. throw TRANS("Cannot add more local clients");
  1946. return NULL;
  1947. }
  1948. /* Get session properties for current game. */
  1949. void *CNetworkLibrary::GetSessionProperties(void)
  1950. {
  1951. // synchronize access to network
  1952. CTSingleLock slNetwork(&ga_csNetwork, TRUE);
  1953. return ga_aubProperties;
  1954. }
  1955. /* Send chat message from some players to some other players. */
  1956. void CNetworkLibrary::SendChat(ULONG ulFrom, ULONG ulTo, const CTString &strMessage)
  1957. {
  1958. // if the string is too long and we're not server
  1959. if (strlen(strMessage)>256 && !_pNetwork->IsServer()) {
  1960. // refuse it
  1961. return;
  1962. }
  1963. // just make the message and send it to server
  1964. CNetworkMessage nm(MSG_CHAT_IN);
  1965. nm<<ulFrom;
  1966. nm<<ulTo;
  1967. nm<<strMessage;
  1968. SendToServer(nm);
  1969. }
  1970. // save current version of engine
  1971. void CNetworkLibrary::WriteVersion_t(CTStream &strm)
  1972. {
  1973. strm.WriteID_t("BUIV"); // build version
  1974. strm<<INDEX(_SE_BUILD_MAJOR);
  1975. }
  1976. // load version of engine saved in file and check against current
  1977. void CNetworkLibrary::CheckVersion_t(CTStream &strm, BOOL bAllowReinit, BOOL &bNeedsReinit)
  1978. {
  1979. // if not saved
  1980. if (strm.PeekID_t()!=CChunkID("BUIV")) { // build version
  1981. // behave as if everything is ok (for old versions)
  1982. bNeedsReinit = FALSE;
  1983. return;
  1984. }
  1985. strm.ExpectID_t("BUIV"); // build version
  1986. // read the saved one
  1987. INDEX iSaved;
  1988. strm>>iSaved;
  1989. // get current one
  1990. INDEX iCurrent = _SE_BUILD_MAJOR;
  1991. // if current version is an internal build
  1992. if (iCurrent==0) {
  1993. // it is never forced to reinit
  1994. bNeedsReinit = FALSE;
  1995. return;
  1996. }
  1997. // if current version is older than the saved one
  1998. if (iCurrent<iSaved) {
  1999. // it cannot be reinitialized
  2000. ThrowF_t(TRANS("File '%s' was saved by a newer version of engine, it cannot be loaded"),
  2001. strm.GetDescription());
  2002. return;
  2003. }
  2004. // if current version is same as the saved one
  2005. if (iCurrent==iSaved) {
  2006. // all ok
  2007. bNeedsReinit = FALSE;
  2008. return;
  2009. }
  2010. // if current version is newer than the saved one
  2011. if (iCurrent>iSaved) {
  2012. // it should be reinitialized
  2013. bNeedsReinit = TRUE;
  2014. // if it may not be reinitialized
  2015. if (!bAllowReinit) {
  2016. ThrowF_t(TRANS("File '%s' was saved by an older version of engine, it cannot be loaded"),
  2017. strm.GetDescription());
  2018. }
  2019. return;
  2020. }
  2021. // this should not happen
  2022. ASSERT(FALSE);
  2023. bNeedsReinit = FALSE;
  2024. return;
  2025. }
  2026. // add a value to the netgraph
  2027. void CNetworkLibrary::AddNetGraphValue(enum NetGraphEntryType nget, FLOAT fLatency)
  2028. {
  2029. net_iGraphBuffer = Clamp(net_iGraphBuffer, INDEX(20), INDEX(1000));
  2030. // make sure the netgraph has wanted number of values
  2031. if (ga_angeNetGraph.Count()!=net_iGraphBuffer) {
  2032. ga_angeNetGraph.Clear();
  2033. ga_angeNetGraph.New(net_iGraphBuffer);
  2034. memset(&ga_angeNetGraph[0], 0, ga_angeNetGraph.Count()*sizeof(ga_angeNetGraph[0]));
  2035. }
  2036. // scroll the values in the netgraph by one value
  2037. memmove(&ga_angeNetGraph[1], &ga_angeNetGraph[0], (ga_angeNetGraph.Count()-1)*sizeof(ga_angeNetGraph[0]));
  2038. // add the new value
  2039. ga_angeNetGraph[0].nge_ngetType = nget;
  2040. ga_angeNetGraph[0].nge_fLatency = fLatency;
  2041. }
  2042. // make default state for a network game
  2043. extern void NET_MakeDefaultState_t(
  2044. const CTFileName &fnmWorld, ULONG ulSpawnFlags, void *pvSessionProperties,
  2045. CTStream &strmState) // throw char *
  2046. {
  2047. // mute all sounds
  2048. _pSound->Mute();
  2049. // first off - mark that we are in the special state
  2050. _bTempNetwork = TRUE;
  2051. // make sure that current network object gets locked
  2052. CTSingleLock slNetwork(&_pNetwork->ga_csNetwork, TRUE);
  2053. // remember original network pointer and clear it
  2054. CNetworkLibrary *pnlOld = _pNetwork;
  2055. _pNetwork = NULL;
  2056. // try to
  2057. try {
  2058. // create new network object
  2059. CNetworkLibrary *pNewNet = new CNetworkLibrary;
  2060. // it must have new mutex index since both will be locked
  2061. pNewNet->ga_csNetwork.cs_iIndex = 2001;
  2062. // lock the new network access
  2063. CTSingleLock slNetwork(&pNewNet->ga_csNetwork, TRUE);
  2064. pNewNet->ga_ctTimersPending = -1; // disable timer pending
  2065. // only after locking it, we may allow the new pointer to be remembered
  2066. // otherwise, the other thread can jump in between
  2067. _pNetwork = pNewNet;
  2068. // remember settings
  2069. _pNetwork->ga_sesSessionState.ses_ulSpawnFlags = ulSpawnFlags;
  2070. _pNetwork->ga_sesSessionState.ses_tmSyncCheckFrequency = 10.0f;
  2071. _pNetwork->ga_sesSessionState.ses_iExtensiveSyncCheck = 0;
  2072. memcpy(_pNetwork->ga_aubProperties, pvSessionProperties, NET_MAXSESSIONPROPERTIES);
  2073. _pNetwork->ga_fnmWorld = fnmWorld;
  2074. _pNetwork->ga_fnmNextLevel = CTString("");
  2075. try {
  2076. // load the world
  2077. _pTimer->SetCurrentTick(0.0f); // must have timer at 0 while loading
  2078. _pNetwork->ga_World.Load_t(fnmWorld);
  2079. // delete all entities that don't fit given spawn flags
  2080. _pNetwork->ga_World.FilterEntitiesBySpawnFlags(_pNetwork->ga_sesSessionState.ses_ulSpawnFlags);
  2081. } catch(char *) {
  2082. throw;
  2083. }
  2084. // remember the world filename
  2085. _pNetwork->ga_fnmWorld = fnmWorld;
  2086. _pNetwork->ga_fnmNextLevel = CTString("");
  2087. // remember the world pointer
  2088. _pShell->SetINDEX("pwoCurrentWorld", (INDEX)&_pNetwork->ga_World);
  2089. // reset random number generator
  2090. _pNetwork->ga_sesSessionState.ResetRND();
  2091. // flush stale caches
  2092. FreeUnusedStock();
  2093. // warmup the world
  2094. _pNetwork->ga_sesSessionState.WarmUpWorld();
  2095. // save the session state to the stream
  2096. _pNetwork->ga_sesSessionState.Write_t(&strmState);
  2097. // if any error
  2098. } catch (char *) {
  2099. // restore original network pointer
  2100. CNetworkLibrary *pnlTemp = _pNetwork;
  2101. _pNetwork = pnlOld;
  2102. if (pnlTemp!=NULL) {
  2103. delete pnlTemp;
  2104. }
  2105. _bTempNetwork = FALSE;
  2106. // fail
  2107. throw;
  2108. }
  2109. // restore original network pointer
  2110. CNetworkLibrary *pnlTemp = _pNetwork;
  2111. _pNetwork = pnlOld;
  2112. delete pnlTemp;
  2113. _bTempNetwork = FALSE;
  2114. }
  2115. // handle broadcast messages (server enumeration)
  2116. void CNetworkLibrary::GameInactive(void)
  2117. {
  2118. GameAgent_EnumUpdate();
  2119. // if no network
  2120. if (!_cmiComm.IsNetworkEnabled()) {
  2121. // do not handle
  2122. return;
  2123. }
  2124. // _cmiComm.Broadcast_Update();
  2125. // repeat
  2126. FOREVER {
  2127. CNetworkMessage nmReceived;
  2128. // _cmiComm.Broadcast_Update();
  2129. ULONG ulFrom;
  2130. UWORD uwPort;
  2131. BOOL bHasMsg = ReceiveBroadcast(nmReceived, ulFrom, uwPort);
  2132. // if there are no more messages
  2133. if (!bHasMsg) {
  2134. // finish
  2135. break;
  2136. }
  2137. /* This is handled by GameAgent.
  2138. // if requesting enumeration and this is server and enumeration is allowed
  2139. if (nmReceived.GetType()==MSG_REQ_ENUMSERVERS
  2140. && IsServer()
  2141. && (ser_bEnumeration && ga_sesSessionState.ses_ctMaxPlayers>1)) {
  2142. // create response
  2143. CNetworkMessage nmEnum(MSG_SERVERINFO);
  2144. nmEnum<<ga_strSessionName;
  2145. nmEnum<<ga_World.wo_strName;
  2146. nmEnum<<ga_srvServer.GetPlayersCount();
  2147. nmEnum<<ga_sesSessionState.ses_ctMaxPlayers;
  2148. // send it
  2149. SendBroadcast(nmEnum, ulFrom, uwPort);
  2150. // if receiving enumeration
  2151. } else if (nmReceived.GetType()==MSG_SERVERINFO) {
  2152. // create a new session
  2153. CNetworkSession &ns = *new CNetworkSession;
  2154. ga_lhEnumeratedSessions.AddTail(ns.ns_lnNode);
  2155. // read it
  2156. nmReceived>>ns.ns_strSession;
  2157. nmReceived>>ns.ns_strWorld;
  2158. nmReceived>>ns.ns_ctPlayers;
  2159. nmReceived>>ns.ns_ctMaxPlayers;
  2160. ns.ns_strAddress = AddressToString(ulFrom);
  2161. }*/
  2162. }
  2163. }
  2164. void CNetworkLibrary::InitCRCGather(void)
  2165. {
  2166. CRCT_ResetActiveList();
  2167. CRCT_bGatherCRCs = TRUE;
  2168. CRCT_AddFile_t(CTString("Classes\\Player.ecl"));
  2169. }
  2170. // finish gathering of file CRCs to CRC table (call for server only!)
  2171. void CNetworkLibrary::FinishCRCGather(void)
  2172. {
  2173. try {
  2174. // make the list
  2175. CTMemoryStream strmCRC;
  2176. CRCT_MakeFileList_t(strmCRC);
  2177. // remember it
  2178. strmCRC.SetPos_t(0);
  2179. ga_slCRCList = strmCRC.GetStreamSize();
  2180. ga_pubCRCList = (UBYTE*)AllocMemory(ga_slCRCList);
  2181. strmCRC.Read_t(ga_pubCRCList, ga_slCRCList);
  2182. // remember its CRC
  2183. strmCRC.SetPos_t(0);
  2184. ga_ulCRC = CRCT_MakeCRCForFiles_t(strmCRC);
  2185. } catch (char *strError) {
  2186. CPrintF(TRANS("Warning, cannot get CRCs: %s\n"), strError);
  2187. }
  2188. }
  2189. // make default state data for creating deltas
  2190. void CNetworkLibrary::MakeDefaultState(const CTFileName &fnmWorld,
  2191. ULONG ulSpawnFlags, void *pvSessionProperties)
  2192. {
  2193. // prepare file or memory stream for state
  2194. CTFileStream strmStateFile; CTMemoryStream strmStateMem;
  2195. CTStream *pstrmState;
  2196. extern INDEX net_bDumpConnectionInfo;
  2197. if (net_bDumpConnectionInfo) {
  2198. strmStateFile.Create_t(CTString("Temp\\DefaultState.bin"));
  2199. pstrmState = &strmStateFile;
  2200. } else {
  2201. pstrmState = &strmStateMem;
  2202. }
  2203. // make default state for a network game
  2204. NET_MakeDefaultState_t(fnmWorld, ulSpawnFlags, pvSessionProperties, *pstrmState);
  2205. pstrmState->SetPos_t(0);
  2206. ga_slDefaultStateSize = pstrmState->GetStreamSize();
  2207. ga_pubDefaultState = (UBYTE*)AllocMemory(ga_slDefaultStateSize);
  2208. pstrmState->Read_t(ga_pubDefaultState, ga_slDefaultStateSize);
  2209. memcpy(ga_aubDefaultProperties, pvSessionProperties, sizeof(ga_aubDefaultProperties));
  2210. }