Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1583 lines
39 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // replayserver.cpp: implementation of the CReplayServer class.
  9. //
  10. //////////////////////////////////////////////////////////////////////
  11. #if defined( REPLAY_ENABLED )
  12. #include <server_class.h>
  13. #include <inetmessage.h>
  14. #include <tier0/vprof.h>
  15. #include <keyvalues.h>
  16. #include <edict.h>
  17. #include <eiface.h>
  18. #include <PlayerState.h>
  19. #include <ireplaydirector.h>
  20. #include <time.h>
  21. #include "replayserver.h"
  22. #include "sv_client.h"
  23. #include "replayclient.h"
  24. #include "server.h"
  25. #include "sv_main.h"
  26. #include "framesnapshot.h"
  27. #include "networkstringtable.h"
  28. #include "cmodel_engine.h"
  29. #include "dt_recv_eng.h"
  30. #include "cdll_engine_int.h"
  31. #include "GameEventManager.h"
  32. #include "host.h"
  33. #include "dt_common_eng.h"
  34. #include "baseautocompletefilelist.h"
  35. #include "sv_steamauth.h"
  36. #include "con_nprint.h"
  37. #include "tier0/icommandline.h"
  38. #include "client_class.h"
  39. // memdbgon must be the last include file in a .cpp file!!!
  40. #include "tier0/memdbgon.h"
  41. extern CNetworkStringTableContainer *networkStringTableContainerClient;
  42. //////////////////////////////////////////////////////////////////////
  43. // Construction/Destruction
  44. //////////////////////////////////////////////////////////////////////
  45. CReplayServer *replay = NULL;
  46. static void replay_title_changed_f( IConVar *var, const char *pOldString, float flOldValue )
  47. {
  48. if ( replay && replay->IsActive() )
  49. {
  50. replay->BroadcastLocalTitle();
  51. }
  52. }
  53. static void replay_name_changed_f( IConVar *var, const char *pOldValue, float flOldValue )
  54. {
  55. Steam3Server().NotifyOfServerNameChange();
  56. }
  57. static ConVar replay_maxclients( "replay_maxclients", "128", 0, "Maximum client number on Replay server.",
  58. true, 0, true, 255 );
  59. ConVar replay_autorecord( "replay_autorecord", "1", 0, "Automatically records all games as Replay demos." );
  60. ConVar replay_name( "replay_name", "Replay", 0, "Replay host name", replay_name_changed_f );
  61. static ConVar replay_password( "replay_password", "", FCVAR_NOTIFY | FCVAR_PROTECTED | FCVAR_DONTRECORD, "Replay password for all clients" );
  62. static ConVar replay_overridemaster( "replay_overridemaster", "0", 0, "Overrides the Replay master root address." );
  63. static ConVar replay_dispatchmode( "replay_dispatchmode", "1", 0, "Dispatch clients to relay proxies: 0=never, 1=if appropriate, 2=always" );
  64. ConVar replay_transmitall( "replay_transmitall", "1", FCVAR_REPLICATED, "Transmit all entities (not only director view)" );
  65. ConVar replay_debug( "replay_debug", "0", 0, "Replay debug info." );
  66. ConVar replay_title( "replay_title", "Replay", 0, "Set title for Replay spectator UI", replay_title_changed_f );
  67. static ConVar replay_deltacache( "replay_deltacache", "2", 0, "Enable delta entity bit stream cache" );
  68. static ConVar replay_relayvoice( "replay_relayvoice", "1", 0, "Relay voice data: 0=off, 1=on" );
  69. ConVar replay_movielength( "replay_movielength", "60", FCVAR_REPLICATED | FCVAR_DONTRECORD, "Replay movie length in seconds" );
  70. ConVar replay_demolifespan( "replay_demolifespan", "5", FCVAR_REPLICATED | FCVAR_DONTRECORD, "The number of days allowed to pass before cleaning up replay demos.", true, 1, true, 30 );
  71. ConVar replay_cleanup_time( "replay_cleanup_time", "1", FCVAR_REPLICATED | FCVAR_DONTRECORD, "The Replay system will periodically remove stale (never downloaded) .dem files from disk. This variable represents the "
  72. "amount of time (in hours) between each cleanup.", true, 1, true, 24 );
  73. CReplayDeltaEntityCache::CReplayDeltaEntityCache()
  74. {
  75. Q_memset( m_Cache, 0, sizeof(m_Cache) );
  76. m_nTick = 0;
  77. m_nMaxEntities = 0;
  78. m_nCacheSize = 0;
  79. }
  80. CReplayDeltaEntityCache::~CReplayDeltaEntityCache()
  81. {
  82. Flush();
  83. }
  84. void CReplayDeltaEntityCache::Flush()
  85. {
  86. if ( m_nMaxEntities != 0 )
  87. {
  88. // at least one entity was set
  89. for ( int i=0; i<m_nMaxEntities; i++ )
  90. {
  91. if ( m_Cache[i] != NULL )
  92. {
  93. free( m_Cache[i] );
  94. m_Cache[i] = NULL;
  95. }
  96. }
  97. m_nMaxEntities = 0;
  98. }
  99. m_nCacheSize = 0;
  100. }
  101. void CReplayDeltaEntityCache::SetTick( int nTick, int nMaxEntities )
  102. {
  103. if ( nTick == m_nTick )
  104. return;
  105. Flush();
  106. m_nCacheSize = replay_deltacache.GetInt() * 1024;
  107. if ( m_nCacheSize <= 0 )
  108. return;
  109. m_nMaxEntities = MIN(nMaxEntities,MAX_EDICTS);
  110. m_nTick = nTick;
  111. }
  112. unsigned char* CReplayDeltaEntityCache::FindDeltaBits( int nEntityIndex, int nDeltaTick, int &nBits )
  113. {
  114. nBits = -1;
  115. if ( nEntityIndex < 0 || nEntityIndex >= m_nMaxEntities )
  116. return NULL;
  117. DeltaEntityEntry_s *pEntry = m_Cache[nEntityIndex];
  118. while ( pEntry )
  119. {
  120. if ( pEntry->nDeltaTick == nDeltaTick )
  121. {
  122. nBits = pEntry->nBits;
  123. return (unsigned char*)(pEntry) + sizeof(DeltaEntityEntry_s);
  124. }
  125. else
  126. {
  127. // keep searching entry list
  128. pEntry = pEntry->pNext;
  129. }
  130. }
  131. return NULL;
  132. }
  133. void CReplayDeltaEntityCache::AddDeltaBits( int nEntityIndex, int nDeltaTick, int nBits, bf_write *pBuffer )
  134. {
  135. if ( nEntityIndex < 0 || nEntityIndex >= m_nMaxEntities || m_nCacheSize <= 0 )
  136. return;
  137. int nBufferSize = PAD_NUMBER( Bits2Bytes(nBits), 4);
  138. DeltaEntityEntry_s *pEntry = m_Cache[nEntityIndex];
  139. if ( pEntry == NULL )
  140. {
  141. if ( (int)(nBufferSize+sizeof(DeltaEntityEntry_s)) > m_nCacheSize )
  142. return; // way too big, don't even create an entry
  143. pEntry = m_Cache[nEntityIndex] = (DeltaEntityEntry_s *) malloc( m_nCacheSize );
  144. }
  145. else
  146. {
  147. char *pEnd = (char*)(pEntry) + m_nCacheSize; // end marker
  148. while( pEntry->pNext )
  149. {
  150. pEntry = pEntry->pNext;
  151. }
  152. int entrySize = sizeof(DeltaEntityEntry_s) + PAD_NUMBER( Bits2Bytes(pEntry->nBits), 4);
  153. DeltaEntityEntry_s *pNew = (DeltaEntityEntry_s*)((char*)(pEntry) + entrySize);
  154. if ( ((char*)(pNew) + sizeof(DeltaEntityEntry_s) + nBufferSize) > pEnd )
  155. return; // data wouldn't fit into cache anymore, don't add new entries
  156. pEntry->pNext = pEntry = pNew;
  157. }
  158. pEntry->pNext = NULL; // link to next
  159. pEntry->nDeltaTick = nDeltaTick;
  160. pEntry->nBits = nBits;
  161. if ( nBits > 0 )
  162. {
  163. bf_read inBuffer;
  164. inBuffer.StartReading( pBuffer->GetData(), pBuffer->m_nDataBytes, pBuffer->GetNumBitsWritten() );
  165. bf_write outBuffer( (char*)(pEntry) + sizeof(DeltaEntityEntry_s), nBufferSize );
  166. outBuffer.WriteBitsFromBuffer( &inBuffer, nBits );
  167. }
  168. }
  169. static RecvTable* FindRecvTable( const char *pName, RecvTable **pRecvTables, int nRecvTables )
  170. {
  171. for ( int i=0; i< nRecvTables; i++ )
  172. {
  173. if ( !Q_strcmp( pName, pRecvTables[i]->GetName() ) )
  174. return pRecvTables[i];
  175. }
  176. return NULL;
  177. }
  178. static RecvTable* AddRecvTableR( SendTable *sendt, RecvTable **pRecvTables, int &nRecvTables )
  179. {
  180. RecvTable *recvt = FindRecvTable( sendt->m_pNetTableName, pRecvTables, nRecvTables );
  181. if ( recvt )
  182. return recvt; // already in list
  183. if ( sendt->m_nProps > 0 )
  184. {
  185. RecvProp *receiveProps = new RecvProp[sendt->m_nProps];
  186. for ( int i=0; i < sendt->m_nProps; i++ )
  187. {
  188. // copy property data
  189. SendProp * sp = sendt->GetProp( i );
  190. RecvProp * rp = &receiveProps[i];
  191. rp->m_pVarName = sp->m_pVarName;
  192. rp->m_RecvType = sp->m_Type;
  193. if ( sp->IsExcludeProp() )
  194. {
  195. // if prop is excluded, give different name
  196. rp->m_pVarName = "IsExcludedProp";
  197. }
  198. if ( sp->IsInsideArray() )
  199. {
  200. rp->SetInsideArray();
  201. rp->m_pVarName = "InsideArrayProp"; // give different name
  202. }
  203. if ( sp->GetType() == DPT_Array )
  204. {
  205. Assert ( sp->GetArrayProp() == sendt->GetProp( i-1 ) );
  206. Assert( receiveProps[i-1].IsInsideArray() );
  207. rp->SetArrayProp( &receiveProps[i-1] );
  208. rp->InitArray( sp->m_nElements, sp->m_ElementStride );
  209. }
  210. if ( sp->GetType() == DPT_DataTable )
  211. {
  212. // recursive create
  213. Assert ( sp->GetDataTable() );
  214. RecvTable *subTable = AddRecvTableR( sp->GetDataTable(), pRecvTables, nRecvTables );
  215. rp->SetDataTable( subTable );
  216. }
  217. }
  218. recvt = new RecvTable( receiveProps, sendt->m_nProps, sendt->m_pNetTableName );
  219. }
  220. else
  221. {
  222. // table with no properties
  223. recvt = new RecvTable( NULL, 0, sendt->m_pNetTableName );
  224. }
  225. pRecvTables[nRecvTables] = recvt;
  226. nRecvTables++;
  227. return recvt;
  228. }
  229. void CReplayServer::FreeClientRecvTables()
  230. {
  231. for ( int i=0; i< m_nRecvTables; i++ )
  232. {
  233. RecvTable *rt = m_pRecvTables[i];
  234. // delete recv table props
  235. if ( rt->m_pProps )
  236. {
  237. Assert( rt->m_nProps > 0 );
  238. delete [] rt->m_pProps;
  239. }
  240. // delete the table itself
  241. delete rt;
  242. }
  243. Q_memset( m_pRecvTables, 0, sizeof( m_pRecvTables ) );
  244. m_nRecvTables = 0;
  245. }
  246. // creates client receive tables from server send tables
  247. void CReplayServer::InitClientRecvTables()
  248. {
  249. ServerClass* pCur = NULL;
  250. if ( ClientDLL_GetAllClasses() != NULL )
  251. return; //already initialized
  252. // first create all SendTables
  253. for ( pCur = serverGameDLL->GetAllServerClasses(); pCur; pCur=pCur->m_pNext )
  254. {
  255. // create receive table from send table.
  256. AddRecvTableR( pCur->m_pTable, m_pRecvTables, m_nRecvTables );
  257. ErrorIfNot(
  258. m_nRecvTables < ARRAYSIZE( m_pRecvTables ),
  259. ("AddRecvTableR: overflowed MAX_DATATABLES")
  260. );
  261. }
  262. // now register client classes
  263. for ( pCur = serverGameDLL->GetAllServerClasses(); pCur; pCur=pCur->m_pNext )
  264. {
  265. ErrorIfNot(
  266. m_nRecvTables < ARRAYSIZE( m_pRecvTables ),
  267. ("ClientDLL_InitRecvTableMgr: overflowed MAX_DATATABLES")
  268. );
  269. // find top receive table for class
  270. RecvTable * recvt = FindRecvTable( pCur->m_pTable->GetName(), m_pRecvTables, m_nRecvTables );
  271. Assert ( recvt );
  272. // register class, constructor addes clientClass to g_pClientClassHead list
  273. ClientClass * clientclass = new ClientClass( pCur->m_pNetworkName, NULL, NULL, recvt );
  274. if ( !clientclass )
  275. {
  276. Msg("REPLAY_InitRecvTableMgr: failed to allocate client class %s.\n", pCur->m_pNetworkName );
  277. return;
  278. }
  279. }
  280. RecvTable_Init( m_pRecvTables, m_nRecvTables );
  281. }
  282. CReplayFrame::CReplayFrame()
  283. {
  284. }
  285. CReplayFrame::~CReplayFrame()
  286. {
  287. FreeBuffers();
  288. }
  289. void CReplayFrame::Reset( void )
  290. {
  291. for ( int i=0; i<REPLAY_BUFFER_MAX; i++ )
  292. {
  293. m_Messages[i].Reset();
  294. }
  295. }
  296. bool CReplayFrame::HasData( void )
  297. {
  298. for ( int i=0; i<REPLAY_BUFFER_MAX; i++ )
  299. {
  300. if ( m_Messages[i].GetNumBitsWritten() > 0 )
  301. return true;
  302. }
  303. return false;
  304. }
  305. void CReplayFrame::CopyReplayData( CReplayFrame &frame )
  306. {
  307. // copy reliable messages
  308. int bits = frame.m_Messages[REPLAY_BUFFER_RELIABLE].GetNumBitsWritten();
  309. if ( bits > 0 )
  310. {
  311. int bytes = PAD_NUMBER( Bits2Bytes(bits), 4 );
  312. m_Messages[REPLAY_BUFFER_RELIABLE].StartWriting( new char[ bytes ], bytes, bits );
  313. Q_memcpy( m_Messages[REPLAY_BUFFER_RELIABLE].GetBasePointer(), frame.m_Messages[REPLAY_BUFFER_RELIABLE].GetBasePointer(), bytes );
  314. }
  315. // copy unreliable messages
  316. bits = frame.m_Messages[REPLAY_BUFFER_UNRELIABLE].GetNumBitsWritten();
  317. bits += frame.m_Messages[REPLAY_BUFFER_TEMPENTS].GetNumBitsWritten();
  318. bits += frame.m_Messages[REPLAY_BUFFER_SOUNDS].GetNumBitsWritten();
  319. if ( replay_relayvoice.GetBool() )
  320. bits += frame.m_Messages[REPLAY_BUFFER_VOICE].GetNumBitsWritten();
  321. if ( bits > 0 )
  322. {
  323. // collapse all unreliable buffers in one
  324. int bytes = PAD_NUMBER( Bits2Bytes(bits), 4 );
  325. m_Messages[REPLAY_BUFFER_UNRELIABLE].StartWriting( new char[ bytes ], bytes );
  326. m_Messages[REPLAY_BUFFER_UNRELIABLE].WriteBits( frame.m_Messages[REPLAY_BUFFER_UNRELIABLE].GetData(), frame.m_Messages[REPLAY_BUFFER_UNRELIABLE].GetNumBitsWritten() );
  327. m_Messages[REPLAY_BUFFER_UNRELIABLE].WriteBits( frame.m_Messages[REPLAY_BUFFER_TEMPENTS].GetData(), frame.m_Messages[REPLAY_BUFFER_TEMPENTS].GetNumBitsWritten() );
  328. m_Messages[REPLAY_BUFFER_UNRELIABLE].WriteBits( frame.m_Messages[REPLAY_BUFFER_SOUNDS].GetData(), frame.m_Messages[REPLAY_BUFFER_SOUNDS].GetNumBitsWritten() );
  329. if ( replay_relayvoice.GetBool() )
  330. m_Messages[REPLAY_BUFFER_UNRELIABLE].WriteBits( frame.m_Messages[REPLAY_BUFFER_VOICE].GetData(), frame.m_Messages[REPLAY_BUFFER_VOICE].GetNumBitsWritten() );
  331. }
  332. }
  333. void CReplayFrame::AllocBuffers( void )
  334. {
  335. // allocate buffers for input frame
  336. for ( int i=0; i < REPLAY_BUFFER_MAX; i++ )
  337. {
  338. Assert( m_Messages[i].GetBasePointer() == NULL );
  339. m_Messages[i].StartWriting( new char[NET_MAX_PAYLOAD], NET_MAX_PAYLOAD);
  340. }
  341. }
  342. void CReplayFrame::FreeBuffers( void )
  343. {
  344. for ( int i=0; i<REPLAY_BUFFER_MAX; i++ )
  345. {
  346. bf_write &msg = m_Messages[i];
  347. if ( msg.GetBasePointer() )
  348. {
  349. delete[] msg.GetBasePointer();
  350. msg.StartWriting( NULL, 0 );
  351. }
  352. }
  353. }
  354. CReplayServer::CReplayServer()
  355. : m_DemoRecorder( this )
  356. {
  357. m_flTickInterval = 0.03;
  358. m_MasterClient = NULL;
  359. m_Server = NULL;
  360. m_Director = NULL;
  361. m_nFirstTick = -1;
  362. m_nLastTick = 0;
  363. m_CurrentFrame = NULL;
  364. m_nViewEntity = 0;
  365. m_nPlayerSlot = 0;
  366. m_bSignonState = false;
  367. m_flStartTime = 0;
  368. m_flFPS = 0;
  369. m_nGameServerMaxClients = 0;
  370. m_fNextSendUpdateTime = 0;
  371. Q_memset( m_pRecvTables, 0, sizeof( m_pRecvTables ) );
  372. m_nRecvTables = 0;
  373. m_vPVSOrigin.Init();
  374. m_nStartTick = 0;
  375. m_bPlayingBack = false;
  376. m_bPlaybackPaused = false;
  377. m_flPlaybackRateModifier = 0;
  378. m_nSkipToTick = 0;
  379. m_bMasterOnlyMode = false;
  380. m_nGlobalSlots = 0;
  381. m_nGlobalClients = 0;
  382. m_nGlobalProxies = 0;
  383. m_vecClientsDownloading.ClearAll();
  384. }
  385. CReplayServer::~CReplayServer()
  386. {
  387. if ( m_nRecvTables > 0 )
  388. {
  389. RecvTable_Term();
  390. FreeClientRecvTables();
  391. }
  392. // make sure everything was destroyed
  393. Assert( m_CurrentFrame == NULL );
  394. Assert( CountClientFrames() == 0 );
  395. }
  396. void CReplayServer::SetMaxClients( int number )
  397. {
  398. // allow max clients 0 in Replay
  399. m_nMaxclients = clamp( number, 0, ABSOLUTE_PLAYER_LIMIT );
  400. }
  401. void CReplayServer::StartMaster(CGameClient *client)
  402. {
  403. Clear(); // clear old settings & buffers
  404. if ( !client )
  405. {
  406. ConMsg("Replay client not found.\n");
  407. return;
  408. }
  409. m_Director = serverReplayDirector;
  410. if ( !m_Director )
  411. {
  412. ConMsg("Mod doesn't support Replay. No director module found.\n");
  413. return;
  414. }
  415. m_MasterClient = client;
  416. m_MasterClient->m_bIsHLTV = false;
  417. m_MasterClient->m_bIsReplay = true;
  418. // let game.dll know that we are the Replay client
  419. Assert( serverGameClients );
  420. CPlayerState *player = serverGameClients->GetPlayerState( m_MasterClient->edict );
  421. player->replay = true;
  422. m_Server = (CGameServer*)m_MasterClient->GetServer();
  423. // set default user settings
  424. m_MasterClient->m_ConVars->SetString( "name", replay_name.GetString() );
  425. m_MasterClient->m_ConVars->SetString( "cl_team", "1" );
  426. m_MasterClient->m_ConVars->SetString( "rate", va( "%d", DEFAULT_RATE ) );
  427. m_MasterClient->m_ConVars->SetString( "cl_updaterate", "32" );
  428. m_MasterClient->m_ConVars->SetString( "cl_interp_ratio", "1.0" );
  429. m_MasterClient->m_ConVars->SetString( "cl_predict", "0" );
  430. m_nViewEntity = m_MasterClient->GetPlayerSlot() + 1;
  431. m_nPlayerSlot = m_MasterClient->GetPlayerSlot();
  432. // copy server settings from m_Server
  433. m_nGameServerMaxClients = m_Server->GetMaxClients(); // maxclients is different on proxy (128)
  434. serverclasses = m_Server->serverclasses;
  435. serverclassbits = m_Server->serverclassbits;
  436. worldmapCRC = m_Server->worldmapCRC;
  437. clientDllCRC = m_Server->clientDllCRC;
  438. m_flTickInterval= m_Server->GetTickInterval();
  439. // allocate buffers for input frame
  440. m_ReplayFrame.AllocBuffers();
  441. InstallStringTables();
  442. // activate director in game.dll
  443. m_Director->SetReplayServer( this );
  444. // register as listener for mod specific events
  445. const char **modevents = m_Director->GetModEvents();
  446. int j = 0;
  447. while ( modevents[j] != NULL )
  448. {
  449. const char *eventname = modevents[j];
  450. CGameEventDescriptor *descriptor = g_GameEventManager.GetEventDescriptor( eventname );
  451. if ( descriptor )
  452. {
  453. g_GameEventManager.AddListener( this, descriptor, CGameEventManager::CLIENTSTUB );
  454. }
  455. else
  456. {
  457. DevMsg("CReplayServer::StartMaster: game event %s not found.\n", eventname );
  458. }
  459. j++;
  460. }
  461. // copy signon buffers
  462. m_Signon.StartWriting( m_Server->m_Signon.GetBasePointer(), m_Server->m_Signon.m_nDataBytes,
  463. m_Server->m_Signon.GetNumBitsWritten() );
  464. Q_strncpy( m_szMapname, m_Server->m_szMapname, sizeof(m_szMapname) );
  465. Q_strncpy( m_szSkyname, m_Server->m_szSkyname, sizeof(m_szSkyname) );
  466. NET_ListenSocket( m_Socket, true ); // activated Replay TCP socket
  467. m_MasterClient->ExecuteStringCommand( "spectate" ); // become a spectator
  468. m_MasterClient->UpdateUserSettings(); // make sure UserInfo is correct
  469. // hack reduce signontick by one to catch changes made in the current tick
  470. m_MasterClient->m_nSignonTick--;
  471. if ( m_bMasterOnlyMode )
  472. {
  473. // we allow only one client in master only mode
  474. replay_maxclients.SetValue( MIN(1,replay_maxclients.GetInt()) );
  475. }
  476. SetMaxClients( replay_maxclients.GetInt() );
  477. m_bSignonState = false; //master proxy is instantly connected
  478. m_nSpawnCount++;
  479. m_flStartTime = net_time;
  480. m_State = ss_active;
  481. // stop any previous recordings
  482. m_DemoRecorder.StopRecording();
  483. // start new recording if autorecord is enabled
  484. if ( replay_autorecord.GetBool() )
  485. {
  486. m_DemoRecorder.StartAutoRecording();
  487. }
  488. ReconnectClients();
  489. }
  490. void CReplayServer::StartDemo(const char *filename)
  491. {
  492. }
  493. bool CReplayServer::DispatchToRelay( CReplayClient *pClient )
  494. {
  495. if ( replay_dispatchmode.GetInt() <= DISPATCH_MODE_OFF )
  496. return false; // don't redirect
  497. CBaseClient *pBestProxy = NULL;
  498. float fBestRatio = 1.0f;
  499. // find best relay proxy
  500. for (int i=0; i < GetClientCount(); i++ )
  501. {
  502. CBaseClient *pProxy = m_Clients[ i ];
  503. // check all known proxies
  504. if ( !pProxy->IsConnected() || !pProxy->IsReplay() || (pClient == pProxy) )
  505. continue;
  506. int slots = Q_atoi( pProxy->GetUserSetting( "replay_slots" ) );
  507. int clients = Q_atoi( pProxy->GetUserSetting( "replay_clients" ) );
  508. // skip overloaded proxies or proxies with no slots at all
  509. if ( (clients > slots) || slots <= 0 )
  510. continue;
  511. // calc clients/slots ratio for this proxy
  512. float ratio = ((float)(clients))/((float)slots);
  513. if ( ratio < fBestRatio )
  514. {
  515. fBestRatio = ratio;
  516. pBestProxy = pProxy;
  517. }
  518. }
  519. if ( pBestProxy == NULL )
  520. {
  521. if ( replay_dispatchmode.GetInt() == DISPATCH_MODE_ALWAYS )
  522. {
  523. // we are in always forward mode, drop client if we can't forward it
  524. pClient->Disconnect("No Replay relay available");
  525. return true;
  526. }
  527. else
  528. {
  529. // just let client connect to this proxy
  530. return false;
  531. }
  532. }
  533. // check if client should stay on this relay server
  534. if ( (replay_dispatchmode.GetInt() == DISPATCH_MODE_AUTO) && (GetMaxClients() > 0) )
  535. {
  536. // ratio = clients/slots. give relay proxies 25% bonus
  537. float myRatio = ((float)GetNumClients()/(float)GetMaxClients()) * 1.25f;
  538. myRatio = MIN( myRatio, 1.0f ); // clamp to 1
  539. // if we have a better local ratio then other proxies, keep this client here
  540. if ( myRatio < fBestRatio )
  541. return false; // don't redirect
  542. }
  543. const char *pszRelayAddr = pBestProxy->GetUserSetting("replay_addr");
  544. if ( !pszRelayAddr )
  545. return false;
  546. ConMsg( "Redirecting spectator %s to Replay relay %s\n",
  547. pClient->GetNetChannel()->GetAddress(),
  548. pszRelayAddr );
  549. // first tell that client that we are a Replay server,
  550. // otherwise it's might ignore the "connect" command
  551. CSVCMsg_ServerInfo_t serverInfo;
  552. FillServerInfo( serverInfo );
  553. pClient->SendNetMsg( serverInfo, true );
  554. // tell the client to connect to this new address
  555. CNETMsg_StringCmd_t cmdMsg( va("connect %s\n", pszRelayAddr ) ) ;
  556. pClient->SendNetMsg( cmdMsg, true );
  557. // increase this proxies client number in advance so this proxy isn't used again next time
  558. int clients = Q_atoi( pBestProxy->GetUserSetting( "replay_clients" ) );
  559. pBestProxy->SetUserCVar( "replay_clients", va("%d", clients+1 ) );
  560. return true;
  561. }
  562. int CReplayServer::GetReplaySlot( void )
  563. {
  564. return m_nPlayerSlot;
  565. }
  566. float CReplayServer::GetOnlineTime( void )
  567. {
  568. return MAX(0, net_time - m_flStartTime);
  569. }
  570. void CReplayServer::BroadcastLocalTitle( CReplayClient *client )
  571. {
  572. IGameEvent *event = g_GameEventManager.CreateEvent( "replay_title", true );
  573. if ( !event )
  574. return;
  575. event->SetString( "text", replay_title.GetString() );
  576. CSVCMsg_GameEvent_t eventMsg;
  577. eventMsg.SetReliable( true );
  578. // create bit stream from KeyValues
  579. if ( !g_GameEventManager.SerializeEvent( event, &eventMsg ) )
  580. {
  581. DevMsg("CReplayServer: failed to serialize title '%s'.\n", event->GetName() );
  582. g_GameEventManager.FreeEvent( event );
  583. return;
  584. }
  585. if ( client )
  586. {
  587. client->SendNetMsg( eventMsg );
  588. }
  589. else
  590. {
  591. for ( int i = 0; i < m_Clients.Count(); i++ )
  592. {
  593. client = Client(i);
  594. if ( !client->IsActive() || client->IsReplay() )
  595. continue;
  596. client->SendNetMsg( eventMsg );
  597. }
  598. }
  599. g_GameEventManager.FreeEvent( event );
  600. }
  601. void CReplayServer::BroadcastLocalChat( const char *pszChat, const char *pszGroup )
  602. {
  603. IGameEvent *event = g_GameEventManager.CreateEvent( "replay_chat", true );
  604. if ( !event )
  605. return;
  606. event->SetString( "text", pszChat );
  607. CSVCMsg_GameEvent_t eventMsg;
  608. eventMsg.SetReliable( false );
  609. // create bit stream from KeyValues
  610. if ( !g_GameEventManager.SerializeEvent( event, &eventMsg ) )
  611. {
  612. DevMsg("CReplayServer: failed to serialize chat '%s'.\n", event->GetName() );
  613. g_GameEventManager.FreeEvent( event );
  614. return;
  615. }
  616. for ( int i = 0; i < m_Clients.Count(); i++ )
  617. {
  618. CReplayClient *cl = Client(i);
  619. if ( !cl->IsActive() || !cl->IsSpawned() || cl->IsReplay() )
  620. continue;
  621. // if this is a spectator chat message and client disabled it, don't show it
  622. if ( Q_strcmp( cl->m_szChatGroup, pszGroup) || cl->m_bNoChat )
  623. continue;
  624. cl->SendNetMsg( eventMsg );
  625. }
  626. g_GameEventManager.FreeEvent( event );
  627. }
  628. void CReplayServer::BroadcastEventLocal( IGameEvent *event, bool bReliable )
  629. {
  630. CSVCMsg_GameEvent_t eventMsg;
  631. eventMsg.SetReliable( bReliable );
  632. // create bit stream from KeyValues
  633. if ( !g_GameEventManager.SerializeEvent( event, &eventMsg ) )
  634. {
  635. DevMsg("CReplayServer: failed to serialize local event '%s'.\n", event->GetName() );
  636. return;
  637. }
  638. for ( int i = 0; i < m_Clients.Count(); i++ )
  639. {
  640. CReplayClient *cl = Client(i);
  641. if ( !cl->IsActive() || !cl->IsSpawned() || cl->IsReplay() )
  642. continue;
  643. if ( !cl->SendNetMsg( eventMsg ) )
  644. {
  645. if ( eventMsg.IsReliable() )
  646. {
  647. DevMsg( "BroadcastMessage: Reliable broadcast message overflow for client %s", cl->GetClientName() );
  648. }
  649. }
  650. }
  651. if ( replay_debug.GetBool() )
  652. Msg("Replay broadcast local event: %s\n", event->GetName() );
  653. }
  654. void CReplayServer::BroadcastEvent(IGameEvent *event)
  655. {
  656. CSVCMsg_GameEvent_t eventMsg;
  657. // create bit stream from KeyValues
  658. if ( !g_GameEventManager.SerializeEvent( event, &eventMsg ) )
  659. {
  660. DevMsg("CReplayServer: failed to serialize event '%s'.\n", event->GetName() );
  661. return;
  662. }
  663. BroadcastMessage( eventMsg, true, true );
  664. if ( replay_debug.GetBool() )
  665. Msg("Replay broadcast event: %s\n", event->GetName() );
  666. }
  667. void CReplayServer::FireGameEvent(IGameEvent *event)
  668. {
  669. if ( !IsActive() )
  670. return;
  671. CSVCMsg_GameEvent_t eventMsg;
  672. // create bit stream from KeyValues
  673. if ( g_GameEventManager.SerializeEvent( event, &eventMsg ) )
  674. {
  675. SendNetMsg( eventMsg );
  676. }
  677. else
  678. {
  679. DevMsg("CReplayServer::FireGameEvent: failed to serialize event '%s'.\n", event->GetName() );
  680. }
  681. }
  682. int CReplayServer::GetEventDebugID()
  683. {
  684. return m_nDebugID;
  685. }
  686. bool CReplayServer::ShouldUpdateMasterServer()
  687. {
  688. if ( IsUsingMasterLegacyMode() )
  689. {
  690. // In the legacy master server updater, we have to call the updater with our CBaseServer* for it to work right.
  691. return true;
  692. }
  693. else
  694. {
  695. // If the main game server is active, then we let it update Steam with the server info.
  696. return !sv.IsActive();
  697. }
  698. }
  699. CBaseClient *CReplayServer::CreateNewClient(int slot )
  700. {
  701. return new CReplayClient( slot, this );
  702. }
  703. void CReplayServer::InstallStringTables( void )
  704. {
  705. #ifndef SHARED_NET_STRING_TABLES
  706. int numTables = m_Server->m_StringTables->GetNumTables();
  707. m_StringTables = &m_NetworkStringTables;
  708. Assert( m_StringTables->GetNumTables() == 0); // must be empty
  709. m_StringTables->AllowCreation( true );
  710. // master replay needs to keep a list of changes for all table items
  711. m_StringTables->EnableRollback( true );
  712. for ( int i =0; i<numTables; i++)
  713. {
  714. // iterate through server tables
  715. CNetworkStringTable *serverTable =
  716. (CNetworkStringTable*)m_Server->m_StringTables->GetTable( i );
  717. if ( !serverTable )
  718. continue;
  719. // get matching client table
  720. CNetworkStringTable *replayTable =
  721. (CNetworkStringTable*)m_StringTables->CreateStringTable(
  722. serverTable->GetTableName(),
  723. serverTable->GetMaxStrings(),
  724. serverTable->GetUserDataSize(),
  725. serverTable->GetUserDataSizeBits(),
  726. serverTable->IsUsingDictionary() ? NSF_DICTIONARY_ENABLED : NSF_NONE
  727. );
  728. if ( !replayTable )
  729. {
  730. DevMsg("SV_InstallReplayStringTableMirrors! Missing client table \"%s\".\n ", serverTable->GetTableName() );
  731. continue;
  732. }
  733. // make replay table an exact copy of server table
  734. replayTable->CopyStringTable( serverTable );
  735. // link replay table to server table
  736. serverTable->SetMirrorTable( replayTable );
  737. }
  738. m_StringTables->AllowCreation( false );
  739. #endif
  740. }
  741. void CReplayServer::RestoreTick( int tick )
  742. {
  743. #ifndef SHARED_NET_STRING_TABLES
  744. int numTables = m_StringTables->GetNumTables();
  745. for ( int i =0; i<numTables; i++)
  746. {
  747. // iterate through server tables
  748. CNetworkStringTable *pTable = (CNetworkStringTable*) m_StringTables->GetTable( i );
  749. pTable->RestoreTick( tick );
  750. }
  751. #endif
  752. }
  753. void CReplayServer::UserInfoChanged( int nClientIndex )
  754. {
  755. // don't change UserInfo table, it keeps the infos of the original players
  756. }
  757. void CReplayServer::LinkInstanceBaselines( void )
  758. {
  759. // Forces to update m_pInstanceBaselineTable.
  760. AUTO_LOCK_FM( g_svInstanceBaselineMutex );
  761. GetInstanceBaselineTable();
  762. Assert( m_pInstanceBaselineTable );
  763. // update all found server classes
  764. for ( ServerClass *pClass = serverGameDLL->GetAllServerClasses(); pClass; pClass=pClass->m_pNext )
  765. {
  766. char idString[32];
  767. Q_snprintf( idString, sizeof( idString ), "%d", pClass->m_ClassID );
  768. // Ok, make a new instance baseline so they can reference it.
  769. int index = m_pInstanceBaselineTable->FindStringIndex( idString );
  770. if ( index != -1 )
  771. {
  772. pClass->m_InstanceBaselineIndex = index;
  773. }
  774. else
  775. {
  776. pClass->m_InstanceBaselineIndex = INVALID_STRING_INDEX;
  777. }
  778. }
  779. }
  780. /* CReplayServer::GetOriginFromPackedEntity is such a bad, bad hack.
  781. extern float DecodeFloat(SendProp const *pProp, bf_read *pIn);
  782. Vector CReplayServer::GetOriginFromPackedEntity(PackedEntity* pe)
  783. {
  784. Vector origin; origin.Init();
  785. SendTable *pSendTable = pe->m_pSendTable;
  786. // recursively go down until BaseEntity sendtable
  787. while ( Q_strcmp( pSendTable->GetName(), "DT_BaseEntity") )
  788. {
  789. SendProp *pProp = pSendTable->GetProp( 0 ); // 0 = baseclass
  790. pSendTable = pProp->GetDataTable();
  791. }
  792. for ( int i=0; i < pSendTable->GetNumProps(); i++ )
  793. {
  794. SendProp *pProp = pSendTable->GetProp( i );
  795. if ( Q_strcmp( pProp->GetName(), "m_vecOrigin" ) == 0 )
  796. {
  797. Assert( pProp->GetType() == DPT_Vector );
  798. bf_read buf( pe->LockData(), Bits2Bytes(pe->GetNumBits()), pProp->GetOffset() );
  799. origin[0] = DecodeFloat(pProp, &buf);
  800. origin[1] = DecodeFloat(pProp, &buf);
  801. origin[2] = DecodeFloat(pProp, &buf);
  802. break;
  803. }
  804. }
  805. return origin;
  806. } */
  807. CReplayEntityData *FindReplayDataInSnapshot( CFrameSnapshot * pSnapshot, int iEntIndex )
  808. {
  809. int a = 0;
  810. int z = pSnapshot->m_nValidEntities-1;
  811. if ( iEntIndex < pSnapshot->m_pValidEntities[a] ||
  812. iEntIndex > pSnapshot->m_pValidEntities[z] )
  813. return NULL;
  814. while ( a < z )
  815. {
  816. int m = (a+z)/2;
  817. int index = pSnapshot->m_pValidEntities[m];
  818. if ( index == iEntIndex )
  819. return &pSnapshot->m_pReplayEntityData[m];
  820. if ( iEntIndex > index )
  821. {
  822. if ( pSnapshot->m_pValidEntities[z] == iEntIndex )
  823. return &pSnapshot->m_pReplayEntityData[z];
  824. if ( a == m )
  825. return NULL;
  826. a = m;
  827. }
  828. else
  829. {
  830. if ( pSnapshot->m_pValidEntities[a] == iEntIndex )
  831. return &pSnapshot->m_pReplayEntityData[a];
  832. if ( z == m )
  833. return NULL;
  834. z = m;
  835. }
  836. }
  837. return NULL;
  838. }
  839. void CReplayServer::EntityPVSCheck( CClientFrame *pFrame )
  840. {
  841. byte PVS[PAD_NUMBER( MAX_MAP_CLUSTERS,8 ) / 8];
  842. int nPVSSize = (GetCollisionBSPData()->numclusters + 7) / 8;
  843. // setup engine PVS
  844. SV_ResetPVS( PVS, nPVSSize );
  845. CFrameSnapshot * pSnapshot = pFrame->GetSnapshot();
  846. Assert ( pSnapshot->m_pReplayEntityData != NULL );
  847. int nDirectorEntity = m_Director->GetPVSEntity();
  848. if ( pSnapshot && nDirectorEntity > 0 )
  849. {
  850. CReplayEntityData *pReplayData = FindReplayDataInSnapshot( pSnapshot, nDirectorEntity );
  851. if ( pReplayData )
  852. {
  853. m_vPVSOrigin.x = pReplayData->origin[0];
  854. m_vPVSOrigin.y = pReplayData->origin[1];
  855. m_vPVSOrigin.z = pReplayData->origin[2];
  856. }
  857. }
  858. else
  859. {
  860. m_vPVSOrigin = m_Director->GetPVSOrigin();
  861. }
  862. SV_AddOriginToPVS( m_vPVSOrigin );
  863. // know remove all entities that aren't in PVS
  864. int entindex = -1;
  865. while ( true )
  866. {
  867. entindex = pFrame->transmit_entity.FindNextSetBit( entindex+1 );
  868. if ( entindex < 0 )
  869. break;
  870. // is transmit_always is set -> no PVS check
  871. if ( pFrame->transmit_always->Get(entindex) )
  872. {
  873. pFrame->last_entity = entindex;
  874. continue;
  875. }
  876. CReplayEntityData *pReplayData = FindReplayDataInSnapshot( pSnapshot, entindex );
  877. if ( !pReplayData )
  878. continue;
  879. unsigned int nNodeCluster = pReplayData->m_nNodeCluster;
  880. // check if node or cluster is in PVS
  881. if ( nNodeCluster & (1<<31) )
  882. {
  883. // it's a node SLOW
  884. nNodeCluster &= ~(1<<31);
  885. if ( CM_HeadnodeVisible( nNodeCluster, PVS, nPVSSize ) )
  886. {
  887. pFrame->last_entity = entindex;
  888. continue;
  889. }
  890. }
  891. else
  892. {
  893. // it's a cluster QUICK
  894. if ( PVS[nNodeCluster >> 3] & (1 << (nNodeCluster & 7)) )
  895. {
  896. pFrame->last_entity = entindex;
  897. continue;
  898. }
  899. }
  900. // entity is not in PVS, remove from transmit_entity list
  901. pFrame->transmit_entity.Clear( entindex );
  902. }
  903. }
  904. CClientFrame *CReplayServer::AddNewFrame( CClientFrame *clientFrame )
  905. {
  906. VPROF_BUDGET( "CReplayServer::AddNewFrame", "Replay" );
  907. Assert ( clientFrame );
  908. Assert( clientFrame->tick_count > m_nLastTick );
  909. m_nLastTick = clientFrame->tick_count;
  910. m_ReplayFrame.SetSnapshot( clientFrame->GetSnapshot() );
  911. m_ReplayFrame.tick_count = clientFrame->tick_count;
  912. m_ReplayFrame.last_entity = clientFrame->last_entity;
  913. m_ReplayFrame.transmit_entity = clientFrame->transmit_entity;
  914. // remember tick of first valid frame
  915. if ( m_nFirstTick < 0 )
  916. {
  917. m_nFirstTick = clientFrame->tick_count;
  918. m_nTickCount = m_nFirstTick;
  919. }
  920. CReplayFrame *replayFrame = new CReplayFrame;
  921. // copy tickcount & entities from client frame
  922. replayFrame->CopyFrame( *clientFrame );
  923. //copy rest (messages, tempents) from current Replay frame
  924. replayFrame->CopyReplayData( m_ReplayFrame );
  925. // add frame to Replay server
  926. AddClientFrame( replayFrame );
  927. if ( m_DemoRecorder.IsRecording() )
  928. {
  929. m_DemoRecorder.WriteFrame( &m_ReplayFrame );
  930. }
  931. // reset Replay frame for recording next messages etc.
  932. m_ReplayFrame.Reset();
  933. m_ReplayFrame.SetSnapshot( NULL );
  934. return replayFrame;
  935. }
  936. void CReplayServer::SendClientMessages ( bool bSendSnapshots )
  937. {
  938. // build individual updates
  939. for ( int i=0; i< m_Clients.Count(); i++ )
  940. {
  941. CReplayClient* client = Client(i);
  942. // Update Host client send state...
  943. if ( !client->ShouldSendMessages() )
  944. {
  945. continue;
  946. }
  947. // Append the unreliable data (player updates and packet entities)
  948. if ( m_CurrentFrame && client->IsActive() )
  949. {
  950. // don't send same snapshot twice
  951. client->SendSnapshot( m_CurrentFrame );
  952. }
  953. else
  954. {
  955. // Connected, but inactive, just send reliable, sequenced info.
  956. client->m_NetChannel->Transmit();
  957. }
  958. client->UpdateSendState();
  959. client->m_fLastSendTime = net_time;
  960. }
  961. }
  962. bool CReplayServer::SendNetMsg( INetMessage &msg, bool bForceReliable )
  963. {
  964. if ( m_bSignonState )
  965. {
  966. return msg.WriteToBuffer( m_Signon );
  967. }
  968. int buffer = REPLAY_BUFFER_UNRELIABLE; // default destination
  969. if ( msg.IsReliable() )
  970. {
  971. buffer = REPLAY_BUFFER_RELIABLE;
  972. }
  973. else if ( msg.GetType() == svc_Sounds )
  974. {
  975. buffer = REPLAY_BUFFER_SOUNDS;
  976. }
  977. else if ( msg.GetType() == svc_VoiceData )
  978. {
  979. buffer = REPLAY_BUFFER_VOICE;
  980. }
  981. else if ( msg.GetType() == svc_TempEntities )
  982. {
  983. buffer = REPLAY_BUFFER_TEMPENTS;
  984. }
  985. // anything else goes to the unreliable bin
  986. return msg.WriteToBuffer( m_ReplayFrame.m_Messages[buffer] );
  987. }
  988. bf_write *CReplayServer::GetBuffer( int nBuffer )
  989. {
  990. if ( nBuffer < 0 || nBuffer >= REPLAY_BUFFER_MAX )
  991. return NULL;
  992. return &m_ReplayFrame.m_Messages[nBuffer];
  993. }
  994. IServer *CReplayServer::GetBaseServer()
  995. {
  996. return (IServer*)this;
  997. }
  998. IReplayDirector *CReplayServer::GetDirector()
  999. {
  1000. return m_Director;
  1001. }
  1002. CClientFrame *CReplayServer::GetDeltaFrame( int nTick )
  1003. {
  1004. if ( !replay_deltacache.GetBool() )
  1005. return GetClientFrame( nTick ); //expensive
  1006. // TODO make that a utlmap
  1007. FOR_EACH_VEC( m_FrameCache, iFrame )
  1008. {
  1009. if ( m_FrameCache[iFrame].nTick == nTick )
  1010. return m_FrameCache[iFrame].pFrame;
  1011. }
  1012. int i = m_FrameCache.AddToTail();
  1013. CReplayFrameCacheEntry_s &entry = m_FrameCache[i];
  1014. entry.nTick = nTick;
  1015. entry.pFrame = GetClientFrame( nTick ); //expensive
  1016. return entry.pFrame;
  1017. }
  1018. void CReplayServer::RunFrame()
  1019. {
  1020. VPROF_BUDGET( "CReplayServer::RunFrame", "Replay" );
  1021. // update network time etc
  1022. NET_RunFrame( Plat_FloatTime() );
  1023. // check if Replay server if active
  1024. if ( !IsActive() )
  1025. return;
  1026. if ( host_frametime > 0 )
  1027. {
  1028. m_flFPS = m_flFPS * 0.99f + 0.01f/host_frametime;
  1029. }
  1030. // get current tick time for director module and restore
  1031. // world (stringtables, framebuffers) as they were at this time
  1032. UpdateTick();
  1033. // Run any commands from client and play client Think functions if it is time.
  1034. CBaseServer::RunFrame();
  1035. SendClientMessages( true );
  1036. // Update the Steam server if we're running a relay.
  1037. if ( !sv.IsActive() )
  1038. Steam3Server().RunFrame();
  1039. UpdateMasterServer();
  1040. // ::Con_NPrintf( 9 , "server time: %d", host_tickcount );
  1041. // ::Con_NPrintf( 10, "replay time: %d", m_DemoRecorder.GetRecordingTick() );
  1042. }
  1043. void CReplayServer::UpdateTick( void )
  1044. {
  1045. VPROF_BUDGET( "CReplayServer::UpdateTick", "Replay" );
  1046. if ( m_nFirstTick < 0 )
  1047. {
  1048. m_nTickCount = 0;
  1049. m_CurrentFrame = NULL;
  1050. return;
  1051. }
  1052. // HACK: I'm not so sure this is the right place for this, but essentially the start tick needs to
  1053. // represent the "oldest" tick in the cache of frames for a replay demo - for a regular demo, it need
  1054. // not be modified here. NOTE: If this is a regular demo, this call does nothing.
  1055. m_DemoRecorder.m_DemoFile.UpdateStartTick( m_DemoRecorder.m_nStartTick );
  1056. // set tick time to last frame added
  1057. int nNewTick = m_nLastTick;
  1058. // get tick from director, he decides delay etc
  1059. nNewTick = MAX( m_nFirstTick, m_Director->GetDirectorTick() );
  1060. // the the closest available frame
  1061. CReplayFrame *newFrame = (CReplayFrame*) GetClientFrame( nNewTick, false );
  1062. if ( newFrame == NULL )
  1063. return; // we dont have a new frame
  1064. if ( m_CurrentFrame == newFrame )
  1065. return; // current frame didn't change
  1066. m_CurrentFrame = newFrame;
  1067. m_nTickCount = m_CurrentFrame->tick_count;
  1068. // restore string tables for this time
  1069. RestoreTick( m_nTickCount );
  1070. // remove entities out of current PVS
  1071. if ( !replay_transmitall.GetBool() )
  1072. {
  1073. EntityPVSCheck( m_CurrentFrame );
  1074. }
  1075. int removeTick = m_nTickCount - 16.0f/m_flTickInterval; // keep 16 second buffer
  1076. if ( removeTick > 0 )
  1077. {
  1078. DeleteClientFrames( removeTick );
  1079. }
  1080. m_FrameCache.RemoveAll();
  1081. }
  1082. const char *CReplayServer::GetName( void ) const
  1083. {
  1084. return replay_name.GetString();
  1085. }
  1086. void CReplayServer::FillServerInfo(CSVCMsg_ServerInfo &serverinfo)
  1087. {
  1088. CBaseServer::FillServerInfo( serverinfo );
  1089. serverinfo.set_player_slot( m_nPlayerSlot ); // all spectators think they're the Replay client
  1090. serverinfo.set_max_clients( m_nGameServerMaxClients );
  1091. }
  1092. void CReplayServer::Clear( void )
  1093. {
  1094. CBaseServer::Clear();
  1095. m_Director = NULL;
  1096. m_MasterClient = NULL;
  1097. m_Server = NULL;
  1098. m_nFirstTick = -1;
  1099. m_nLastTick = 0;
  1100. m_nTickCount = 0;
  1101. m_CurrentFrame = NULL;
  1102. m_nPlayerSlot = 0;
  1103. m_flStartTime = 0.0f;
  1104. m_nViewEntity = 1;
  1105. m_nGameServerMaxClients = 0;
  1106. m_fNextSendUpdateTime = 0.0f;
  1107. m_ReplayFrame.FreeBuffers();
  1108. m_vPVSOrigin.Init();
  1109. m_vecClientsDownloading.ClearAll();
  1110. DeleteClientFrames( -1 );
  1111. m_DeltaCache.Flush();
  1112. m_FrameCache.RemoveAll();
  1113. }
  1114. void CReplayServer::Init(bool bIsDedicated)
  1115. {
  1116. CBaseServer::Init( bIsDedicated );
  1117. m_Socket = NS_REPLAY;
  1118. // check if only master proxy is allowed, no broadcasting
  1119. if ( CommandLine()->FindParm("-tvmasteronly") )
  1120. {
  1121. m_bMasterOnlyMode = true;
  1122. }
  1123. }
  1124. void CReplayServer::Changelevel()
  1125. {
  1126. m_DemoRecorder.StopRecording();
  1127. InactivateClients();
  1128. DeleteClientFrames(-1);
  1129. m_CurrentFrame = NULL;
  1130. }
  1131. void CReplayServer::GetNetStats( float &avgIn, float &avgOut )
  1132. {
  1133. CBaseServer::GetNetStats( avgIn, avgOut );
  1134. }
  1135. void CReplayServer::Shutdown( void )
  1136. {
  1137. m_DemoRecorder.StopRecording(); // if recording, stop now
  1138. if ( m_MasterClient )
  1139. m_MasterClient->Disconnect( "Replay stop." );
  1140. if ( m_Director )
  1141. m_Director->SetReplayServer( NULL );
  1142. g_GameEventManager.RemoveListener( this );
  1143. CBaseServer::Shutdown();
  1144. }
  1145. int CReplayServer::GetChallengeType ( netadr_t &adr )
  1146. {
  1147. return PROTOCOL_HASHEDCDKEY; // Replay doesn't need Steam authentication
  1148. }
  1149. const char *CReplayServer::GetPassword() const
  1150. {
  1151. const char *password = replay_password.GetString();
  1152. // if password is empty or "none", return NULL
  1153. if ( !password[0] || !Q_stricmp(password, "none" ) )
  1154. {
  1155. return NULL;
  1156. }
  1157. return password;
  1158. }
  1159. IClient *CReplayServer::ConnectClient ( const ns_address &adr, int protocol, int challenge, int authProtocol,
  1160. const char *name, const char *password, const char *hashedCDkey, int cdKeyLen,
  1161. CUtlVector< CCLCMsg_SplitPlayerConnect_t * > & splitScreenClients, bool isClientLowViolence, CrossPlayPlatform_t clientPlatform,
  1162. const byte *pbEncryptionKey, int nEncryptionKeyIndex )
  1163. {
  1164. IClient *client = (CReplayClient*)CBaseServer::ConnectClient(
  1165. adr, protocol, challenge,authProtocol, name, password, hashedCDkey, cdKeyLen, splitScreenClients, isClientLowViolence, clientPlatform,
  1166. pbEncryptionKey, nEncryptionKeyIndex );
  1167. if ( client )
  1168. {
  1169. // remember password
  1170. CReplayClient *pReplayClient = (CReplayClient*)client;
  1171. Q_strncpy( pReplayClient->m_szPassword, password, sizeof(pReplayClient->m_szPassword) );
  1172. }
  1173. return client;
  1174. }
  1175. CON_COMMAND( replay_status, "Show Replay server status." )
  1176. {
  1177. float in, out;
  1178. char gd[MAX_OSPATH];
  1179. Q_FileBase( com_gamedir, gd, sizeof( gd ) );
  1180. if ( !replay || !replay->IsActive() )
  1181. {
  1182. ConMsg("Replay not active.\n" );
  1183. return;
  1184. }
  1185. replay->GetNetStats( in, out );
  1186. in /= 1024; // as KB
  1187. out /= 1024;
  1188. ConMsg("--- Replay Status ---\n");
  1189. ConMsg("Online %s, FPS %.1f, Version %i (%s)\n",
  1190. COM_FormatSeconds( replay->GetOnlineTime() ), replay->m_flFPS, build_number(),
  1191. #ifdef _WIN32
  1192. "Win32" );
  1193. #else
  1194. "Linux" );
  1195. #endif
  1196. ConMsg("Master \"%s\", delay %.0f\n", replay->GetName(), replay->GetDirector()->GetDelay() );
  1197. ConMsg("Game Time %s, Mod \"%s\", Map \"%s\", Players %i\n", COM_FormatSeconds( replay->GetTime() ),
  1198. gd, replay->GetMapName(), replay->GetNumPlayers() );
  1199. ConMsg("Local IP %s:%i, KB/sec In %.1f, Out %.1f\n",
  1200. net_local_adr.ToString( true ), replay->GetUDPPort(), in ,out );
  1201. if ( replay->m_DemoRecorder.IsRecording() )
  1202. {
  1203. ConMsg("Recording to \"%s\", length %s.\n", replay->m_DemoRecorder.GetDemoFile()->m_szFileName,
  1204. COM_FormatSeconds( host_state.interval_per_tick * replay->m_DemoRecorder.GetRecordingTick() ) );
  1205. }
  1206. }
  1207. CON_COMMAND( replay_record, "Starts Replay demo recording." )
  1208. {
  1209. #if 0
  1210. AssertMsg( 0, "Use replay_autorecord 1!" );
  1211. #else
  1212. if ( !replay || !replay->IsActive() )
  1213. {
  1214. ConMsg("Replay not active.\n" );
  1215. return;
  1216. }
  1217. if ( replay->m_DemoRecorder.IsRecording() )
  1218. {
  1219. ConMsg("Replay already recording to %s.\n", replay->m_DemoRecorder.GetDemoFile()->m_szFileName );
  1220. return;
  1221. }
  1222. replay->m_DemoRecorder.StartAutoRecording();
  1223. #endif
  1224. }
  1225. CON_COMMAND( replay_stoprecord, "Stops Replay demo recording." )
  1226. {
  1227. if ( !replay || !replay->IsActive() )
  1228. {
  1229. ConMsg("Replay not active.\n" );
  1230. return;
  1231. }
  1232. replay->m_DemoRecorder.StopRecording();
  1233. }
  1234. #endif