12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525 |
- /* Copyright (c) 2002-2012 Croteam Ltd.
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as published by
- the Free Software Foundation
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
- #include "StdH.h"
- #include <Engine/Build.h>
- #include <Engine/Base/Console.h>
- #include <Engine/Base/CRCTable.h>
- #include <Engine/Base/Shell.h>
- #include <Engine/Base/ProgressHook.h>
- #include <Engine/Network/Server.h>
- #include <Engine/Network/SessionState.h>
- #include <Engine/Network/Network.h>
- #include <Engine/Network/PlayerSource.h>
- #include <Engine/Network/PlayerBuffer.h>
- #include <Engine/Network/PlayerTarget.h>
- #include <Engine/Entities/InternalClasses.h>
- #include <Engine/Entities/Precaching.h>
- #include <Engine/Network/CommunicationInterface.h>
- #include <Engine/Templates/Stock_CModelData.h>
- #include <Engine/Templates/Stock_CAnimData.h>
- #include <Engine/Templates/Stock_CTextureData.h>
- #include <Engine/Templates/Stock_CSoundData.h>
- #include <Engine/Templates/Stock_CEntityClass.h>
- #include <Engine/Base/Statistics_internal.h>
- #include <Engine/Graphics/DrawPort.h>
- #include <Engine/Sound/SoundLibrary.h>
- #include <Engine/Sound/SoundListener.h>
- #include <Engine/Rendering/Render.h>
- #include <Engine/Rendering/Render_internal.h>
- #include <Engine/Base/ListIterator.inl>
- #include <Engine/Math/Float.h>
- #include <Engine/Rendering/RenderProfile.h>
- #include <Engine/Network/NetworkProfile.h>
- #include <Engine/Network/LevelChange.h>
- #include <Engine/Brushes/BrushArchive.h>
- #include <Engine/Entities/Entity.h>
- #include <Engine/Models/ModelObject.h>
- #include <Engine/Ska/ModelInstance.h>
- #include <Engine/Entities/ShadingInfo.h>
- #include <Engine/Entities/EntityCollision.h>
- #include <Engine/Entities/LastPositions.h>
- #include <Engine/Templates/DynamicContainer.cpp>
- #include <Engine/Templates/DynamicArray.cpp>
- #include <Engine/Templates/StaticArray.cpp>
- #include <Engine/Templates/StaticStackArray.cpp>
- #include <Engine/Templates/Stock_CAnimData.h>
- #include <Engine/Templates/Stock_CTextureData.h>
- #include <Engine/Templates/Stock_CSoundData.h>
- #include <Engine/Templates/Stock_CEntityClass.h>
- #include <Engine/Templates/Stock_CModelData.h>
- #include <Engine/Templates/Stock_CAnimSet.h>
- #include <Engine/Templates/Stock_CMesh.h>
- #include <Engine/Templates/Stock_CShader.h>
- #include <Engine/Templates/Stock_CSkeleton.h>
- #include <Engine/GameAgent/GameAgent.h>
- // pointer to global instance of the only game object in the application
- CNetworkLibrary *_pNetwork= NULL;
- extern BOOL _bNeedPretouch;
- extern BOOL _bMultiPlayer = FALSE;
- extern INDEX _ctEntities = 0;
- extern INDEX _ctPredictorEntities = 0;
- extern LevelChangePhase _lphCurrent = LCP_NOCHANGE;
- extern BOOL _bTempNetwork = FALSE; // set while using temporary second network object
- extern BOOL con_bCapture;
- extern CTString con_strCapture;
- static CWorld *_pwoCurrentWorld = NULL;
- static FLOAT _bStartDemoRecordingNextTime = FALSE;
- static FLOAT _bStopDemoRecordingNextTime = FALSE;
- static INDEX dem_iRecordedNumber = 0;
- // network control
- extern INDEX ser_bReportSyncOK = FALSE;
- extern INDEX ser_bReportSyncBad = TRUE;
- extern INDEX ser_bReportSyncLate = FALSE;
- extern INDEX ser_bReportSyncEarly = FALSE;
- extern INDEX ser_bPauseOnSyncBad = FALSE;
- extern INDEX ser_iKickOnSyncBad = 10;
- extern INDEX ser_bKickOnSyncLate = 1;
- extern INDEX ser_iRememberBehind = 3000;
- extern INDEX ser_iExtensiveSyncCheck = 0;
- extern INDEX ser_bClientsMayPause = TRUE;
- extern FLOAT ser_tmSyncCheckFrequency = 1.0f;
- extern INDEX ser_iSyncCheckBuffer = 60;
- extern INDEX ser_bEnumeration = TRUE;
- extern INDEX ser_bPingGameAgent = TRUE;
- extern FLOAT ser_tmKeepAlive = 0.1f;
- extern FLOAT ser_tmPingUpdate = 3.0f;
- extern INDEX ser_bWaitFirstPlayer = 0;
- extern INDEX ser_iMaxAllowedBPS = 8000;
- extern CTString ser_strIPMask = "";
- extern CTString ser_strNameMask = "";
- extern INDEX ser_bInverseBanning = FALSE;
- extern CTString ser_strMOTD = "";
- extern INDEX cli_bEmulateDesync = FALSE;
- extern INDEX cli_bDumpSync = FALSE;
- extern INDEX cli_bDumpSyncEachTick = FALSE;
- extern INDEX cli_bAutoAdjustSettings = FALSE;
- extern FLOAT cli_tmAutoAdjustThreshold = 2.0f;
- extern INDEX cli_bPrediction = FALSE;
- extern INDEX cli_iMaxPredictionSteps = 10;
- extern INDEX cli_bPredictIfServer = FALSE;
- extern INDEX cli_bPredictLocalPlayers = TRUE;
- extern INDEX cli_bPredictRemotePlayers = FALSE;
- extern FLOAT cli_fPredictEntitiesRange = 20.0f;
- extern INDEX cli_bLerpActions = FALSE;
- extern INDEX cli_bReportPredicted = FALSE;
- extern INDEX cli_iSendBehind = 3;
- extern INDEX cli_iPredictionFlushing = 1;
- extern INDEX cli_iBufferActions = 1;
- extern INDEX cli_iMaxBPS = 4000;
- extern INDEX cli_iMinBPS = 0;
- extern INDEX net_iCompression = 1;
- extern INDEX net_bLookupHostNames = FALSE;
- extern INDEX net_bReportPackets = FALSE;
- extern INDEX net_iMaxSendRetries = 10;
- extern FLOAT net_fSendRetryWait = 0.5f;
- extern INDEX net_bReportTraffic = FALSE;
- extern INDEX net_bReportICMPErrors = FALSE;
- extern INDEX net_bReportMiscErrors = FALSE;
- extern INDEX net_bLerping = TRUE;
- extern INDEX net_iGraphBuffer = 100;
- extern INDEX net_iExactTimer = 2;
- extern INDEX net_bDumpStreamBlocks = 0;
- extern INDEX net_bDumpConnectionInfo = 0;
- extern INDEX net_iPort = 25600;
- extern CTString net_strLocalHost = "";
- extern CTString net_strLocationCode = "";
- extern CTString net_strConnectPassword = "";
- extern CTString net_strAdminPassword = "";
- extern CTString net_strVIPPassword = "";
- extern CTString net_strObserverPassword = "";
- extern INDEX net_iVIPReserve = 0;
- extern INDEX net_iMaxObservers = 16;
- extern INDEX net_iMaxClients = 0;
- extern FLOAT net_tmConnectionTimeout = 30.0f;
- extern FLOAT net_tmProblemsTimeout = 5.0f;
- extern FLOAT net_tmDisconnectTimeout = 300.0f; // must be higher for level changing
- extern INDEX net_bReportCRC = FALSE;
- extern FLOAT net_fDropPackets = 0.0f;
- extern FLOAT net_tmLatency = 0.0f;
- extern INDEX ent_bReportSpawnInWall = FALSE;
- extern FLOAT cmd_tmTick = 0.0f;
- extern CTString cmd_cmdOnTick = "";
- extern CTString cmd_strChatSender = "";
- extern CTString cmd_strChatMessage = "";
- extern CTString cmd_cmdOnChat = "";
- extern INDEX net_ctChatMessages = 0; // counter for incoming chat messages
- extern CPacketBufferStats _pbsSend;
- extern CPacketBufferStats _pbsRecv;
- extern BOOL _bPredictionActive = FALSE;
- class CGatherCRC {
- public:
- BOOL bOld;
- CGatherCRC();
- ~CGatherCRC();
- };
- CGatherCRC::CGatherCRC() {
- bOld = CRCT_bGatherCRCs;
- }
- CGatherCRC::~CGatherCRC() {
- CRCT_bGatherCRCs = bOld;
- }
- // precache control
- extern INDEX _precache_NONE = PRECACHE_NONE;
- extern INDEX _precache_SMART = PRECACHE_SMART;
- extern INDEX _precache_ALL = PRECACHE_ALL;
- extern INDEX _precache_PARANOIA = PRECACHE_PARANOIA;
- extern INDEX gam_iPrecachePolicy = _precache_SMART;
- extern INDEX _precache_bNowPrecaching = FALSE;
- extern INDEX dbg_bBreak = FALSE;
- extern INDEX gam_bPretouch = FALSE;
- extern FLOAT phy_fCollisionCacheAhead = 5.0f;
- extern FLOAT phy_fCollisionCacheAround = 1.5f;
- extern FLOAT cli_fPredictionFilter = 0.5f;
- extern INDEX shd_bCacheAll;
- // input
- extern INDEX inp_iKeyboardReadingMethod = 2; // 0=getasynckey, 1=virtkeytrap, 2=scancodetrap
- extern INDEX inp_bAllowMouseAcceleration = TRUE;
- extern FLOAT inp_fMouseSensitivity = 1.0f;
- extern INDEX inp_bMousePrecision = FALSE;
- extern FLOAT inp_fMousePrecisionFactor = 4.0f;
- extern FLOAT inp_fMousePrecisionThreshold = 10.0f;
- extern FLOAT inp_fMousePrecisionTimeout = 0.25f;
- extern FLOAT inp_bInvertMouse = FALSE;
- extern INDEX inp_bFilterMouse = FALSE;
- extern INDEX inp_bAllowPrescan = TRUE;
- extern INDEX inp_i2ndMousePort = 0; // COM no (0=disable)
- extern FLOAT inp_f2ndMouseSensitivity = 1.0f;
- extern INDEX inp_b2ndMousePrecision = FALSE;
- extern FLOAT inp_f2ndMousePrecisionFactor = 4.0f;
- extern FLOAT inp_f2ndMousePrecisionThreshold = 10.0f;
- extern FLOAT inp_f2ndMousePrecisionTimeout = 0.25f;
- extern INDEX inp_bInvert2ndMouse = FALSE;
- extern INDEX inp_bFilter2ndMouse = FALSE;
- extern INDEX inp_iMButton4Up;
- extern INDEX inp_iMButton4Dn;
- extern INDEX inp_iMButton5Up;
- extern INDEX inp_iMButton5Dn;
- extern INDEX inp_bMsgDebugger;
- extern INDEX inp_ctJoysticksAllowed;
- extern INDEX inp_bForceJoystickPolling;
- extern INDEX inp_bAutoDisableJoysticks;
- extern INDEX wed_bUseGenericTextureReplacement = FALSE;
- extern void RendererInfo(void);
- extern void ClearRenderer(void);
- // cache all shadowmaps now
- extern void CacheShadows(void)
- {
- // mute all sounds
- _pSound->Mute();
- CWorld *pwo = (CWorld*)_pShell->GetINDEX("pwoCurrentWorld");
- if( pwo!=NULL) {
- pwo->wo_baBrushes.CacheAllShadowmaps();
- CPrintF( TRANS("All shadows recached"));
- if( shd_bCacheAll) CPrintF(".\n");
- else CPrintF( TRANS(", but not for long.\n(precache all shadows function is disabled)\n"));
- }
- // mark that we need pretouching
- _bNeedPretouch = TRUE;
- }
- // check if a name or IP matches a mask
- extern BOOL MatchesBanMask(const CTString &strString, const CTString &strMask)
- {
- CTString strRest = strMask;
- CTString strLine;
- while(strRest!="") {
- strLine = strRest;
- strLine.OnlyFirstLine();
- strRest.RemovePrefix(strLine);
- strRest.DeleteChar(0);
- if (strString.Matches(strLine)) {
- return TRUE;
- }
- }
- return FALSE;
- }
- extern CTString RemoveSubstring(const CTString &strFull, const CTString &strSub);
- static void AddIPMask(void* pArgs)
- {
- CTString strIP = *NEXTARGUMENT(CTString*);
- ser_strIPMask+= strIP+"\n";
- }
- static void RemIPMask(void* pArgs)
- {
- CTString strIP = *NEXTARGUMENT(CTString*);
- ser_strIPMask = RemoveSubstring(ser_strIPMask, strIP+"\n");
- }
- static void AddNameMask(void* pArgs)
- {
- CTString strName = *NEXTARGUMENT(CTString*);
- ser_strNameMask += strName+"\n";
- }
- static void RemNameMask(void* pArgs)
- {
- CTString strName = *NEXTARGUMENT(CTString*);
- ser_strNameMask = RemoveSubstring(ser_strNameMask, strName+"\n");
- }
- static void StartDemoRecording(void)
- {
- _bStartDemoRecordingNextTime = TRUE;
- }
- static void StopDemoRecording(void)
- {
- _bStopDemoRecordingNextTime = TRUE;
- }
- static void NetworkInfo(void)
- {
- CPrintF("*Network library information:\n");
- CPrintF("Entities existing: %d\n", _ctEntities);
- CPrintF("Predictor entities existing: %d\n", _ctPredictorEntities);
- CPrintF("Server:\n");
- if (_pNetwork->ga_srvServer.srv_bActive) {
- CPrintF(" last processed tick: %g\n", _pNetwork->ga_srvServer.srv_tmLastProcessedTick);
- CPrintF(" last processed sequence: %d\n", _pNetwork->ga_srvServer.srv_iLastProcessedSequence);
- CPrintF(" players:\n");
- for(INDEX iplb=0; iplb<_pNetwork->ga_srvServer.srv_aplbPlayers.Count(); iplb++) {
- CPlayerBuffer &plb = _pNetwork->ga_srvServer.srv_aplbPlayers[iplb];
- if (plb.plb_Active) {
- CPrintF(" %2d(%2d):'%s'@client%2d: (%dact)\n",
- iplb, plb.plb_Index, plb.plb_pcCharacter.GetNameForPrinting(),
- plb.plb_iClient, plb.plb_abReceived.GetCount());
- }
- }
- CPrintF(" clients:\n");
- for(INDEX iSession=0; iSession<_pNetwork->ga_srvServer.srv_assoSessions.Count(); iSession++) {
- CSessionSocket &sso = _pNetwork->ga_srvServer.srv_assoSessions[iSession];
- if (sso.sso_bActive) {
- CPrintF(" %2d:'%s'\n", iSession, _cmiComm.Server_GetClientName(iSession)),
- CPrintF(" buffer: %dblk=%dk\n",
- sso.sso_nsBuffer.GetUsedBlocks(),
- sso.sso_nsBuffer.GetUsedMemory()/1024);
- CPrintF(" state:");
- if (sso.sso_iDisconnectedState>0) {
- CPrintF(" disconnecting");
- } else if (sso.sso_bSendStream) {
- CPrintF(" connected");
- } else {
- CPrintF(" connecting");
- }
- CPrintF("\n");
- }
- }
- } else {
- CPrintF(" not a server\n");
- }
- CPrintF("Session state:\n");
- CPrintF(" buffer: (%dblk)%dk\n",
- _pNetwork->ga_sesSessionState.ses_nsGameStream.GetUsedBlocks(),
- _pNetwork->ga_sesSessionState.ses_nsGameStream.GetUsedMemory()/1024);
- CPrintF(" last processed tick: %g\n", _pNetwork->ga_sesSessionState.ses_tmLastProcessedTick);
- CPrintF(" last processed sequence: %d\n", _pNetwork->ga_sesSessionState.ses_iLastProcessedSequence);
- CPrintF(" level change: %d\n", _pNetwork->ga_sesSessionState.ses_iLevel);
- for(INDEX iplt=0; iplt<_pNetwork->ga_sesSessionState.ses_apltPlayers.Count(); iplt++) {
- CPlayerTarget &plt = _pNetwork->ga_sesSessionState.ses_apltPlayers[iplt];
- if (plt.plt_bActive) {
- ULONG ulID = -1;
- if (plt.plt_penPlayerEntity!=NULL) {
- ulID = plt.plt_penPlayerEntity->en_ulID;
- }
- CPrintF(" player %2d (ID:%d): (%dact)\n", iplt, ulID, plt.plt_abPrediction.GetCount());
- }
- }
- if (TIMER_PROFILING) {
- CTString strNetProfile;
- _pfNetworkProfile.Report(strNetProfile);
- CPrintF(strNetProfile);
- }
- }
- static void ListPlayers(void)
- {
- CPrintF("player list:\n");
- if (!_pNetwork->ga_srvServer.srv_bActive) {
- CPrintF(" <not a server>\n");
- return;
- }
- CPrintF(" client# name\n");
- CPrintF(" ----------------------\n");
- for(INDEX iplb=0; iplb<_pNetwork->ga_srvServer.srv_aplbPlayers.Count(); iplb++) {
- CPlayerBuffer &plb = _pNetwork->ga_srvServer.srv_aplbPlayers[iplb];
- if (plb.plb_Active) {
- CPrintF(" %-2d %s\n", plb.plb_iClient, plb.plb_pcCharacter.GetNameForPrinting());
- }
- }
- CPrintF(" ----------------------\n");
- }
- static void KickClient(INDEX iClient, const CTString &strReason)
- {
- if (!_pNetwork->IsServer()) {
- CPrintF( TRANS("Only server can kick people!\n"));
- return;
- }
- iClient = Clamp(iClient, INDEX(0), INDEX(NET_MAXGAMECOMPUTERS));
- if (!_pNetwork->ga_srvServer.srv_assoSessions[iClient].IsActive()) {
- CPrintF(TRANS("Client not connected!\n"));
- return;
- }
- if (iClient == 0) {
- CPrintF(TRANS("Can't kick local client!\n"));
- return;
- }
- CPrintF( TRANS("Kicking %d with explanation '%s'...\n"), iClient, strReason);
- _pNetwork->ga_srvServer.SendDisconnectMessage(iClient, "Admin: "+strReason);
- }
- static void KickClientCfunc(void* pArgs)
- {
- INDEX iClient = NEXTARGUMENT(INDEX);
- CTString strReason = *NEXTARGUMENT(CTString*);
- KickClient(iClient, strReason);
- }
- static void KickByName(const CTString &strName, const CTString &strReason)
- {
- if (!_pNetwork->IsServer()) {
- CPrintF( TRANS("Only server can kick people!\n"));
- return;
- }
- for(INDEX iplb=0; iplb<_pNetwork->ga_srvServer.srv_aplbPlayers.Count(); iplb++) {
- CPlayerBuffer &plb = _pNetwork->ga_srvServer.srv_aplbPlayers[iplb];
- if (plb.plb_Active && plb.plb_pcCharacter.GetNameForPrinting().Undecorated().Matches(strName)) {
- KickClient(plb.plb_iClient, strReason);
- }
- }
- }
- static void KickByNameCfunc(void* pArgs)
- {
- CTString strName = *NEXTARGUMENT(CTString*);
- CTString strReason = *NEXTARGUMENT(CTString*);
- KickByName(strName, strReason);
- }
- static void Admin(void* pArgs)
- {
- CTString strCommand = *NEXTARGUMENT(CTString*);
- CNetworkMessage nm(MSG_ADMIN_COMMAND);
- nm<<net_strAdminPassword<<strCommand;
- _pNetwork->SendToServerReliable(nm);
- }
- static void StockInfo(void)
- {
- // find memory used by shadowmap (both cached and uploaded)
- INDEX ctCachedShadows=0, ctDynamicShadows=0, ctFlatShadows=0;
- SLONG slStaticMemory=0, slDynamicMemory=0, slUploadMemory=0;
- SLONG slShdBytes=0, slSlackMemory=0, slFlatMemory=0;
- INDEX ct256=0, ct128=0, ct64=0, ct32=0, ct16=0;
- SLONG sl256Memory=0, sl128Memory=0, sl64Memory=0, sl32Memory=0, sl16Memory=0;
- if( _pGfx!=NULL)
- {
- FLOAT fSlackRatio;
- FOREACHINLIST( CShadowMap, sm_lnInGfx, _pGfx->gl_lhCachedShadows, itsm)
- { // get polygon size in pixels (used portion of shadowmap)
- SLONG slStaticSize, slDynamicSize, slUploadSize;
- BOOL bIsFlat = itsm->GetUsedMemory( slStaticSize, slDynamicSize, slUploadSize, fSlackRatio);
- SLONG slTotalSize = slDynamicSize+slUploadSize;
- if( bIsFlat) {
- slStaticMemory += 4;
- slTotalSize += 4;
- slFlatMemory += slStaticSize;
- ctFlatShadows++;
- } else {
- slStaticMemory += slStaticSize;
- slTotalSize += slStaticSize;
- if( slTotalSize>0) ctCachedShadows++;
- }
- if( slDynamicSize>0) {
- slDynamicMemory += slDynamicSize;
- ctDynamicShadows++;
- }
- slUploadMemory += slUploadSize;
- slShdBytes += slTotalSize + sizeof(CShadowMap);
- slSlackMemory += slTotalSize*fSlackRatio;
- if( !bIsFlat) { // by size ...
- if( slStaticSize>128*1024) { ct256++; sl256Memory+=slTotalSize; }
- else if( slStaticSize> 64*1024) { ct128++; sl128Memory+=slTotalSize; }
- else if( slStaticSize> 32*1024) { ct64++; sl64Memory +=slTotalSize; }
- else if( slStaticSize> 16*1024) { ct32++; sl32Memory +=slTotalSize; }
- else if( slStaticSize> 0) { ct16++; sl16Memory +=slTotalSize; }
- }
- }
- // report shadowmap memory usage (if any)
- if( slShdBytes>0) {
- CPrintF( "\nCached shadowmaps:\n");
- CPrintF( " Total: %d in %d KB with %d%% (%d KB) of slack space\n", ctCachedShadows, slShdBytes/1024, slSlackMemory*100/slShdBytes, slSlackMemory/1024);
- CPrintF( " Static: %d KB\n", slStaticMemory/1024);
- CPrintF( " Upload: %d KB\n", slUploadMemory/1024);
- CPrintF( " Dynamic: %d in %d KB\n", ctDynamicShadows, slDynamicMemory/1024);
- if( ctCachedShadows<1) ctCachedShadows=1; // for percentage calc
- CPrintF( " Flats: %d (%d%%) with %d KB saved\n", ctFlatShadows, ctFlatShadows*100/ctCachedShadows, slFlatMemory/1024);
- CPrintF("of size:\n");
- CPrintF( " >128K: %4d in %d KB\n", ct256, sl256Memory/1024);
- CPrintF( " 128-64K: %4d in %d KB\n", ct128, sl128Memory/1024);
- CPrintF( " 64-32K: %4d in %d KB\n", ct64, sl64Memory /1024);
- CPrintF( " 32-16K: %4d in %d KB\n", ct32, sl32Memory /1024);
- CPrintF( " <=16K: %4d in %d KB\n", ct16, sl16Memory /1024);
- }
- }
- // report world stats
- INDEX ctEntities=0, ctShadowLayers=0, ctPolys=0, ctPlanes=0, ctEdges=0, ctVertices=0, ctSectors=0;
- SLONG slEntBytes=0, slLyrBytes=0, slPlyBytes=0, slPlnBytes=0, slEdgBytes=0, slVtxBytes=0, slSecBytes=0;
- SLONG slCgrBytes=0;
- CWorld *pwo = (CWorld*)_pShell->GetINDEX("pwoCurrentWorld");
- if( pwo!=NULL)
- {
- // report count of and memory used by entities
- FOREACHINDYNAMICCONTAINER( pwo->wo_cenEntities, CEntity, iten) {
- ctEntities++;
- slEntBytes += iten->GetUsedMemory();
- }
- // report shadow layers and world geometry memory usage
- FOREACHINDYNAMICARRAY( pwo->wo_baBrushes.ba_abrBrushes, CBrush3D, itbr) // for all brush entities in the world
- {
- // skip brush without entity
- if( itbr->br_penEntity==NULL) continue;
- // for each mip
- FOREACHINLIST( CBrushMip, bm_lnInBrush, itbr->br_lhBrushMips, itbm)
- {
- // for each sector in the brush mip
- FOREACHINDYNAMICARRAY( itbm->bm_abscSectors, CBrushSector, itbsc)
- {
- // add sector class memory usage to polygons memory
- ctSectors++;
- slSecBytes += itbsc->GetUsedMemory();
- // add each vertex and working vertex in sector
- ctVertices += itbsc->bsc_abvxVertices.Count();
- FOREACHINSTATICARRAY( itbsc->bsc_abvxVertices, CBrushVertex, itbvx) slVtxBytes += itbvx->GetUsedMemory();
- FOREACHINSTATICARRAY( itbsc->bsc_awvxVertices, CWorkingVertex, itwvx) slVtxBytes += 32; // aligned to 32 bytes!
- // add each plane and working plane in sector
- ctPlanes += itbsc->bsc_abplPlanes.Count();
- FOREACHINSTATICARRAY( itbsc->bsc_abplPlanes, CBrushPlane, itbpl) slPlnBytes += itbpl->GetUsedMemory();
- FOREACHINSTATICARRAY( itbsc->bsc_awplPlanes, CWorkingPlane, itwpl) slPlnBytes += sizeof(CWorkingPlane);
- // add each edge and working edge in sector
- ctEdges += itbsc->bsc_abedEdges.Count();
- FOREACHINSTATICARRAY( itbsc->bsc_abedEdges, CBrushEdge, itbed) slEdgBytes += itbed->GetUsedMemory();
- FOREACHINSTATICARRAY( itbsc->bsc_awedEdges, CWorkingEdge, itwed) slEdgBytes += sizeof(CWorkingEdge);
- // for each polygon in sector
- ctPolys += itbsc->bsc_abpoPolygons.Count();
- FOREACHINSTATICARRAY( itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo) {
- CBrushPolygon &bpo = *itbpo;
- slPlyBytes += bpo.GetUsedMemory();
- // count in the shadow layers (if any)
- if( bpo.bpo_smShadowMap.bsm_lhLayers.IsEmpty()) continue; // skip polygon without shadowmap
- ctShadowLayers += bpo.bpo_smShadowMap.GetShadowLayersCount();
- slLyrBytes += bpo.bpo_smShadowMap.GetUsedMemory();
- }
- }
- }
- } // add in memory used by collision grid
- extern SLONG GetCollisionGridMemory( CCollisionGrid *pcg);
- slCgrBytes += GetCollisionGridMemory( pwo->wo_pcgCollisionGrid);
- }
- // stock info
- const DOUBLE dToMB = 1.0/1024.0/1024.0;
- const FLOAT fTexBytes = dToMB * _pTextureStock->CalculateUsedMemory();
- const FLOAT fMdlBytes = dToMB * _pModelStock->CalculateUsedMemory();
- const FLOAT fSndBytes = dToMB * _pSoundStock->CalculateUsedMemory();
- const FLOAT fMshBytes = dToMB * _pMeshStock->CalculateUsedMemory();
- const FLOAT fAstBytes = dToMB * _pAnimSetStock->CalculateUsedMemory();
- const FLOAT fShaBytes = dToMB * _pShaderStock->CalculateUsedMemory();
- const FLOAT fSkaBytes = dToMB * _pSkeletonStock->CalculateUsedMemory();
- CPrintF("\nStock information:\n");
- CPrintF(" Textures: %5d (%5.2f MB)\n", _pTextureStock->GetTotalCount(), fTexBytes);
- CPrintF(" ShadowMaps: %5d (%5.2f MB)\n", ctCachedShadows, slShdBytes*dToMB);
- CPrintF(" Entities: %5d (%5.2f MB)\n", ctEntities, slEntBytes*dToMB);
- CPrintF(" Sounds: %5d (%5.2f MB)\n", _pSoundStock->GetTotalCount(), fSndBytes);
- CPrintF("\n");
- CPrintF(" Sectors: %5d (%5.2f MB)\n", ctSectors, slSecBytes*dToMB);
- CPrintF(" Planes: %5d (%5.2f MB)\n", ctPlanes, slPlnBytes*dToMB);
- CPrintF(" Edges: %5d (%5.2f MB)\n", ctEdges, slEdgBytes*dToMB);
- CPrintF(" Polygons: %5d (%5.2f MB)\n", ctPolys, slPlyBytes*dToMB);
- CPrintF(" Vertices: %5d (%5.2f MB)\n", ctVertices, slVtxBytes*dToMB);
- CPrintF(" ShadowLayers: %5d (%5.2f MB)\n", ctShadowLayers, slLyrBytes*dToMB);
- CPrintF("\n");
- CPrintF(" Models: %5d (%5.2f MB)\n", _pModelStock->GetTotalCount(), fMdlBytes);
- CPrintF(" Meshes: %5d (%5.2f MB)\n", _pMeshStock->GetTotalCount(), fMshBytes);
- CPrintF(" Skeletons: %5d (%5.2f MB)\n", _pSkeletonStock->GetTotalCount(), fSkaBytes);
- CPrintF(" AnimSets: %5d (%5.2f MB)\n", _pAnimSetStock->GetTotalCount(), fAstBytes);
- CPrintF(" Shaders: %5d (%5.2f MB)\n", _pShaderStock->GetTotalCount(), fShaBytes);
- CPrintF("\n");
- CPrintF("CollisionGrid: %.2f MB\n", slCgrBytes*dToMB);
- CPrintF("--------------\n");
- CPrintF(" Total: %.2f MB\n", fTexBytes+fSndBytes+fMdlBytes+fMshBytes+fSkaBytes+fAstBytes+fShaBytes
- + (slShdBytes+slEntBytes+slSecBytes+slPlnBytes+slEdgBytes+slPlyBytes+slVtxBytes+slLyrBytes+slCgrBytes)*dToMB);
- CPrintF("\n");
- }
- static void StockDump(void)
- {
- try {
- CTFileStream strm;
- CTFileName fnm = CTString("Temp\\StockDump.txt");
- strm.Create_t(fnm);
- strm.PutLine_t("Animations:");
- _pAnimStock->DumpMemoryUsage_t(strm);
- strm.PutLine_t("Textures:");
- _pTextureStock->DumpMemoryUsage_t(strm);
- strm.PutLine_t("Models:");
- _pModelStock->DumpMemoryUsage_t(strm);
- strm.PutLine_t("Sounds:");
- _pSoundStock->DumpMemoryUsage_t(strm);
- strm.PutLine_t("Classes:");
- _pEntityClassStock->DumpMemoryUsage_t(strm);
- CPrintF("Dumped to '%s'\n", CTString(fnm));
- } catch (char *strError) {
- CPrintF("Error: %s\n", strError);
- }
- }
- // free all unused stocks
- extern void FreeUnusedStock(void)
- {
- // free all unused stocks
- _pEntityClassStock->FreeUnused();
- _pModelStock->FreeUnused();
- _pSoundStock->FreeUnused();
- _pTextureStock->FreeUnused();
- _pAnimStock->FreeUnused();
- }
- /*
- * This is called every TickQuantum seconds.
- */
- void CNetworkTimerHandler::HandleTimer(void)
- {
- if (this==NULL || _bTempNetwork) {
- return; // this can happen during NET_MakeDefaultState_t()!
- }
- // enable stream handling during timer
- CTSTREAM_BEGIN {
- // do the timer loop
- _pNetwork->TimerLoop();
- } CTSTREAM_END;
- }
- /*
- * Default constructor.
- */
- CNetworkLibrary::CNetworkLibrary(void) :
- ga_IsServer(FALSE), // is not server
- ga_bDemoRec(FALSE), // not recording demo
- ga_bDemoPlay(FALSE), // not playing demo
- ga_bDemoPlayFinished(FALSE), // demo not finished
- ga_srvServer(*new CServer),
- ga_sesSessionState(*new CSessionState)
- {
- ga_aplsPlayers.New(NET_MAXLOCALPLAYERS);
- // default demo syncronization is real-time, with 1:1 playback speed
- ga_fDemoSyncRate = DEMOSYNC_REALTIME;
- ga_fDemoRealTimeFactor = 1.0f;
- ga_fGameRealTimeFactor = 1.0f;
- ga_pubDefaultState = NULL;
- ga_slDefaultStateSize = 0;
- memset(ga_aubDefaultProperties, 0, sizeof(ga_aubDefaultProperties));
- ga_pubCRCList = NULL;
- ga_slCRCList = 0;
- ga_ulDemoMinorVersion = _SE_BUILD_MINOR;
- ga_csNetwork.cs_iIndex = 2000;
- ga_ctTimersPending = -1;
- ga_fEnumerationProgress = 0;
- ga_bEnumerationChange = FALSE;
- }
- /*
- * Destructor.
- */
- CNetworkLibrary::~CNetworkLibrary(void)
- {
- // clear the global world
- ga_World.DeletePredictors();
- ga_World.Clear();
- // free renderer info to free pointers to entities etc.
- if (!_bTempNetwork) {
- extern void ClearRenderer(void);
- ClearRenderer();
- }
- delete &ga_sesSessionState;
- delete &ga_srvServer;
- }
- /*
- * Initialize game management.
- */
- void CNetworkLibrary::Init(const CTString &strGameID)
- {
- // remember the game ID
- CMessageDispatcher::Init(strGameID);
- // add shell symbols
- _pShell->DeclareSymbol("user INDEX dbg_bBreak;", &dbg_bBreak);
- _pShell->DeclareSymbol("persistent user INDEX gam_bPretouch;", &gam_bPretouch);
- _pShell->DeclareSymbol("user INDEX dem_iRecordedNumber;", &dem_iRecordedNumber);
- _pShell->DeclareSymbol("user void StartDemoRecording(void);", &StartDemoRecording);
- _pShell->DeclareSymbol("user void StopDemoRecording(void);", &StopDemoRecording);
- _pShell->DeclareSymbol("user void NetworkInfo(void);", &NetworkInfo);
- _pShell->DeclareSymbol("user void StockInfo(void);", &StockInfo);
- _pShell->DeclareSymbol("user void StockDump(void);", &StockDump);
- _pShell->DeclareSymbol("user void RendererInfo(void);", &RendererInfo);
- _pShell->DeclareSymbol("user void ClearRenderer(void);", &ClearRenderer);
- _pShell->DeclareSymbol("user void CacheShadows(void);", &CacheShadows);
- _pShell->DeclareSymbol("user void KickClient(INDEX, CTString);", &KickClientCfunc);
- _pShell->DeclareSymbol("user void KickByName(CTString, CTString);", &KickByNameCfunc);
- _pShell->DeclareSymbol("user void ListPlayers(void);", &ListPlayers);
- _pShell->DeclareSymbol("user void Admin(CTString);", &Admin);
- _pShell->DeclareSymbol("user void AddIPMask(CTString);", &AddIPMask);
- _pShell->DeclareSymbol("user void RemIPMask(CTString);", &RemIPMask);
- _pShell->DeclareSymbol("user void AddNameMask(CTString);", &AddNameMask);
- _pShell->DeclareSymbol("user void RemNameMask(CTString);", &RemNameMask);
- _pShell->DeclareSymbol("user FLOAT dem_tmTimer;", &ga_fDemoTimer);
- _pShell->DeclareSymbol("user FLOAT dem_fSyncRate;", &ga_fDemoSyncRate);
- _pShell->DeclareSymbol("user FLOAT dem_fRealTimeFactor;", &ga_fDemoRealTimeFactor);
- _pShell->DeclareSymbol("user FLOAT gam_fRealTimeFactor;", &ga_fGameRealTimeFactor);
- _pShell->DeclareSymbol("user const FLOAT net_tmLatency;", &net_tmLatency);
- _pShell->DeclareSymbol("user const FLOAT cmd_tmTick;", &cmd_tmTick);
- _pShell->DeclareSymbol("persistent user CTString cmd_cmdOnTick;", &cmd_cmdOnTick);
- _pShell->DeclareSymbol("user CTString cmd_strChatSender ;", &cmd_strChatSender );
- _pShell->DeclareSymbol("user CTString cmd_strChatMessage;", &cmd_strChatMessage);
- _pShell->DeclareSymbol("persistent user CTString cmd_cmdOnChat;", &cmd_cmdOnChat);
- _pShell->DeclareSymbol("user INDEX net_ctChatMessages;", &net_ctChatMessages);
- _pShell->DeclareSymbol("persistent user INDEX ent_bReportSpawnInWall;", &ent_bReportSpawnInWall);
- _pShell->DeclareSymbol("user INDEX ser_bReportSyncOK;", &ser_bReportSyncOK);
- _pShell->DeclareSymbol("user INDEX ser_bReportSyncBad;", &ser_bReportSyncBad);
- _pShell->DeclareSymbol("user INDEX ser_bReportSyncLate;", &ser_bReportSyncLate);
- _pShell->DeclareSymbol("user INDEX ser_bReportSyncEarly;", &ser_bReportSyncEarly);
- _pShell->DeclareSymbol("user INDEX ser_bPauseOnSyncBad;", &ser_bPauseOnSyncBad);
- _pShell->DeclareSymbol("user INDEX ser_iKickOnSyncBad;", &ser_iKickOnSyncBad);
- _pShell->DeclareSymbol("user INDEX ser_bKickOnSyncLate;", &ser_bKickOnSyncLate);
- _pShell->DeclareSymbol("persistent user FLOAT ser_tmSyncCheckFrequency;", &ser_tmSyncCheckFrequency);
- _pShell->DeclareSymbol("persistent user INDEX ser_iSyncCheckBuffer;", &ser_iSyncCheckBuffer);
- _pShell->DeclareSymbol("persistent user INDEX cli_bLerpActions;", &cli_bLerpActions);
- _pShell->DeclareSymbol("persistent user INDEX cli_bReportPredicted;", &cli_bReportPredicted);
- _pShell->DeclareSymbol("persistent user INDEX net_iExactTimer;", &net_iExactTimer);
- _pShell->DeclareSymbol("user INDEX net_bDumpStreamBlocks;", &net_bDumpStreamBlocks);
- _pShell->DeclareSymbol("user INDEX net_bDumpConnectionInfo;", &net_bDumpConnectionInfo);
- _pShell->DeclareSymbol("user INDEX net_iPort;", &net_iPort);
- _pShell->DeclareSymbol("persistent user CTString net_strLocalHost;", &net_strLocalHost);
- _pShell->DeclareSymbol("persistent user CTString net_strLocationCode;", &net_strLocationCode);
- _pShell->DeclareSymbol("user CTString net_strVIPPassword;", &net_strVIPPassword);
- _pShell->DeclareSymbol("user CTString net_strObserverPassword;", &net_strObserverPassword);
- _pShell->DeclareSymbol("user INDEX net_iVIPReserve;", &net_iVIPReserve);
- _pShell->DeclareSymbol("user INDEX net_iMaxObservers;", &net_iMaxObservers);
- _pShell->DeclareSymbol("user INDEX net_iMaxClients;", &net_iMaxClients);
- _pShell->DeclareSymbol("user CTString net_strConnectPassword;", &net_strConnectPassword);
- _pShell->DeclareSymbol("user CTString net_strAdminPassword;", &net_strAdminPassword);
- _pShell->DeclareSymbol("user FLOAT net_tmConnectionTimeout;", &net_tmConnectionTimeout);
- _pShell->DeclareSymbol("user FLOAT net_tmProblemsTimeout;", &net_tmProblemsTimeout);
- _pShell->DeclareSymbol("user FLOAT net_tmDisconnectTimeout;", &net_tmDisconnectTimeout);
- _pShell->DeclareSymbol("user INDEX net_bReportCRC;", &net_bReportCRC);
- _pShell->DeclareSymbol("user INDEX ser_iRememberBehind;", &ser_iRememberBehind);
- _pShell->DeclareSymbol("user INDEX cli_bEmulateDesync;", &cli_bEmulateDesync);
- _pShell->DeclareSymbol("user INDEX cli_bDumpSync;", &cli_bDumpSync);
- _pShell->DeclareSymbol("user INDEX cli_bDumpSyncEachTick;",&cli_bDumpSyncEachTick);
- _pShell->DeclareSymbol("persistent user INDEX ser_iExtensiveSyncCheck;", &ser_iExtensiveSyncCheck);
- _pShell->DeclareSymbol("persistent user INDEX net_bLookupHostNames;", &net_bLookupHostNames);
- _pShell->DeclareSymbol("persistent user INDEX net_iCompression ;", &net_iCompression);
- _pShell->DeclareSymbol("persistent user INDEX net_bReportPackets;", &net_bReportPackets);
- _pShell->DeclareSymbol("persistent user INDEX net_iMaxSendRetries;", &net_iMaxSendRetries);
- _pShell->DeclareSymbol("persistent user FLOAT net_fSendRetryWait;", &net_fSendRetryWait);
- _pShell->DeclareSymbol("persistent user INDEX net_bReportTraffic;", &net_bReportTraffic);
- _pShell->DeclareSymbol("persistent user INDEX net_bReportICMPErrors;", &net_bReportICMPErrors);
- _pShell->DeclareSymbol("persistent user INDEX net_bReportMiscErrors;", &net_bReportMiscErrors);
- _pShell->DeclareSymbol("persistent user INDEX net_bLerping;", &net_bLerping);
- _pShell->DeclareSymbol("persistent user INDEX ser_bClientsMayPause;", &ser_bClientsMayPause);
- _pShell->DeclareSymbol("persistent user INDEX ser_bEnumeration;", &ser_bEnumeration);
- _pShell->DeclareSymbol("persistent user INDEX ser_bPingGameAgent;", &ser_bPingGameAgent);
- _pShell->DeclareSymbol("persistent user FLOAT ser_tmKeepAlive;", &ser_tmKeepAlive);
- _pShell->DeclareSymbol("persistent user FLOAT ser_tmPingUpdate;", &ser_tmPingUpdate);
- _pShell->DeclareSymbol("persistent user INDEX ser_bWaitFirstPlayer;", &ser_bWaitFirstPlayer);
- _pShell->DeclareSymbol("persistent user INDEX ser_iMaxAllowedBPS;", &ser_iMaxAllowedBPS);
- _pShell->DeclareSymbol("persistent user INDEX ser_iMaxAllowedBPS;", &ser_iMaxAllowedBPS);
- _pShell->DeclareSymbol("persistent user CTString ser_strIPMask;", &ser_strIPMask);
- _pShell->DeclareSymbol("persistent user CTString ser_strNameMask;", &ser_strNameMask);
- _pShell->DeclareSymbol("persistent user INDEX ser_bInverseBanning;", &ser_bInverseBanning);
- _pShell->DeclareSymbol("persistent user CTString ser_strMOTD;", &ser_strMOTD);
- _pShell->DeclareSymbol("persistent user INDEX cli_bAutoAdjustSettings;", &cli_bAutoAdjustSettings);
- _pShell->DeclareSymbol("persistent user FLOAT cli_tmAutoAdjustThreshold;", &cli_tmAutoAdjustThreshold);
- _pShell->DeclareSymbol("persistent user INDEX cli_bPrediction;", &cli_bPrediction);
- _pShell->DeclareSymbol("persistent user INDEX cli_iMaxPredictionSteps;", &cli_iMaxPredictionSteps);
- _pShell->DeclareSymbol("persistent user INDEX cli_bPredictIfServer;", &cli_bPredictIfServer);
- _pShell->DeclareSymbol("persistent user INDEX cli_bPredictLocalPlayers;", &cli_bPredictLocalPlayers);
- _pShell->DeclareSymbol("persistent user INDEX cli_bPredictRemotePlayers;", &cli_bPredictRemotePlayers);
- _pShell->DeclareSymbol("persistent user FLOAT cli_fPredictEntitiesRange;", &cli_fPredictEntitiesRange);
- _pShell->DeclareSymbol("persistent user FLOAT cli_fPredictionFilter;", &cli_fPredictionFilter);
- _pShell->DeclareSymbol("persistent user INDEX cli_iSendBehind;", &cli_iSendBehind);
- _pShell->DeclareSymbol("persistent user INDEX cli_iPredictionFlushing;", &cli_iPredictionFlushing);
- _pShell->DeclareSymbol("persistent user INDEX cli_iBufferActions;", &cli_iBufferActions);
- _pShell->DeclareSymbol("persistent user INDEX cli_iMaxBPS;", &cli_iMaxBPS);
- _pShell->DeclareSymbol("persistent user INDEX cli_iMinBPS;", &cli_iMinBPS);
- _pShell->DeclareSymbol("user FLOAT net_fLimitLatencySend;", &_pbsSend.pbs_fLatencyLimit);
- _pShell->DeclareSymbol("user FLOAT net_fLimitLatencyRecv;", &_pbsRecv.pbs_fLatencyLimit);
- _pShell->DeclareSymbol("user FLOAT net_fLatencyVariationSend;", &_pbsSend.pbs_fLatencyVariation);
- _pShell->DeclareSymbol("user FLOAT net_fLatencyVariationRecv;", &_pbsRecv.pbs_fLatencyVariation);
- _pShell->DeclareSymbol("user FLOAT net_fLimitBandwidthSend;", &_pbsSend.pbs_fBandwidthLimit);
- _pShell->DeclareSymbol("user FLOAT net_fLimitBandwidthRecv;", &_pbsRecv.pbs_fBandwidthLimit);
- _pShell->DeclareSymbol("user FLOAT net_fDropPackets;", &net_fDropPackets);
- _pShell->DeclareSymbol("persistent user INDEX net_iGraphBuffer;", &net_iGraphBuffer);
- _pShell->DeclareSymbol("user const INDEX precache_NONE;", &_precache_NONE);
- _pShell->DeclareSymbol("user const INDEX precache_SMART;", &_precache_SMART);
- _pShell->DeclareSymbol("user const INDEX precache_ALL;", &_precache_ALL);
- _pShell->DeclareSymbol("user const INDEX precache_PARANOIA;", &_precache_PARANOIA);
- _pShell->DeclareSymbol("persistent user INDEX gam_iPrecachePolicy;", &gam_iPrecachePolicy);
- _pShell->DeclareSymbol("user FLOAT phy_fCollisionCacheAhead;", &phy_fCollisionCacheAhead);
- _pShell->DeclareSymbol("user FLOAT phy_fCollisionCacheAround;", &phy_fCollisionCacheAround);
- _pShell->DeclareSymbol("persistent user INDEX inp_iKeyboardReadingMethod;", &inp_iKeyboardReadingMethod);
- _pShell->DeclareSymbol("persistent user INDEX inp_bAllowMouseAcceleration;", &inp_bAllowMouseAcceleration);
- _pShell->DeclareSymbol("persistent user FLOAT inp_fMouseSensitivity;", &inp_fMouseSensitivity);
- _pShell->DeclareSymbol("persistent user INDEX inp_bMousePrecision;", &inp_bMousePrecision);
- _pShell->DeclareSymbol("persistent user FLOAT inp_fMousePrecisionFactor;", &inp_fMousePrecisionFactor);
- _pShell->DeclareSymbol("persistent user FLOAT inp_fMousePrecisionThreshold;", &inp_fMousePrecisionThreshold);
- _pShell->DeclareSymbol("persistent user FLOAT inp_fMousePrecisionTimeout;", &inp_fMousePrecisionTimeout);
- _pShell->DeclareSymbol("persistent user INDEX inp_bInvertMouse;", &inp_bInvertMouse);
- _pShell->DeclareSymbol("persistent user INDEX inp_bFilterMouse;", &inp_bFilterMouse);
- _pShell->DeclareSymbol("persistent user INDEX inp_bAllowPrescan;", &inp_bAllowPrescan);
- _pShell->DeclareSymbol("persistent user INDEX inp_i2ndMousePort;", &inp_i2ndMousePort);
- _pShell->DeclareSymbol("persistent user INDEX inp_bInvert2ndMouse;", &inp_bInvert2ndMouse);
- _pShell->DeclareSymbol("persistent user INDEX inp_bFilter2ndMouse;", &inp_bFilter2ndMouse);
- _pShell->DeclareSymbol("persistent user FLOAT inp_f2ndMouseSensitivity;", &inp_f2ndMouseSensitivity);
- _pShell->DeclareSymbol("persistent user INDEX inp_b2ndMousePrecision;", &inp_b2ndMousePrecision);
- _pShell->DeclareSymbol("persistent user FLOAT inp_f2ndMousePrecisionFactor;", &inp_f2ndMousePrecisionFactor);
- _pShell->DeclareSymbol("persistent user FLOAT inp_f2ndMousePrecisionThreshold;", &inp_f2ndMousePrecisionThreshold);
- _pShell->DeclareSymbol("persistent user FLOAT inp_f2ndMousePrecisionTimeout;", &inp_f2ndMousePrecisionTimeout);
- _pShell->DeclareSymbol("persistent user INDEX inp_bMsgDebugger;", &inp_bMsgDebugger);
- _pShell->DeclareSymbol("persistent user INDEX inp_iMButton4Up;", &inp_iMButton4Up);
- _pShell->DeclareSymbol("persistent user INDEX inp_iMButton4Dn;", &inp_iMButton4Dn);
- _pShell->DeclareSymbol("persistent user INDEX inp_iMButton5Up;", &inp_iMButton5Up);
- _pShell->DeclareSymbol("persistent user INDEX inp_iMButton5Dn;", &inp_iMButton5Dn);
- _pShell->DeclareSymbol("persistent user INDEX inp_ctJoysticksAllowed;", &inp_ctJoysticksAllowed);
- _pShell->DeclareSymbol("persistent user INDEX inp_bForceJoystickPolling;", &inp_bForceJoystickPolling);
- _pShell->DeclareSymbol("persistent user INDEX inp_bAutoDisableJoysticks;", &inp_bAutoDisableJoysticks);
- _pShell->DeclareSymbol("persistent user INDEX wed_bUseGenericTextureReplacement;", &wed_bUseGenericTextureReplacement);
- _pShell->DeclareSymbol("persistent user CTString ga_strServer;", &ga_strServer);
- _pShell->DeclareSymbol("persistent user CTString ga_strMSLegacy;", &ga_strMSLegacy);
- _pShell->DeclareSymbol("persistent user INDEX ga_bMSLegacy;", &ga_bMSLegacy);
- _pShell->DeclareSymbol("INDEX pwoCurrentWorld;", &_pwoCurrentWorld);
- }
- /*
- * Add the timer handler.
- */
- void CNetworkLibrary::AddTimerHandler(void)
- {
- if (this==NULL || _bTempNetwork) {
- return; // this can happen during NET_MakeDefaultState_t()!
- }
- _pTimer->AddHandler(&ga_thTimerHandler);
- }
- /*
- * Remove the timer handler.
- */
- void CNetworkLibrary::RemoveTimerHandler(void)
- {
- if (this==NULL || _bTempNetwork) {
- return; // this can happen during NET_MakeDefaultState_t()!
- }
- _pTimer->RemHandler(&ga_thTimerHandler);
- }
- /*
- // set settings to prediction-off
- void AdjustPredictionOff(void)
- {
- if (!cli_bAutoAdjustSettings) {
- return;
- }
- if (cli_bPrediction) {
- CPrintF("AutoAdjustment: prediction off, buffer 1\n");
- }
- cli_bPrediction = 0;
- cli_iBufferActions = 1;
- }
- // set settings to prediction-on
- void AdjustPredictionOn(void)
- {
- if (!cli_bAutoAdjustSettings) {
- return;
- }
- if (!cli_bPrediction) {
- CPrintF("AutoAdjustment: prediction on, buffer 3\n");
- }
- cli_bPrediction = 1;
- cli_iBufferActions = 3;
- }
- // automatically adjust network settings
- void CNetworkLibrary::AutoAdjustSettings(void)
- {
- // if server and not debugging prediction
- if (IsServer() && !cli_bPredictIfServer) {
- // just turn it all off
- AdjustPredictionOff();
- return;
- }
- static TIME _tmLastTimeNoPredictionSteps = -1;
- // get network lag in terms of ticks
- INDEX ctLagTicks = ga_sesSessionState.GetPredictionStepsCount()-(cli_iBufferActions-1);
- // if no significant lag
- if (ctLagTicks<=1) {
- // set settings to prediction-off
- AdjustPredictionOff();
- _tmLastTimeNoPredictionSteps = _pTimer->CurrentTick();
- // if there is lag now for some time
- } else if (_pTimer->CurrentTick()-_tmLastTimeNoPredictionSteps>=cli_tmAutoAdjustThreshold) {
- // set settings to prediction-on
- AdjustPredictionOn();
- }
- }
- */
- /*
- * Start a peer-to-peer game session.
- *
- * remember to keep this routine up to date with CNetworkLibrary::Read()
- */
- void CNetworkLibrary::StartPeerToPeer_t(const CTString &strSessionName,
- const CTFileName &fnmWorld, ULONG ulSpawnFlags,
- INDEX ctMaxPlayers, BOOL bWaitAllPlayers,
- void *pvSessionProperties) // throw char *
- {
- // mute all sounds
- _pSound->Mute();
- // go on
- CPrintF( TRANS("Starting session: '%s'\n"), strSessionName);
- CPrintF( TRANS(" level: '%s'\n"), (const char*) fnmWorld);
- CPrintF( TRANS(" spawnflags: %08x\n"), ulSpawnFlags);
- CPrintF( TRANS(" max players: %d\n"), ctMaxPlayers);
- CPrintF( TRANS(" waiting: %d\n"), bWaitAllPlayers);
- CGatherCRC gc;
- // if starting in network
- if (_cmiComm.IsNetworkEnabled()) {
- CPrintF( TRANS(" network is on\n"));
- // start gathering CRCs
- InitCRCGather();
- // make default state data for creating deltas
- MakeDefaultState(fnmWorld, ulSpawnFlags, pvSessionProperties);
- } else {
- CPrintF( TRANS(" network is off\n"));
- }
- // access to the list of handlers must be locked
- CTSingleLock slHooks(&_pTimer->tm_csHooks, TRUE);
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- ga_ctTimersPending = -1; // disable timer pending
- ga_strSessionName = strSessionName;
- ga_bLocalPause = FALSE;
- ga_sesSessionState.ses_iLevel+=1;
- ga_sesSessionState.ses_ulSpawnFlags = ulSpawnFlags;
- ga_sesSessionState.ses_tmSyncCheckFrequency = ser_tmSyncCheckFrequency;
- ga_sesSessionState.ses_iExtensiveSyncCheck = ser_iExtensiveSyncCheck;
- memcpy(ga_aubProperties, pvSessionProperties, NET_MAXSESSIONPROPERTIES);
- // remember the world filename
- ga_fnmWorld = fnmWorld;
- ga_fnmNextLevel = CTString("");
- try {
- // load the world
- _pTimer->SetCurrentTick(0.0f); // must have timer at 0 while loading
- ga_World.Load_t(fnmWorld);
- // delete all entities that don't fit given spawn flags
- ga_World.FilterEntitiesBySpawnFlags(ga_sesSessionState.ses_ulSpawnFlags);
- } catch(char *) {
- ga_fnmWorld = CTString("");
- _cmiComm.Server_Close();
- _cmiComm.Client_Close();
- throw;
- }
- // remember the world pointer
- _pShell->SetINDEX("pwoCurrentWorld", (INDEX)&ga_World);
- SetProgressDescription(TRANS("starting server"));
- CallProgressHook_t(0.0f);
- // initialize server
- try {
- ga_srvServer.Start_t();
- } catch (char *) {
- ga_World.DeletePredictors();
- ga_World.Clear();
- throw;
- }
- ga_IsServer = TRUE;
- ga_ulDemoMinorVersion = _SE_BUILD_MINOR;
- CallProgressHook_t(1.0f);
- // start the timer loop
- AddTimerHandler();
- SetProgressDescription(TRANS("starting session"));
- CallProgressHook_t(0.0f);
- // initialize session state
- try {
- ga_sesSessionState.Start_t(-1);
- } catch (char *strError) {
- (void)strError;
- RemoveTimerHandler();
- ga_srvServer.Stop();
- ga_World.DeletePredictors();
- ga_World.Clear();
- throw;
- }
- CallProgressHook_t(1.0f);
- // remember maximum number of players
- ga_sesSessionState.ses_ctMaxPlayers = ctMaxPlayers;
- ga_sesSessionState.ses_bWaitAllPlayers = bWaitAllPlayers;
- // time speed is normal by default
- ga_sesSessionState.ses_fRealTimeFactor = 1.0f;
- // eventually cache all shadowmaps in world (memory eater!)
- if( shd_bCacheAll) ga_World.wo_baBrushes.CacheAllShadowmaps();
- // flush stale caches
- FreeUnusedStock();
- // mark that pretouching is required
- _bNeedPretouch = TRUE;
- // start timer sync anew
- ga_ctTimersPending = 0;
- FinishCRCGather();
- CPrintF( TRANS(" started.\n"));
- }
- /*
- * Save the game.
- */
- void CNetworkLibrary::Save_t(const CTFileName &fnmGame) // throw char *
- {
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- // must be server
- if (!ga_IsServer) {
- throw TRANS("Cannot save game - not a server!\n");
- }
- // create the file
- CTFileStream strmFile;
- strmFile.Create_t(fnmGame);
- // write game to stream
- strmFile.WriteID_t("GAME");
- ga_sesSessionState.Write_t(&strmFile);
- strmFile.WriteID_t("GEND"); // game end
- }
- /*
- * Load the game.
- *
- * remember to keep this routine up to date with CNetworkLibrary::StartPeerToPeer()
- */
- void CNetworkLibrary::Load_t(const CTFileName &fnmGame) // throw char *
- {
- // mute all sounds
- _pSound->Mute();
- // access to the list of handlers must be locked
- CTSingleLock slHooks(&_pTimer->tm_csHooks, TRUE);
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- ga_ctTimersPending = -1; // disable timer pending
- CGatherCRC gc;
- ga_bLocalPause = FALSE;
- // open the file
- CTFileStream strmFile;
- strmFile.Open_t(fnmGame);
- // if starting in network
- if (_cmiComm.IsNetworkEnabled()) {
- // start gathering CRCs
- InitCRCGather();
- }
- // initialize server
- ga_srvServer.Start_t();
- ga_IsServer = TRUE;
- ga_ulDemoMinorVersion = _SE_BUILD_MINOR;
- ga_fnmNextLevel = CTString("");
- memset(ga_aubProperties, 0, NET_MAXSESSIONPROPERTIES);
- // start the timer loop
- AddTimerHandler();
- strmFile.ExpectID_t("GAME");
- // read session state
- try {
- ga_sesSessionState.Start_t(-1);
- ga_sesSessionState.Read_t(&strmFile);
- // if starting in network
- if (_cmiComm.IsNetworkEnabled()) {
- // make default state data for creating deltas
- MakeDefaultState(ga_fnmWorld, ga_sesSessionState.ses_ulSpawnFlags,
- ga_aubProperties);
- }
- // players will be connected later
- ga_sesSessionState.ses_apltPlayers.Clear();
- ga_sesSessionState.ses_apltPlayers.New(NET_MAXGAMEPLAYERS);
- strmFile.ExpectID_t("GEND"); // game end
- } catch(char *) {
- RemoveTimerHandler();
- ga_srvServer.Stop();
- ga_IsServer = FALSE;
- throw;
- }
- // set time and pause for server from the saved game
- ga_sesSessionState.ses_iLevel+=1;
- ga_srvServer.srv_tmLastProcessedTick = ga_sesSessionState.ses_tmLastProcessedTick;
- ga_srvServer.srv_iLastProcessedSequence = ga_sesSessionState.ses_iLastProcessedSequence;
- ga_srvServer.srv_bPause = ga_sesSessionState.ses_bPause;
- ga_srvServer.srv_bGameFinished = ga_sesSessionState.ses_bGameFinished;
- ga_sesSessionState.ses_tmPredictionHeadTick = ga_sesSessionState.ses_tmLastProcessedTick;
- // start sending stream to local state
- ga_srvServer.srv_assoSessions[0].sso_bSendStream = TRUE;
- ga_srvServer.srv_assoSessions[0].sso_iLastSentSequence = ga_srvServer.srv_iLastProcessedSequence;
- // eventually cache all shadowmaps in world (memory eater!)
- if( shd_bCacheAll) ga_World.wo_baBrushes.CacheAllShadowmaps();
- // flush stale caches
- FreeUnusedStock();
- // mark that pretouching is required
- _bNeedPretouch = TRUE;
- // start timer sync anew
- ga_ctTimersPending = 0;
- FinishCRCGather();
- }
- /*
- * Save a debugging game.
- */
- void CNetworkLibrary::DebugSave(void)
- {
- // try to save game
- try {
- Save_t(CTString("Save\\Debug.sav"));
- // if not successful
- } catch (char *strError){
- FatalError("Cannot save debug game:\n%s", strError);
- }
- }
- /* Enumerate existing sessions. */
- void CNetworkLibrary::EnumSessions(BOOL bInternet)
- {
- // clear old list
- FORDELETELIST(CNetworkSession, ns_lnNode, ga_lhEnumeratedSessions, itns) {
- delete &*itns;
- }
- // make sure network is on
- if (!_cmiComm.IsNetworkEnabled()) {
- _cmiComm.PrepareForUse(/*network*/TRUE, /*client*/FALSE); // have to enumerate as server
- }
- // request enumeration
- GameAgent_EnumTrigger(bInternet);
- }
- /*
- * Join a running multi-player game.
- */
- void CNetworkLibrary::JoinSession_t(const CNetworkSession &nsSesssion, INDEX ctLocalPlayers) // throw char *
- {
- // mute all sounds
- _pSound->Mute();
- // report session addres
- CPrintF( TRANS("Joining session at: '%s'\n"), nsSesssion.ns_strAddress);
- ga_bLocalPause = FALSE;
- // access to the list of handlers must be locked
- CTSingleLock slHooks(&_pTimer->tm_csHooks, TRUE);
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- ga_ctTimersPending = -1; // disable timer pending
- // start gathering CRCs
- CGatherCRC gc;
- InitCRCGather();
- // set session name and server address
- ga_strSessionName = nsSesssion.ns_strSession;
- ga_strServerAddress = nsSesssion.ns_strAddress;
- ga_fnmNextLevel = CTString("");
- ga_fnmWorld = CTString("");
- memset(ga_aubProperties, 0, NET_MAXSESSIONPROPERTIES);
- ga_IsServer = FALSE;
- ga_ulDemoMinorVersion = _SE_BUILD_MINOR;
- // start the timer loop
- AddTimerHandler();
- SetProgressDescription(TRANS("connecting"));
- CallProgressHook_t(0.0f);
- // initialize session state
- try {
- ga_sesSessionState.Start_t(ctLocalPlayers);
- } catch(char *) {
- RemoveTimerHandler();
- throw;
- }
- // remember the world pointer
- _pShell->SetINDEX("pwoCurrentWorld", (INDEX)&ga_World);
- // eventually cache all shadowmaps in world (memory eater!)
- if( shd_bCacheAll) ga_World.wo_baBrushes.CacheAllShadowmaps();
- // flush stale caches
- FreeUnusedStock();
- // mark that pretouching is required
- _bNeedPretouch = TRUE;
- // run main loop to let session state process messages from server
- MainLoop();
- // start timer sync anew
- ga_ctTimersPending = 0;
- // initially auto adjust prediction on
- // AdjustPredictionOn();
- CPrintF(" joined\n");
- }
- /* Start playing a demo. */
- void CNetworkLibrary::StartDemoPlay_t(const CTFileName &fnDemo) // throw char *
- {
- // mute all sounds
- _pSound->Mute();
- // access to the list of handlers must be locked
- CTSingleLock slHooks(&_pTimer->tm_csHooks, TRUE);
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- ga_ctTimersPending = -1; // disable timer pending
- ga_bLocalPause = FALSE;
- // open the file
- ga_strmDemoPlay.Open_t(fnDemo);
- // remember that playing demo
- ga_bDemoPlay = TRUE;
- ga_bDemoPlayFinished = FALSE;
- // create session name from demo name
- CTString strSessionName = CTString("Demo: ")+fnDemo;
- ga_strSessionName = strSessionName;
- ga_IsServer = FALSE;
- // start the timer loop
- AddTimerHandler();
- // initialize server
- try {
- // read initial info to stream
- ga_strmDemoPlay.ExpectID_t("DEMO");
- if (ga_strmDemoPlay.PeekID_t()==CChunkID("MVER")) {
- ga_strmDemoPlay.ExpectID_t("MVER");
- ga_strmDemoPlay>>ga_ulDemoMinorVersion;
- } else {
- ga_ulDemoMinorVersion = 2;
- }
- ga_sesSessionState.Read_t(&ga_strmDemoPlay);
- } catch(char *) {
- RemoveTimerHandler();
- ga_strmDemoPlay.Close();
- ga_bDemoPlay = FALSE;
- throw;
- }
- // eventually cache all shadowmaps in world (memory eater!)
- if( shd_bCacheAll) ga_World.wo_baBrushes.CacheAllShadowmaps();
- // flush stale caches
- FreeUnusedStock();
- // mark that pretouching is required
- _bNeedPretouch = TRUE;
- // remember the world pointer
- _pShell->SetINDEX("pwoCurrentWorld", (INDEX)&ga_World);
- // demo synchronization starts at the beginning initially
- ga_fDemoTimer = 0.0f;
- ga_tvDemoTimerLastTime = _pTimer->GetHighPrecisionTimer();
- // demo sync seuqence must be initialized first time in ProcessGameStream()
- ga_sesSessionState.ses_tmLastDemoSequence = -1.0f;
- // run main loop to let server process messages from host
- MainLoop();
- // start timer sync anew
- ga_ctTimersPending = 0;
- }
- /* Test if currently playing demo has finished. */
- BOOL CNetworkLibrary::IsDemoPlayFinished(void)
- {
- return ga_bDemoPlay && ga_bDemoPlayFinished;
- }
- /* Test if currently playing a demo. */
- BOOL CNetworkLibrary::IsPlayingDemo(void)
- {
- return ga_bDemoPlay;
- }
- /* Test if currently recording a demo. */
- BOOL CNetworkLibrary::IsRecordingDemo(void)
- {
- return ga_bDemoRec;
- }
- BOOL CNetworkLibrary::IsNetworkEnabled(void)
- {
- return _cmiComm.IsNetworkEnabled();
- }
- // pause/unpause game
- void CNetworkLibrary::TogglePause(void)
- {
- ga_sesSessionState.ses_bWantPause = !ga_sesSessionState.ses_bWantPause;
- }
- // test if game is paused
- BOOL CNetworkLibrary::IsPaused(void)
- {
- if (this==NULL || _bTempNetwork) {
- return TRUE; // this can happen during NET_MakeDefaultState_t()!
- }
- return ga_sesSessionState.ses_bPause;
- }
- // test if having connnection problems (not getting messages from server regulary)
- BOOL CNetworkLibrary::IsConnectionStable(void)
- {
- // if network is not enabled
- if (!_cmiComm.IsNetworkEnabled()) {
- // it is always stable
- return TRUE;
- }
- // check when last message was received.
- return (_pTimer->GetHighPrecisionTimer()-ga_sesSessionState.ses_tvMessageReceived).GetSeconds()<net_tmProblemsTimeout;
- }
- // test if completely disconnected and why
- BOOL CNetworkLibrary::IsDisconnected(void)
- {
- return ga_sesSessionState.ses_strDisconnected!="";
- }
- const CTString &CNetworkLibrary::WhyDisconnected(void)
- {
- return ga_sesSessionState.ses_strDisconnected;
- }
- // set/get server side pause (for single player only)
- void CNetworkLibrary::SetLocalPause(BOOL bPause)
- {
- ga_bLocalPause = bPause;
- }
- BOOL CNetworkLibrary::GetLocalPause(void)
- {
- if (this==NULL || _bTempNetwork) {
- return TRUE; // this can happen during NET_MakeDefaultState_t()!
- }
- return ga_bLocalPause;
- }
- // get server/client name and address
- void CNetworkLibrary::GetHostName(CTString &strName, CTString &strAddress)
- {
- _cmiComm.GetHostName(strName, strAddress);
- }
- // mark that the game has finished -- called from AI
- void CNetworkLibrary::SetGameFinished(void)
- {
- ga_sesSessionState.ses_bGameFinished = TRUE;
- if (IsServer()) {
- ga_srvServer.srv_bGameFinished = TRUE;
- }
- }
- BOOL CNetworkLibrary::IsGameFinished(void)
- {
- return ga_sesSessionState.ses_bGameFinished;
- }
- // manipulation with realtime factor for slower/faster time -- called from AI
- void CNetworkLibrary::SetRealTimeFactor(FLOAT fSpeed)
- {
- ga_sesSessionState.ses_fRealTimeFactor = fSpeed;
- }
- FLOAT CNetworkLibrary::GetRealTimeFactor(void)
- {
- return ga_sesSessionState.ses_fRealTimeFactor;
- }
- // test if game is waiting for more players to connect
- BOOL CNetworkLibrary::IsWaitingForPlayers(void)
- {
- // if game mode does not include waiting for players
- if (!ga_sesSessionState.ses_bWaitAllPlayers) {
- // not waiting
- return FALSE;
- }
- // if server
- if (IsServer()) {
- // check number of players on server
- return ga_srvServer.GetPlayersCount()<ga_sesSessionState.ses_ctMaxPlayers;
- // if not server
- } else {
- // check number of players in session
- return ga_sesSessionState.GetPlayersCount()<ga_sesSessionState.ses_ctMaxPlayers;
- }
- }
- // test if game is waiting for server
- BOOL CNetworkLibrary::IsWaitingForServer(void)
- {
- return ga_sesSessionState.ses_bWaitingForServer;
- }
- // test if game session is currently doing prediction
- BOOL CNetworkLibrary::IsPredicting(void)
- {
- return ga_sesSessionState.ses_bPredicting;
- }
- /*
- * Stop currently running game.
- */
- void CNetworkLibrary::StopGame(void)
- {
- // mute all sounds
- _pSound->Mute();
- CPrintF( TRANS("stopping game.\n"));
- // access to the list of handlers must be locked
- CTSingleLock slHooks(&_pTimer->tm_csHooks, TRUE);
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- ga_ctTimersPending = -1; // disable timer pending
- // stop demo recording if active
- StopDemoRec();
- // if playing demo
- if (ga_bDemoPlay) {
- // close the demo file
- ga_strmDemoPlay.Close();
- // remember that not playing demo
- ga_bDemoPlay = FALSE;
- ga_bDemoPlayFinished = FALSE;
- }
- // stop the timer loop
- RemoveTimerHandler();
- // stop session
- ga_sesSessionState.Stop();
- // stop server
- if (ga_IsServer) {
- ga_srvServer.Stop();
- ga_IsServer = FALSE;
- }
- ga_ulDemoMinorVersion = _SE_BUILD_MINOR;
- ga_strSessionName = "";
- ga_World.DeletePredictors();
- ga_World.Clear();
- // free default state if existing
- if (ga_pubDefaultState!=NULL) {
- FreeMemory(ga_pubDefaultState);
- ga_pubDefaultState = NULL;
- ga_slDefaultStateSize = 0;
- memset(ga_aubDefaultProperties, 0, sizeof(ga_aubDefaultProperties));
- }
- if (ga_pubCRCList!=NULL) {
- FreeMemory(ga_pubCRCList);
- ga_pubCRCList = NULL;
- ga_slCRCList = 0;
- }
- ga_aplsPlayers.Clear();
- ga_aplsPlayers.New(NET_MAXLOCALPLAYERS);
- // remember the world pointer
- _pShell->SetINDEX("pwoCurrentWorld", (INDEX)NULL);
- // rewind the timer
- _pTimer->SetCurrentTick(0.0f);
- }
- // initiate level change
- void CNetworkLibrary::ChangeLevel(
- const CTFileName &fnmNextLevel, BOOL bRemember, INDEX iUserData)
- {
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- ASSERT(!IsPredicting());
- // if not currently changing
- if (_lphCurrent==LCP_NOCHANGE) {
- // initiate change
- ga_fnmNextLevel = fnmNextLevel;
- ga_bNextRemember = bRemember;
- ga_iNextLevelUserData = iUserData;
- _lphCurrent = LCP_INITIATED;
- }
- }
- // really do the level change
- void CNetworkLibrary::ChangeLevel_internal(void)
- {
- CSetFPUPrecision FPUPrecision(FPT_24BIT);
- extern BOOL _bReinitEntitiesWhileCopying;
- _bReinitEntitiesWhileCopying = FALSE;
- // mute all sounds
- _pSound->Mute();
- // cancel all predictions before crossing levels
- _pNetwork->ga_World.DeletePredictors();
- // find all entities that are to cross to next level
- CEntitySelection senToCross;
- {FOREACHINDYNAMICCONTAINER(ga_World.wo_cenEntities, CEntity, iten) {
- if (iten->en_ulFlags&ENF_CROSSESLEVELS) {
- senToCross.Select(*iten);
- }
- }}
- // copy them to a temporary world
- CWorld wldTemp;
- CEntitySelection senInTemp;
- wldTemp.CopyEntities(ga_World, senToCross,
- senInTemp, CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0)));
- // remember characters for all player targets and disable them
- CPlayerCharacter apc[NET_MAXGAMEPLAYERS];
- BOOL abWasActive[NET_MAXGAMEPLAYERS];
- CPlayerAction apaActions[NET_MAXGAMEPLAYERS][2];
- {for(INDEX i=0; i<NET_MAXGAMEPLAYERS; i++) {
- CPlayerTarget &plt = ga_sesSessionState.ses_apltPlayers[i];
- abWasActive[i] = plt.IsActive();
- if (plt.IsActive()) {
- apc[i] = plt.plt_penPlayerEntity->en_pcCharacter;
- apaActions[i][0] = plt.plt_paLastAction;
- apaActions[i][1] = plt.plt_paPreLastAction;
- plt.plt_penPlayerEntity = NULL;
- plt.Deactivate();
- }
- }}
- // destroy all entities that will cross level
- ga_World.DestroyEntities(senToCross);
- // if should remember old levels
- if (ga_bNextRemember) {
- // remember current level
- ga_sesSessionState.RememberCurrentLevel(ga_fnmWorld);
- }
- CGatherCRC gc;
- // if starting in network
- if (_cmiComm.IsNetworkEnabled()) {
- // start gathering CRCs
- InitCRCGather();
- // make default state data for creating deltas
- MakeDefaultState(ga_fnmNextLevel, ga_sesSessionState.ses_ulSpawnFlags, ga_aubProperties);
- }
- // if the new level is not remembered
- if (ga_sesSessionState.FindRememberedLevel(ga_fnmNextLevel)==NULL) {
- // remember original world filename
- CTFileName fnmOldWorld = ga_fnmWorld;
- // try to
- try {
- // load the new world
- _pTimer->SetCurrentTick(0.0f); // must have timer at 0 while loading
- ga_World.Load_t(ga_fnmNextLevel);
- // delete all entities that don't fit given spawn flags
- ga_World.FilterEntitiesBySpawnFlags(ga_sesSessionState.ses_ulSpawnFlags);
- // if failed
- } catch(char *strError) {
- // report error
- CPrintF(TRANS("Cannot change level:\n%s"), strError);
- // try to
- try {
- // load the old world
- ga_fnmNextLevel = fnmOldWorld;
- ga_World.Load_t(ga_fnmNextLevel);
- // delete all entities that don't fit given spawn flags
- ga_World.FilterEntitiesBySpawnFlags(ga_sesSessionState.ses_ulSpawnFlags);
- // if that fails
- } catch (char *strError2) {
- // fatal error
- FatalError(
- TRANS("Cannot change level because:\n%s\n"
- "and cannot go back to original one because:\n%s"), strError, strError2);
- return;
- }
- }
- // remember the world filename
- ga_fnmWorld = ga_fnmNextLevel;
- // remember the world pointer
- _pShell->SetINDEX("pwoCurrentWorld", (INDEX)&ga_World);
- // if there is remembered level
- } else {
- // restore it
- ga_sesSessionState.RestoreOldLevel(ga_fnmNextLevel);
- }
- // set overdue timers in just loaded world to be due in current time
- ga_World.AdjustLateTimers(ga_sesSessionState.ses_tmLastProcessedTick);
- // copy entities from temporary world into new one
- CEntitySelection senCrossed;
- ga_World.CopyEntities(wldTemp, senInTemp,
- senCrossed, CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0)));
- // restore pointers to entities for all active player targets
- {for(INDEX i=0; i<NET_MAXGAMEPLAYERS; i++) {
- CPlayerTarget &plt = ga_sesSessionState.ses_apltPlayers[i];
- if (abWasActive[i]) {
- plt.Activate();
- plt.plt_paLastAction = apaActions[i][0];
- plt.plt_paPreLastAction = apaActions[i][1];
- plt.AttachEntity(ga_World.FindEntityWithCharacter(apc[i]));
- }
- }}
- _bReinitEntitiesWhileCopying = TRUE;
- // if should not remember old levels
- if (!ga_bNextRemember) {
- // clear them all
- ga_sesSessionState.ForgetOldLevels();
- }
- // if not server
- if (!IsServer()) {
- // start waiting for server
- ga_sesSessionState.ses_bWaitingForServer = TRUE;
- // if server
- } else {
- // flush sync check buffer
- ga_srvServer.srv_ascChecks.Clear();
- // for each client
- {for( INDEX iClient=0; iClient<NET_MAXGAMECOMPUTERS; iClient++) {
- CSessionSocket &sso = ga_srvServer.srv_assoSessions[iClient];
- // reset message timer
- sso.sso_tvMessageReceived = -1I64;
- // reset sync timer
- sso.sso_tmLastSyncReceived = -1.0f;
- }}
- // for each player
- {for( INDEX iPlayer=0; iPlayer<NET_MAXGAMEPLAYERS; iPlayer++) {
- CPlayerBuffer &plb = _pNetwork->ga_srvServer.srv_aplbPlayers[iPlayer];
- if (plb.plb_Active) {
- // add one dummy action
- CPlayerAction pa;
- pa.Clear();
- pa.pa_aRotation = plb.plb_paLastAction.pa_aRotation;
- pa.pa_aViewRotation = plb.plb_paLastAction.pa_aViewRotation;
- plb.plb_abReceived.AddAction(pa);
- }
- }}
- }
- ga_sesSessionState.ses_iLevel+=1;
- // flush stale caches
- FreeUnusedStock();
- // mark that pretouching is required
- _bNeedPretouch = TRUE;
- // start timer sync anew
- ga_ctTimersPending = 0;
- FinishCRCGather();
- }
- /* Start recording a demo. */
- void CNetworkLibrary::StartDemoRec_t(const CTFileName &fnDemo) // throw char *
- {
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- // if already recording
- if (ga_bDemoRec) {
- // error
- throw TRANS("Already recording a demo!");
- }
- // create the file
- ga_strmDemoRec.Create_t(fnDemo);
- // write initial info to stream
- ga_strmDemoRec.WriteID_t("DEMO");
- ga_strmDemoRec.WriteID_t("MVER");
- ga_strmDemoRec<<ULONG(_SE_BUILD_MINOR);
- ga_sesSessionState.Write_t(&ga_strmDemoRec);
- // remember that recording demo
- ga_bDemoRec = TRUE;
- }
- /* Stop recording a demo. */
- void CNetworkLibrary::StopDemoRec(void)
- {
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- // if not recording
- if (!ga_bDemoRec) {
- // do nothing
- return;
- }
- // write terminal info to the stream
- ga_strmDemoRec.WriteID_t("DEND"); // game end
- // close the file
- ga_strmDemoRec.Close();
- // remember that not recording demo
- ga_bDemoRec = FALSE;
- }
- // split the rcon response string into lines and send one by one to the client
- static void SendAdminResponse(ULONG ulAdr, UWORD uwPort, ULONG ulCode, const CTString &strResponse)
- {
- CTString str = strResponse;
- INDEX iLineCt = 0;
- while (str!="") {
- CTString strLine = str;
- strLine.OnlyFirstLine();
- str.RemovePrefix(strLine);
- str.DeleteChar(0);
- if (strLine.Length()>0) {
- CNetworkMessage nm(MSG_EXTRA);
- nm<<CTString(0, "log %u %d %s\n", ulCode, iLineCt++, strLine);
- _pNetwork->SendBroadcast(nm, ulAdr, uwPort);
- }
- }
- }
- /*
- * Main loop.
- */
- void CNetworkLibrary::MainLoop(void)
- {
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- // update network state variable (to control usage of some cvars that cannot be altered in mulit-player mode)
- _bMultiPlayer = (_pNetwork->ga_sesSessionState.GetPlayersCount() > 1);
- // if should change world
- if (_lphCurrent==LCP_SIGNALLED) {
- // really do the level change here
- ChangeLevel_internal();
- _lphCurrent=LCP_CHANGED;
- }
- if (_bStartDemoRecordingNextTime) {
- _bStartDemoRecordingNextTime = 0.0f;
- if (!ga_bDemoRec) {
- try {
- CTString strName;
- strName.PrintF("Temp\\Recorded%02d.dem", (INDEX)dem_iRecordedNumber);
- StartDemoRec_t(strName);
- dem_iRecordedNumber+=1;
- } catch(char *strError) {
- CPrintF(TRANS("Demo recording error: %s\n"), strError);
- }
- }
- }
- if (_bStopDemoRecordingNextTime) {
- _bStopDemoRecordingNextTime = 0.0f;
- if (ga_bDemoRec) {
- StopDemoRec();
- }
- }
- _sfStats.StartTimer(CStatForm::STI_MAINLOOP);
- _pfNetworkProfile.StartTimer(CNetworkProfile::PTI_MAINLOOP);
- // handle messages for session state
- if (!ga_bDemoPlay) {
- if (_cmiComm.Client_Update() == FALSE) {
- ga_sesSessionState.Stop();
- return;
- }
- ga_sesSessionState.SessionStateLoop();
- if (_cmiComm.Client_Update() == FALSE) {
- ga_sesSessionState.Stop();
- return;
- }
- }
- // if this is server computer
- if (ga_IsServer) {
- // handle server messages
- _cmiComm.Server_Update();
- }
- // let server process game stream
- TIME tmBefore = _pTimer->GetRealTimeTick();
- _pTimer->SetLerp(0.0f);
- /*
- // automatically adjust network settings
- if (cli_bAutoAdjustSettings) {
- AutoAdjustSettings();
- }
- */
- // determine whether to use prediction
- BOOL bUsePrediction = cli_bPrediction && (cli_bPredictIfServer || !IsServer());
- _bPredictionActive = bUsePrediction; // memeber this for other misc code
- // mark all predictable entities that will be predicted using user-set criterions
- if (bUsePrediction) {
- ga_World.MarkForPrediction();
- }
- // process the game stream coming from the server
- ga_sesSessionState.ProcessGameStream();
- // flush actions that don't need to be predicted any more
- ga_sesSessionState.FlushProcessedPredictions();
- // process additional prediction steps
- if (bUsePrediction) {
- // mark all new predictable entities that might have been spawned
- ga_World.UnmarkForPrediction();
- ga_World.MarkForPrediction();
- ga_sesSessionState.ProcessPrediction();
- // unmark all predictable entities marked for prediction
- ga_World.UnmarkForPrediction();
- }
- ga_sesSessionState.ses_tmLastUpdated = _pTimer->GetRealTimeTick();
- TIME tmAfter = _pTimer->GetRealTimeTick();
- ga_sesSessionState.ses_bKeepingUpWithTime = (tmAfter-tmBefore)<=_pTimer->TickQuantum*2.01f;
- CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
- // set the lerping factor for current frame
- if (!ga_bDemoPlay) {
- ga_sesSessionState.SetLerpFactor(tvNow);
- } else {
- ga_sesSessionState.SetLerpFactor(CTimerValue(ga_fDemoTimer));
- }
- // if playing a demo
- if (ga_bDemoPlay) {
- // if synchronizing by real time
- if (ga_fDemoSyncRate==DEMOSYNC_REALTIME) {
- // if server is keeping up
- if (ga_sesSessionState.ses_bKeepingUpWithTime) {
- // add passed time with slow/fast factor
- ga_fDemoTimer += FLOAT((tvNow-ga_tvDemoTimerLastTime).GetSeconds())
- *ga_fDemoRealTimeFactor*ga_sesSessionState.ses_fRealTimeFactor;
- }
- // if synchronizing is stopped
- } else if (ga_fDemoSyncRate==DEMOSYNC_STOP) {
- // don't step
- NOTHING;
- // if synchronizing by given steps
- } else {
- // just add the step
- ga_fDemoTimer += 1.0f/ga_fDemoSyncRate;
- }
- }
- // remember the demo timer
- ga_tvDemoTimerLastTime = tvNow;
- // if network
- if (_cmiComm.IsNetworkEnabled()) {
- // do services for gameagent querying
- GameAgent_ServerUpdate();
- // _cmiComm.Broadcast_Update();
- // repeat
- FOREVER {
- CNetworkMessage nmReceived;
- // _cmiComm.Broadcast_Update();
- ULONG ulFrom;
- UWORD uwPort;
- BOOL bHasMsg = ReceiveBroadcast(nmReceived, ulFrom, uwPort);
- // if there are no more messages
- if (!bHasMsg) {
- // finish
- break;
- }
- // if this message is not valid rcon message
- if (nmReceived.GetType()!=MSG_EXTRA) {
- // skip it
- continue;
- }
- // get the string from the message
- CTString strMsg;
- nmReceived>>strMsg;
- // if this is server
- if (IsServer()) {
- // accept requests
- if (!strMsg.RemovePrefix("rcmd ")) {
- continue;
- }
- ULONG ulCode;
- char strPass[80];
- char strCmd[256];
- strMsg.ScanF("%u \"%80[^\"]\"%256[^\n]", &ulCode, strPass, strCmd);
- CTString strAdr = AddressToString(ulFrom);
- if (net_strAdminPassword=="" || net_strAdminPassword!=strPass) {
- CPrintF(TRANS("Server: Client '%s', Wrong password for remote administration.\n"), (const char*)strAdr);
- continue;
- }
- CPrintF(TRANS("Server: Client '%s', Admin cmd: %s\n"), (const char*)strAdr, strCmd);
- con_bCapture = TRUE;
- con_strCapture = "";
- _pShell->Execute(CTString(strCmd)+";");
- CTString strResponse = CTString(">")+strCmd+"\n"+con_strCapture;
- SendAdminResponse(ulFrom, uwPort, ulCode, strResponse);
- con_bCapture = FALSE;
- con_strCapture = "";
- }
- }
- }
- _pfNetworkProfile.StopTimer(CNetworkProfile::PTI_MAINLOOP);
- _sfStats.StopTimer(CStatForm::STI_MAINLOOP);
- }
- // make actions packet for local players and send to server
- void CNetworkLibrary::SendActionsToServer(void)
- {
- // make the packet
- CNetworkMessage nmAction(MSG_ACTION);
- // for all local players on this machine
- for(INDEX ipls=0; ipls<ga_aplsPlayers.Count(); ipls++) {
- CPlayerSource &pls = ga_aplsPlayers[ipls];
- // create action packet if the player exists
- pls.WriteActionPacket(nmAction);
- }
- // send the packet
- SendToServer(nmAction);
- }
- /*
- * Client loop.
- */
- void CNetworkLibrary::TimerLoop(void)
- {
- if (this==NULL || _bTempNetwork) {
- return; // this can happen during NET_MakeDefaultState_t()!
- }
- _pfNetworkProfile.StartTimer(CNetworkProfile::PTI_TIMERLOOP);
- // count number of timer interrupts that happened
- if (ga_ctTimersPending>=0) {
- ga_ctTimersPending++;
- }
- // if can synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, FALSE);
- // initially, no timer functions needed
- INDEX ct = 0;
- // if timer exactness level is full
- if (net_iExactTimer==2) {
- // lock network mutex
- slNetwork.Lock();
- // execute exactly one
- ct = 1;
- // if timer exactness level is partial
- } else if (net_iExactTimer==1) {
- // if network mutex can be locked
- if (slNetwork.TryToLock()) {
- // execute all pending
- ct = ga_ctTimersPending;
- }
- // if timer exactness level is low
- } else if (net_iExactTimer==0) {
- // if network mutex can be locked
- if (slNetwork.TryToLock()) {
- // execute exactly one
- ct = 1;
- }
- }
- // for each pending interrupt
- while(ct) {
- ct--;
- ga_ctTimersPending--;
- // if not disconnected
- // if (!IsDisconnected()) {
- if (_cmiComm.cci_bClientInitialized) {
- // make actions packet for all local players and send to server
- SendActionsToServer();
- _cmiComm.Client_Update();
- }
- // if this is server computer
- if (ga_IsServer) {
- // handle server messages
- _cmiComm.Server_Update();
- ga_srvServer.ServerLoop();
- _cmiComm.Server_Update();
- }
- }
- _pfNetworkProfile.StopTimer(CNetworkProfile::PTI_TIMERLOOP);
- }
- /* Get player entity for a given local player. */
- CEntity *CNetworkLibrary::GetLocalPlayerEntity(CPlayerSource *ppls)
- {
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- // get the index of the player target in game state
- INDEX iPlayerTarget = ppls->pls_Index;
- // if player is not added
- if (iPlayerTarget<0) {
- // no entity
- return NULL;
- // if player is added
- } else {
- // get the entity from player target
- CPlayerTarget &plt = ga_sesSessionState.ses_apltPlayers[iPlayerTarget];
- CPlayerEntity *pen = plt.plt_penPlayerEntity;
- return pen;
- }
- }
- /* Get player entity for a given player by name. */
- CEntity *CNetworkLibrary::GetPlayerEntityByName(const CTString &strName)
- {
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- // for each player in game
- CStaticArray<CPlayerTarget> &aplt = ga_sesSessionState.ses_apltPlayers;
- for(INDEX iplt = 0; iplt<aplt.Count(); iplt++) {
- // if it is active and has that name
- if (aplt[iplt].IsActive()
- &&aplt[iplt].plt_penPlayerEntity->en_pcCharacter.GetName()==strName) {
- // return it
- return aplt[iplt].plt_penPlayerEntity;
- }
- }
- // else not found
- return NULL;
- }
- /* Get number of entities with given name. */
- INDEX CNetworkLibrary::GetNumberOfEntitiesWithName(const CTString &strName)
- {
- INDEX ctEntities = 0;
- {FOREACHINDYNAMICCONTAINER(ga_World.wo_cenEntities, CEntity, iten) {
- if (iten->GetName()==strName) {
- ctEntities++;
- }
- }}
- return ctEntities;
- }
- /* Get n-th entity with given name. */
- CEntity *CNetworkLibrary::GetEntityWithName(const CTString &strName, INDEX iEntityWithThatName)
- {
- INDEX ctEntities = 0;
- CEntity *pen = NULL;
- {FOREACHINDYNAMICCONTAINER(ga_World.wo_cenEntities, CEntity, iten) {
- if (iten->GetName()==strName) {
- pen = iten;
- if (ctEntities==iEntityWithThatName) {
- break;
- }
- ctEntities++;
- }
- }}
- return pen;
- }
- /* Test if a given player is local to this computer. */
- BOOL CNetworkLibrary::IsPlayerLocal(CEntity *pen)
- {
- return GetPlayerSource(pen)!=NULL;
- }
- // get player source for a given player if it is local to this computer
- CPlayerSource *CNetworkLibrary::GetPlayerSource(CEntity *pen)
- {
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- // for all local player on this machine
- {FOREACHINSTATICARRAY(ga_aplsPlayers, CPlayerSource, itpls) {
- // get the index of the player target in game state
- INDEX iPlayerTarget = itpls->pls_Index;
- // if player is added
- if (iPlayerTarget>=0) {
- // get the player target
- CPlayerTarget &plt = ga_sesSessionState.ses_apltPlayers[iPlayerTarget];
- // if it is that one
- if (plt.plt_penPlayerEntity == pen) {
- // return it
- return itpls;
- }
- }
- }}
- // if not found, it is not local
- return NULL;
- }
- // get game time in currently running game
- TIME CNetworkLibrary::GetGameTime(void)
- {
- return ga_sesSessionState.ses_tmLastProcessedTick;
- }
- /*
- * Add a new client to game.
- */
- CPlayerSource *CNetworkLibrary::AddPlayer_t(CPlayerCharacter &pcCharacter) // throw char *
- {
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- CPrintF( TRANS("Adding player: '%s'\n"), pcCharacter.GetNameForPrinting());
- // for all local clients on this machine
- FOREACHINSTATICARRAY(ga_aplsPlayers, CPlayerSource, itcls) {
- // if client is not active
- if (!itcls->IsActive()) {
- // activate it
- itcls->Start_t(pcCharacter);
- CPrintF( TRANS(" done.\n"));
- return &itcls.Current();
- }
- }
- // number of local clients is limited with NET_MAXLOCALCLIENTS
- ASSERTALWAYS("Adding too much local clients!");
- throw TRANS("Cannot add more local clients");
- return NULL;
- }
- /* Get session properties for current game. */
- void *CNetworkLibrary::GetSessionProperties(void)
- {
- // synchronize access to network
- CTSingleLock slNetwork(&ga_csNetwork, TRUE);
- return ga_aubProperties;
- }
- /* Send chat message from some players to some other players. */
- void CNetworkLibrary::SendChat(ULONG ulFrom, ULONG ulTo, const CTString &strMessage)
- {
- // if the string is too long and we're not server
- if (strlen(strMessage)>256 && !_pNetwork->IsServer()) {
- // refuse it
- return;
- }
- // just make the message and send it to server
- CNetworkMessage nm(MSG_CHAT_IN);
- nm<<ulFrom;
- nm<<ulTo;
- nm<<strMessage;
- SendToServer(nm);
- }
- // save current version of engine
- void CNetworkLibrary::WriteVersion_t(CTStream &strm)
- {
- strm.WriteID_t("BUIV"); // build version
- strm<<INDEX(_SE_BUILD_MAJOR);
- }
- // load version of engine saved in file and check against current
- void CNetworkLibrary::CheckVersion_t(CTStream &strm, BOOL bAllowReinit, BOOL &bNeedsReinit)
- {
- // if not saved
- if (strm.PeekID_t()!=CChunkID("BUIV")) { // build version
- // behave as if everything is ok (for old versions)
- bNeedsReinit = FALSE;
- return;
- }
- strm.ExpectID_t("BUIV"); // build version
- // read the saved one
- INDEX iSaved;
- strm>>iSaved;
- // get current one
- INDEX iCurrent = _SE_BUILD_MAJOR;
- // if current version is an internal build
- if (iCurrent==0) {
- // it is never forced to reinit
- bNeedsReinit = FALSE;
- return;
- }
- // if current version is older than the saved one
- if (iCurrent<iSaved) {
- // it cannot be reinitialized
- ThrowF_t(TRANS("File '%s' was saved by a newer version of engine, it cannot be loaded"),
- strm.GetDescription());
- return;
- }
- // if current version is same as the saved one
- if (iCurrent==iSaved) {
- // all ok
- bNeedsReinit = FALSE;
- return;
- }
- // if current version is newer than the saved one
- if (iCurrent>iSaved) {
- // it should be reinitialized
- bNeedsReinit = TRUE;
- // if it may not be reinitialized
- if (!bAllowReinit) {
- ThrowF_t(TRANS("File '%s' was saved by an older version of engine, it cannot be loaded"),
- strm.GetDescription());
- }
- return;
- }
- // this should not happen
- ASSERT(FALSE);
- bNeedsReinit = FALSE;
- return;
- }
- // add a value to the netgraph
- void CNetworkLibrary::AddNetGraphValue(enum NetGraphEntryType nget, FLOAT fLatency)
- {
- net_iGraphBuffer = Clamp(net_iGraphBuffer, INDEX(20), INDEX(1000));
- // make sure the netgraph has wanted number of values
- if (ga_angeNetGraph.Count()!=net_iGraphBuffer) {
- ga_angeNetGraph.Clear();
- ga_angeNetGraph.New(net_iGraphBuffer);
- memset(&ga_angeNetGraph[0], 0, ga_angeNetGraph.Count()*sizeof(ga_angeNetGraph[0]));
- }
- // scroll the values in the netgraph by one value
- memmove(&ga_angeNetGraph[1], &ga_angeNetGraph[0], (ga_angeNetGraph.Count()-1)*sizeof(ga_angeNetGraph[0]));
- // add the new value
- ga_angeNetGraph[0].nge_ngetType = nget;
- ga_angeNetGraph[0].nge_fLatency = fLatency;
- }
- // make default state for a network game
- extern void NET_MakeDefaultState_t(
- const CTFileName &fnmWorld, ULONG ulSpawnFlags, void *pvSessionProperties,
- CTStream &strmState) // throw char *
- {
- // mute all sounds
- _pSound->Mute();
- // first off - mark that we are in the special state
- _bTempNetwork = TRUE;
- // make sure that current network object gets locked
- CTSingleLock slNetwork(&_pNetwork->ga_csNetwork, TRUE);
- // remember original network pointer and clear it
- CNetworkLibrary *pnlOld = _pNetwork;
- _pNetwork = NULL;
- // try to
- try {
- // create new network object
- CNetworkLibrary *pNewNet = new CNetworkLibrary;
- // it must have new mutex index since both will be locked
- pNewNet->ga_csNetwork.cs_iIndex = 2001;
- // lock the new network access
- CTSingleLock slNetwork(&pNewNet->ga_csNetwork, TRUE);
- pNewNet->ga_ctTimersPending = -1; // disable timer pending
- // only after locking it, we may allow the new pointer to be remembered
- // otherwise, the other thread can jump in between
- _pNetwork = pNewNet;
- // remember settings
- _pNetwork->ga_sesSessionState.ses_ulSpawnFlags = ulSpawnFlags;
- _pNetwork->ga_sesSessionState.ses_tmSyncCheckFrequency = 10.0f;
- _pNetwork->ga_sesSessionState.ses_iExtensiveSyncCheck = 0;
- memcpy(_pNetwork->ga_aubProperties, pvSessionProperties, NET_MAXSESSIONPROPERTIES);
- _pNetwork->ga_fnmWorld = fnmWorld;
- _pNetwork->ga_fnmNextLevel = CTString("");
- try {
- // load the world
- _pTimer->SetCurrentTick(0.0f); // must have timer at 0 while loading
- _pNetwork->ga_World.Load_t(fnmWorld);
- // delete all entities that don't fit given spawn flags
- _pNetwork->ga_World.FilterEntitiesBySpawnFlags(_pNetwork->ga_sesSessionState.ses_ulSpawnFlags);
- } catch(char *) {
- throw;
- }
- // remember the world filename
- _pNetwork->ga_fnmWorld = fnmWorld;
- _pNetwork->ga_fnmNextLevel = CTString("");
- // remember the world pointer
- _pShell->SetINDEX("pwoCurrentWorld", (INDEX)&_pNetwork->ga_World);
- // reset random number generator
- _pNetwork->ga_sesSessionState.ResetRND();
- // flush stale caches
- FreeUnusedStock();
- // warmup the world
- _pNetwork->ga_sesSessionState.WarmUpWorld();
- // save the session state to the stream
- _pNetwork->ga_sesSessionState.Write_t(&strmState);
- // if any error
- } catch (char *) {
- // restore original network pointer
- CNetworkLibrary *pnlTemp = _pNetwork;
- _pNetwork = pnlOld;
- if (pnlTemp!=NULL) {
- delete pnlTemp;
- }
- _bTempNetwork = FALSE;
- // fail
- throw;
- }
- // restore original network pointer
- CNetworkLibrary *pnlTemp = _pNetwork;
- _pNetwork = pnlOld;
- delete pnlTemp;
- _bTempNetwork = FALSE;
- }
- // handle broadcast messages (server enumeration)
- void CNetworkLibrary::GameInactive(void)
- {
- GameAgent_EnumUpdate();
- // if no network
- if (!_cmiComm.IsNetworkEnabled()) {
- // do not handle
- return;
- }
- // _cmiComm.Broadcast_Update();
- // repeat
- FOREVER {
- CNetworkMessage nmReceived;
- // _cmiComm.Broadcast_Update();
- ULONG ulFrom;
- UWORD uwPort;
- BOOL bHasMsg = ReceiveBroadcast(nmReceived, ulFrom, uwPort);
- // if there are no more messages
- if (!bHasMsg) {
- // finish
- break;
- }
- /* This is handled by GameAgent.
- // if requesting enumeration and this is server and enumeration is allowed
- if (nmReceived.GetType()==MSG_REQ_ENUMSERVERS
- && IsServer()
- && (ser_bEnumeration && ga_sesSessionState.ses_ctMaxPlayers>1)) {
- // create response
- CNetworkMessage nmEnum(MSG_SERVERINFO);
- nmEnum<<ga_strSessionName;
- nmEnum<<ga_World.wo_strName;
- nmEnum<<ga_srvServer.GetPlayersCount();
- nmEnum<<ga_sesSessionState.ses_ctMaxPlayers;
- // send it
- SendBroadcast(nmEnum, ulFrom, uwPort);
- // if receiving enumeration
- } else if (nmReceived.GetType()==MSG_SERVERINFO) {
- // create a new session
- CNetworkSession &ns = *new CNetworkSession;
- ga_lhEnumeratedSessions.AddTail(ns.ns_lnNode);
- // read it
- nmReceived>>ns.ns_strSession;
- nmReceived>>ns.ns_strWorld;
- nmReceived>>ns.ns_ctPlayers;
- nmReceived>>ns.ns_ctMaxPlayers;
- ns.ns_strAddress = AddressToString(ulFrom);
- }*/
- }
- }
- void CNetworkLibrary::InitCRCGather(void)
- {
- CRCT_ResetActiveList();
- CRCT_bGatherCRCs = TRUE;
- CRCT_AddFile_t(CTString("Classes\\Player.ecl"));
- }
- // finish gathering of file CRCs to CRC table (call for server only!)
- void CNetworkLibrary::FinishCRCGather(void)
- {
- try {
- // make the list
- CTMemoryStream strmCRC;
- CRCT_MakeFileList_t(strmCRC);
- // remember it
- strmCRC.SetPos_t(0);
- ga_slCRCList = strmCRC.GetStreamSize();
- ga_pubCRCList = (UBYTE*)AllocMemory(ga_slCRCList);
- strmCRC.Read_t(ga_pubCRCList, ga_slCRCList);
- // remember its CRC
- strmCRC.SetPos_t(0);
- ga_ulCRC = CRCT_MakeCRCForFiles_t(strmCRC);
- } catch (char *strError) {
- CPrintF(TRANS("Warning, cannot get CRCs: %s\n"), strError);
- }
- }
- // make default state data for creating deltas
- void CNetworkLibrary::MakeDefaultState(const CTFileName &fnmWorld,
- ULONG ulSpawnFlags, void *pvSessionProperties)
- {
- // prepare file or memory stream for state
- CTFileStream strmStateFile; CTMemoryStream strmStateMem;
- CTStream *pstrmState;
- extern INDEX net_bDumpConnectionInfo;
- if (net_bDumpConnectionInfo) {
- strmStateFile.Create_t(CTString("Temp\\DefaultState.bin"));
- pstrmState = &strmStateFile;
- } else {
- pstrmState = &strmStateMem;
- }
- // make default state for a network game
- NET_MakeDefaultState_t(fnmWorld, ulSpawnFlags, pvSessionProperties, *pstrmState);
- pstrmState->SetPos_t(0);
- ga_slDefaultStateSize = pstrmState->GetStreamSize();
- ga_pubDefaultState = (UBYTE*)AllocMemory(ga_slDefaultStateSize);
- pstrmState->Read_t(ga_pubDefaultState, ga_slDefaultStateSize);
- memcpy(ga_aubDefaultProperties, pvSessionProperties, sizeof(ga_aubDefaultProperties));
- }
|