Team Fortress 2 Source Code as on 22/4/2020
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.

911 lines
25 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include <proto_version.h>
  9. #include <netmessages.h>
  10. #include "hltvclientstate.h"
  11. #include "hltvserver.h"
  12. #include "quakedef.h"
  13. #include "cl_main.h"
  14. #include "host.h"
  15. #include "dt_recv_eng.h"
  16. #include "dt_common_eng.h"
  17. #include "framesnapshot.h"
  18. #include "clientframe.h"
  19. #include "ents_shared.h"
  20. #include "server.h"
  21. #include "eiface.h"
  22. #include "server_class.h"
  23. #include "cdll_engine_int.h"
  24. #include "sv_main.h"
  25. #include "changeframelist.h"
  26. #include "GameEventManager.h"
  27. #include "dt_recv_decoder.h"
  28. #include "utllinkedlist.h"
  29. #include "cl_demo.h"
  30. // memdbgon must be the last include file in a .cpp file!!!
  31. #include "tier0/memdbgon.h"
  32. // copy message data from in to out buffer
  33. #define CopyDataInToOut(msg) \
  34. int size = PAD_NUMBER( Bits2Bytes(msg->m_nLength), 4); \
  35. byte *buffer = (byte*) stackalloc( size ); \
  36. msg->m_DataIn.ReadBits( buffer, msg->m_nLength ); \
  37. msg->m_DataOut.StartWriting( buffer, size, msg->m_nLength );\
  38. static void HLTV_Callback_InstanceBaseline( void *object, INetworkStringTable *stringTable, int stringNumber, char const *newString, void const *newData )
  39. {
  40. // relink server classes to instance baselines
  41. CHLTVServer *pHLTV = (CHLTVServer*)object;
  42. pHLTV->LinkInstanceBaselines();
  43. }
  44. extern CUtlLinkedList< CRecvDecoder *, unsigned short > g_RecvDecoders;
  45. extern ConVar tv_autorecord;
  46. static ConVar tv_autoretry( "tv_autoretry", "1", 0, "Relay proxies retry connection after network timeout" );
  47. static ConVar tv_timeout( "tv_timeout", "30", 0, "SourceTV connection timeout in seconds." );
  48. ConVar tv_snapshotrate("tv_snapshotrate", "16", 0, "Snapshots broadcasted per second" );
  49. //////////////////////////////////////////////////////////////////////
  50. // Construction/Destruction
  51. //////////////////////////////////////////////////////////////////////
  52. CHLTVClientState::CHLTVClientState()
  53. {
  54. m_pNewClientFrame = NULL;
  55. m_pCurrentClientFrame = NULL;
  56. m_bSaveMemory = false;
  57. }
  58. CHLTVClientState::~CHLTVClientState()
  59. {
  60. }
  61. void CHLTVClientState::CopyNewEntity(
  62. CEntityReadInfo &u,
  63. int iClass,
  64. int iSerialNum
  65. )
  66. {
  67. ServerClass *pServerClass = SV_FindServerClass( iClass );
  68. Assert( pServerClass );
  69. ClientClass *pClientClass = GetClientClass( iClass );
  70. Assert( pClientClass );
  71. const int ent = u.m_nNewEntity;
  72. // copy class & serial
  73. CFrameSnapshot *pSnapshot = u.m_pTo->GetSnapshot();
  74. pSnapshot->m_pEntities[ent].m_nSerialNumber = iSerialNum;
  75. pSnapshot->m_pEntities[ent].m_pClass = pServerClass;
  76. // Get either the static or instance baseline.
  77. const void *pFromData = NULL;
  78. int nFromBits = 0;
  79. int nFromTick = 0; // MOTODO get tick when baseline last changed
  80. PackedEntity *baseline = u.m_bAsDelta ? GetEntityBaseline( u.m_nBaseline, ent ) : NULL;
  81. if ( baseline && baseline->m_pClientClass == pClientClass )
  82. {
  83. Assert( !baseline->IsCompressed() );
  84. pFromData = baseline->GetData();
  85. nFromBits = baseline->GetNumBits();
  86. }
  87. else
  88. {
  89. // Every entity must have a static or an instance baseline when we get here.
  90. ErrorIfNot(
  91. GetClassBaseline( iClass, &pFromData, &nFromBits ),
  92. ("HLTV_CopyNewEntity: GetDynamicBaseline(%d) failed.", iClass)
  93. );
  94. nFromBits *= 8; // convert to bits
  95. }
  96. // create new ChangeFrameList containing all properties set as changed
  97. int nFlatProps = SendTable_GetNumFlatProps( pServerClass->m_pTable );
  98. IChangeFrameList *pChangeFrame = NULL;
  99. if ( !m_bSaveMemory )
  100. {
  101. pChangeFrame = AllocChangeFrameList( nFlatProps, nFromTick );
  102. }
  103. // Now make a PackedEntity and store the new packed data in there.
  104. PackedEntity *pPackedEntity = framesnapshotmanager->CreatePackedEntity( pSnapshot, ent );
  105. pPackedEntity->SetChangeFrameList( pChangeFrame );
  106. pPackedEntity->SetServerAndClientClass( pServerClass, pClientClass );
  107. // Make space for the baseline data.
  108. ALIGN4 char packedData[MAX_PACKEDENTITY_DATA] ALIGN4_POST;
  109. bf_read fromBuf( "HLTV_ReadEnterPVS1", pFromData, Bits2Bytes( nFromBits ), nFromBits );
  110. bf_write writeBuf( "HLTV_ReadEnterPVS2", packedData, sizeof( packedData ) );
  111. int changedProps[MAX_DATATABLE_PROPS];
  112. // decode basline, is compressed against zero values
  113. int nChangedProps = RecvTable_MergeDeltas( pClientClass->m_pRecvTable, &fromBuf,
  114. u.m_pBuf, &writeBuf, -1, changedProps );
  115. // update change tick in ChangeFrameList
  116. if ( pChangeFrame )
  117. {
  118. pChangeFrame->SetChangeTick( changedProps, nChangedProps, pSnapshot->m_nTickCount );
  119. }
  120. if ( u.m_bUpdateBaselines )
  121. {
  122. SetEntityBaseline( (u.m_nBaseline==0)?1:0, pClientClass, u.m_nNewEntity, packedData, writeBuf.GetNumBytesWritten() );
  123. }
  124. pPackedEntity->AllocAndCopyPadded( packedData, writeBuf.GetNumBytesWritten() );
  125. // If ent doesn't think it's in PVS, signal that it is
  126. Assert( u.m_pTo->last_entity <= ent );
  127. u.m_pTo->last_entity = ent;
  128. u.m_pTo->transmit_entity.Set( ent );
  129. }
  130. static inline void HLTV_CopyExitingEnt( CEntityReadInfo &u )
  131. {
  132. if ( !u.m_bAsDelta ) // Should never happen on a full update.
  133. {
  134. Assert(0); // cl.validsequence = 0;
  135. ConMsg( "WARNING: CopyExitingEnt on full update.\n" );
  136. u.m_UpdateType = Failed; // break out
  137. return;
  138. }
  139. CFrameSnapshot *pFromSnapshot = u.m_pFrom->GetSnapshot(); // get from snapshot
  140. const int ent = u.m_nOldEntity;
  141. CFrameSnapshot *pSnapshot = u.m_pTo->GetSnapshot(); // get to snapshot
  142. // copy ent handle, serial numbers & class info
  143. Assert( ent < pFromSnapshot->m_nNumEntities );
  144. pSnapshot->m_pEntities[ent] = pFromSnapshot->m_pEntities[ent];
  145. Assert( pSnapshot->m_pEntities[ent].m_pPackedData != INVALID_PACKED_ENTITY_HANDLE );
  146. // increase PackedEntity reference counter
  147. PackedEntity *pEntity = framesnapshotmanager->GetPackedEntity( pSnapshot, ent );
  148. Assert( pEntity );
  149. pEntity->m_ReferenceCount++;
  150. Assert( u.m_pTo->last_entity <= ent );
  151. // mark flags as received
  152. u.m_pTo->last_entity = ent;
  153. u.m_pTo->transmit_entity.Set( ent );
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Purpose: A svc_signonnum has been received, perform a client side setup
  157. // Output : void CL_SignonReply
  158. //-----------------------------------------------------------------------------
  159. bool CHLTVClientState::SetSignonState ( int state, int count )
  160. {
  161. // ConDMsg ("CL_SignonReply: %i\n", cl.signon);
  162. if ( !CBaseClientState::SetSignonState( state, count ) )
  163. return false;
  164. Assert ( m_nSignonState == state );
  165. switch ( m_nSignonState )
  166. {
  167. case SIGNONSTATE_CHALLENGE : break;
  168. case SIGNONSTATE_CONNECTED : {
  169. // allow longer timeout
  170. m_NetChannel->SetTimeout( SIGNON_TIME_OUT );
  171. m_NetChannel->Clear();
  172. // set user settings (rate etc)
  173. NET_SetConVar convars;
  174. Host_BuildConVarUpdateMessage( &convars, FCVAR_USERINFO, false );
  175. // let server know that we are a proxy server:
  176. NET_SetConVar::cvar_t acvar;
  177. V_strcpy_safe( acvar.name, "tv_relay" );
  178. V_strcpy_safe( acvar.value, "1" );
  179. convars.m_ConVars.AddToTail( acvar );
  180. m_NetChannel->SendNetMsg( convars );
  181. }
  182. break;
  183. case SIGNONSTATE_NEW : SendClientInfo();
  184. break;
  185. case SIGNONSTATE_PRESPAWN : break;
  186. case SIGNONSTATE_SPAWN : m_pHLTV->SignonComplete();
  187. break;
  188. case SIGNONSTATE_FULL : m_NetChannel->SetTimeout( tv_timeout.GetFloat() );
  189. // start new recording if autorecord is enabled
  190. if ( tv_autorecord.GetBool() )
  191. {
  192. hltv->m_DemoRecorder.StartAutoRecording();
  193. m_NetChannel->SetDemoRecorder( &hltv->m_DemoRecorder );
  194. }
  195. break;
  196. case SIGNONSTATE_CHANGELEVEL: m_pHLTV->Changelevel();
  197. m_NetChannel->SetTimeout( SIGNON_TIME_OUT ); // allow 5 minutes timeout
  198. break;
  199. }
  200. if ( m_nSignonState >= SIGNONSTATE_CONNECTED )
  201. {
  202. // tell server that we entered now that state
  203. NET_SignonState signonState( m_nSignonState, count );
  204. m_NetChannel->SendNetMsg( signonState );
  205. }
  206. return true;
  207. }
  208. void CHLTVClientState::SendClientInfo( void )
  209. {
  210. CLC_ClientInfo info;
  211. info.m_nSendTableCRC = SendTable_GetCRC();
  212. info.m_nServerCount = m_nServerCount;
  213. info.m_bIsHLTV = true;
  214. #if defined( REPLAY_ENABLED )
  215. info.m_bIsReplay = false;
  216. #endif
  217. info.m_nFriendsID = 0;
  218. info.m_FriendsName[0] = 0;
  219. // CheckOwnCustomFiles(); // load & verfiy custom player files
  220. for ( int i=0; i< MAX_CUSTOM_FILES; i++ )
  221. info.m_nCustomFiles[i] = 0;
  222. m_NetChannel->SendNetMsg( info );
  223. }
  224. void CHLTVClientState::SendPacket()
  225. {
  226. if ( !IsConnected() )
  227. return;
  228. if ( ( net_time < m_flNextCmdTime ) || !m_NetChannel->CanPacket() )
  229. return;
  230. if ( IsActive() )
  231. {
  232. NET_Tick tick( m_nDeltaTick, host_frametime_unbounded, host_frametime_stddeviation );
  233. m_NetChannel->SendNetMsg( tick );
  234. }
  235. m_NetChannel->SendDatagram( NULL );
  236. if ( IsActive() )
  237. {
  238. // use full update rate when active
  239. float commandInterval = (2.0f/3.0f) / tv_snapshotrate.GetInt();
  240. float maxDelta = min ( host_state.interval_per_tick, commandInterval );
  241. float delta = clamp( (float)(net_time - m_flNextCmdTime), 0.0f, maxDelta );
  242. m_flNextCmdTime = net_time + commandInterval - delta;
  243. }
  244. else
  245. {
  246. // during signon process send only 5 packets/second
  247. m_flNextCmdTime = net_time + ( 1.0f / 5.0f );
  248. }
  249. }
  250. bool CHLTVClientState::ProcessStringCmd(NET_StringCmd *msg)
  251. {
  252. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  253. }
  254. bool CHLTVClientState::ProcessSetConVar(NET_SetConVar *msg)
  255. {
  256. if ( !CBaseClientState::ProcessSetConVar( msg ) )
  257. return false;
  258. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  259. }
  260. void CHLTVClientState::Clear()
  261. {
  262. CBaseClientState::Clear();
  263. m_pNewClientFrame = NULL;
  264. m_pCurrentClientFrame = NULL;
  265. }
  266. bool CHLTVClientState::ProcessServerInfo(SVC_ServerInfo *msg )
  267. {
  268. // Reset client state
  269. Clear();
  270. // is server a HLTV proxy or demo file ?
  271. if ( !m_pHLTV->IsPlayingBack() )
  272. {
  273. if ( !msg->m_bIsHLTV )
  274. {
  275. ConMsg ( "Server (%s) is not a SourceTV proxy.\n", m_NetChannel->GetAddress() );
  276. Disconnect( "Server is not a SourceTV proxy", true );
  277. return false;
  278. }
  279. }
  280. // tell HLTV relay to clear everything
  281. m_pHLTV->StartRelay();
  282. // Process the message
  283. if ( !CBaseClientState::ProcessServerInfo( msg ) )
  284. {
  285. Disconnect( "CBaseClientState::ProcessServerInfo failed", true );
  286. return false;
  287. }
  288. m_StringTableContainer = m_pHLTV->m_StringTables;
  289. Assert( m_StringTableContainer->GetNumTables() == 0); // must be empty
  290. #ifndef SHARED_NET_STRING_TABLES
  291. // relay uses normal string tables without a change history
  292. m_StringTableContainer->EnableRollback( false );
  293. #endif
  294. // copy setting from HLTV client to HLTV server
  295. m_pHLTV->m_nGameServerMaxClients = m_nMaxClients;
  296. m_pHLTV->serverclasses = m_nServerClasses;
  297. m_pHLTV->serverclassbits = m_nServerClassBits;
  298. m_pHLTV->m_nPlayerSlot = m_nPlayerSlot;
  299. // copy other settings to HLTV server
  300. V_memcpy( m_pHLTV->worldmapMD5.bits, msg->m_nMapMD5.bits, MD5_DIGEST_LENGTH );
  301. m_pHLTV->m_flTickInterval = msg->m_fTickInterval;
  302. host_state.interval_per_tick = msg->m_fTickInterval;
  303. Q_strncpy( m_pHLTV->m_szMapname, msg->m_szMapName, sizeof(m_pHLTV->m_szMapname) );
  304. Q_strncpy( m_pHLTV->m_szSkyname, msg->m_szSkyName, sizeof(m_pHLTV->m_szSkyname) );
  305. return true;
  306. }
  307. bool CHLTVClientState::ProcessClassInfo( SVC_ClassInfo *msg )
  308. {
  309. if ( !msg->m_bCreateOnClient )
  310. {
  311. ConMsg("HLTV SendTable CRC differs from server.\n");
  312. Disconnect( "HLTV SendTable CRC differs from server.", true );
  313. return false;
  314. }
  315. #ifdef _HLTVTEST
  316. RecvTable_Term( false );
  317. #endif
  318. // Create all of the send tables locally
  319. DataTable_CreateClientTablesFromServerTables();
  320. // Now create all of the server classes locally, too
  321. DataTable_CreateClientClassInfosFromServerClasses( this );
  322. LinkClasses(); // link server and client classes
  323. #ifdef DEDICATED
  324. bool bAllowMismatches = false;
  325. #else
  326. bool bAllowMismatches = ( demoplayer && demoplayer->IsPlayingBack() );
  327. #endif // DEDICATED
  328. if ( !RecvTable_CreateDecoders( serverGameDLL->GetStandardSendProxies(), bAllowMismatches ) ) // create receive table decoders
  329. {
  330. Host_EndGame( true, "CL_ParseClassInfo_EndClasses: CreateDecoders failed.\n" );
  331. return false;
  332. }
  333. return true;
  334. }
  335. void CHLTVClientState::PacketEnd( void )
  336. {
  337. // did we get a snapshot with this packet ?
  338. if ( m_pNewClientFrame )
  339. {
  340. // if so, add a new frame to HLTV
  341. m_pCurrentClientFrame = m_pHLTV->AddNewFrame( m_pNewClientFrame );
  342. delete m_pNewClientFrame; // release own refernces
  343. m_pNewClientFrame = NULL;
  344. }
  345. }
  346. bool CHLTVClientState::HookClientStringTable( char const *tableName )
  347. {
  348. INetworkStringTable *table = GetStringTable( tableName );
  349. if ( !table )
  350. return false;
  351. // Hook instance baseline table
  352. if ( !Q_strcasecmp( tableName, INSTANCE_BASELINE_TABLENAME ) )
  353. {
  354. table->SetStringChangedCallback( m_pHLTV, HLTV_Callback_InstanceBaseline );
  355. return true;
  356. }
  357. return false;
  358. }
  359. void CHLTVClientState::InstallStringTableCallback( char const *tableName )
  360. {
  361. INetworkStringTable *table = GetStringTable( tableName );
  362. if ( !table )
  363. return;
  364. // Hook instance baseline table
  365. if ( !Q_strcasecmp( tableName, INSTANCE_BASELINE_TABLENAME ) )
  366. {
  367. table->SetStringChangedCallback( m_pHLTV, HLTV_Callback_InstanceBaseline );
  368. return;
  369. }
  370. }
  371. bool CHLTVClientState::ProcessSetView( SVC_SetView *msg )
  372. {
  373. if ( !CBaseClientState::ProcessSetView( msg ) )
  374. return false;
  375. return m_pHLTV->SendNetMsg( *msg );
  376. }
  377. bool CHLTVClientState::ProcessVoiceInit( SVC_VoiceInit *msg )
  378. {
  379. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  380. }
  381. bool CHLTVClientState::ProcessVoiceData( SVC_VoiceData *msg )
  382. {
  383. int size = PAD_NUMBER( Bits2Bytes(msg->m_nLength), 4);
  384. byte *buffer = (byte*) stackalloc( size );
  385. msg->m_DataIn.ReadBits( buffer, msg->m_nLength );
  386. msg->m_DataOut = buffer;
  387. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  388. }
  389. bool CHLTVClientState::ProcessSounds(SVC_Sounds *msg)
  390. {
  391. CopyDataInToOut( msg );
  392. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  393. }
  394. bool CHLTVClientState::ProcessPrefetch( SVC_Prefetch *msg )
  395. {
  396. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  397. }
  398. bool CHLTVClientState::ProcessFixAngle( SVC_FixAngle *msg )
  399. {
  400. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  401. }
  402. bool CHLTVClientState::ProcessCrosshairAngle( SVC_CrosshairAngle *msg )
  403. {
  404. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  405. }
  406. bool CHLTVClientState::ProcessBSPDecal( SVC_BSPDecal *msg )
  407. {
  408. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  409. }
  410. bool CHLTVClientState::ProcessGameEvent( SVC_GameEvent *msg )
  411. {
  412. bf_read tmpBuf = msg->m_DataIn;
  413. IGameEvent *event = g_GameEventManager.UnserializeEvent( &tmpBuf );
  414. if ( event )
  415. {
  416. const char *pszName = event->GetName();
  417. bool bDontForward = false;
  418. if ( Q_strcmp( pszName, "hltv_status" ) == 0 )
  419. {
  420. m_pHLTV->m_nGlobalSlots = event->GetInt("slots");;
  421. m_pHLTV->m_nGlobalProxies = event->GetInt("proxies");
  422. m_pHLTV->m_nGlobalClients = event->GetInt("clients");
  423. m_pHLTV->m_RootServer.SetFromString( event->GetString("master") );
  424. bDontForward = true;
  425. }
  426. else if ( Q_strcmp( pszName, "hltv_title" ) == 0 )
  427. {
  428. // ignore title messages
  429. bDontForward = true;
  430. }
  431. // free event resources
  432. g_GameEventManager.FreeEvent( event );
  433. if ( bDontForward )
  434. return true;
  435. }
  436. // forward event
  437. CopyDataInToOut( msg );
  438. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  439. }
  440. bool CHLTVClientState::ProcessGameEventList( SVC_GameEventList *msg )
  441. {
  442. // copy message before processing
  443. SVC_GameEventList tmpMsg = *msg;
  444. CBaseClientState::ProcessGameEventList( &tmpMsg );
  445. CopyDataInToOut( msg );
  446. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  447. }
  448. bool CHLTVClientState::ProcessUserMessage( SVC_UserMessage *msg )
  449. {
  450. CopyDataInToOut( msg );
  451. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  452. }
  453. bool CHLTVClientState::ProcessEntityMessage( SVC_EntityMessage *msg )
  454. {
  455. CopyDataInToOut( msg );
  456. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  457. }
  458. bool CHLTVClientState::ProcessMenu( SVC_Menu *msg )
  459. {
  460. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  461. }
  462. bool CHLTVClientState::ProcessPacketEntities( SVC_PacketEntities *entmsg )
  463. {
  464. CClientFrame *oldFrame = NULL;
  465. #ifdef _HLTVTEST
  466. if ( g_RecvDecoders.Count() == 0 )
  467. return false;
  468. #endif
  469. if ( entmsg->m_bIsDelta )
  470. {
  471. if ( GetServerTickCount() == entmsg->m_nDeltaFrom )
  472. {
  473. Host_Error( "Update self-referencing, connection dropped.\n" );
  474. return false;
  475. }
  476. // Otherwise, mark where we are valid to and point to the packet entities we'll be updating from.
  477. oldFrame = m_pHLTV->GetClientFrame( entmsg->m_nDeltaFrom );
  478. }
  479. // create new empty snapshot
  480. CFrameSnapshot* pSnapshot = framesnapshotmanager->CreateEmptySnapshot( GetServerTickCount(), entmsg->m_nMaxEntries );
  481. Assert( m_pNewClientFrame == NULL );
  482. m_pNewClientFrame = new CClientFrame( pSnapshot );
  483. Assert( entmsg->m_nBaseline >= 0 && entmsg->m_nBaseline < 2 );
  484. if ( entmsg->m_bUpdateBaseline )
  485. {
  486. // server requested to use this snapshot as baseline update
  487. int nUpdateBaseline = (entmsg->m_nBaseline == 0) ? 1 : 0;
  488. CopyEntityBaseline( entmsg->m_nBaseline, nUpdateBaseline );
  489. // send new baseline acknowledgement(as reliable)
  490. CLC_BaselineAck baseline( GetServerTickCount(), entmsg->m_nBaseline );
  491. m_NetChannel->SendNetMsg( baseline, true );
  492. }
  493. // copy classes and serial numbers from current frame
  494. if ( m_pCurrentClientFrame )
  495. {
  496. CFrameSnapshot* pLastSnapshot = m_pCurrentClientFrame->GetSnapshot();
  497. CFrameSnapshotEntry *pEntry = pSnapshot->m_pEntities;
  498. CFrameSnapshotEntry *pLastEntry = pLastSnapshot->m_pEntities;
  499. Assert( pLastSnapshot->m_nNumEntities <= pSnapshot->m_nNumEntities );
  500. for ( int i = 0; i<pLastSnapshot->m_nNumEntities; i++ )
  501. {
  502. pEntry->m_nSerialNumber = pLastEntry->m_nSerialNumber;
  503. pEntry->m_pClass = pLastEntry->m_pClass;
  504. pEntry++;
  505. pLastEntry++;
  506. }
  507. }
  508. CEntityReadInfo u;
  509. u.m_pBuf = &entmsg->m_DataIn;
  510. u.m_pFrom = oldFrame;
  511. u.m_pTo = m_pNewClientFrame;
  512. u.m_bAsDelta = entmsg->m_bIsDelta;
  513. u.m_nHeaderCount = entmsg->m_nUpdatedEntries;
  514. u.m_nBaseline = entmsg->m_nBaseline;
  515. u.m_bUpdateBaselines = entmsg->m_bUpdateBaseline;
  516. ReadPacketEntities( u );
  517. // adjust reference count to be 1
  518. pSnapshot->ReleaseReference();
  519. return CBaseClientState::ProcessPacketEntities( entmsg );
  520. }
  521. bool CHLTVClientState::ProcessTempEntities( SVC_TempEntities *msg )
  522. {
  523. CopyDataInToOut( msg );
  524. return m_pHLTV->SendNetMsg( *msg ); // relay to server
  525. }
  526. void CHLTVClientState::ReadEnterPVS( CEntityReadInfo &u )
  527. {
  528. int iClass = u.m_pBuf->ReadUBitLong( m_nServerClassBits );
  529. int iSerialNum = u.m_pBuf->ReadUBitLong( NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS );
  530. CopyNewEntity( u, iClass, iSerialNum );
  531. if ( u.m_nNewEntity == u.m_nOldEntity ) // that was a recreate
  532. u.NextOldEntity();
  533. }
  534. void CHLTVClientState::ReadLeavePVS( CEntityReadInfo &u )
  535. {
  536. // do nothing, this entity was removed
  537. Assert( !u.m_pTo->transmit_entity.Get(u.m_nOldEntity) );
  538. if ( u.m_UpdateFlags & FHDR_DELETE )
  539. {
  540. CFrameSnapshot *pSnapshot = u.m_pTo->GetSnapshot();
  541. CFrameSnapshotEntry *pEntry = &pSnapshot->m_pEntities[u.m_nOldEntity];
  542. // clear entity references
  543. pEntry->m_nSerialNumber = -1;
  544. pEntry->m_pClass = NULL;
  545. Assert( pEntry->m_pPackedData == INVALID_PACKED_ENTITY_HANDLE );
  546. }
  547. u.NextOldEntity();
  548. }
  549. void CHLTVClientState::ReadDeltaEnt( CEntityReadInfo &u )
  550. {
  551. const int i = u.m_nNewEntity;
  552. CFrameSnapshot *pFromSnapshot = u.m_pFrom->GetSnapshot();
  553. CFrameSnapshot *pSnapshot = u.m_pTo->GetSnapshot();
  554. Assert( i < pFromSnapshot->m_nNumEntities );
  555. pSnapshot->m_pEntities[i] = pFromSnapshot->m_pEntities[i];
  556. PackedEntity *pToPackedEntity = framesnapshotmanager->CreatePackedEntity( pSnapshot, i );
  557. // WARNING! get pFromPackedEntity after new pPackedEntity has been created, otherwise pointer may be wrong
  558. PackedEntity *pFromPackedEntity = framesnapshotmanager->GetPackedEntity( pFromSnapshot, i );
  559. pToPackedEntity->SetServerAndClientClass( pFromPackedEntity->m_pServerClass, pFromPackedEntity->m_pClientClass );
  560. // create a copy of the pFromSnapshot ChangeFrameList
  561. IChangeFrameList* pChangeFrame = NULL;
  562. if ( !m_bSaveMemory )
  563. {
  564. pChangeFrame = pFromPackedEntity->GetChangeFrameList()->Copy();
  565. pToPackedEntity->SetChangeFrameList( pChangeFrame );
  566. }
  567. // Make space for the baseline data.
  568. ALIGN4 char packedData[MAX_PACKEDENTITY_DATA] ALIGN4_POST;
  569. const void *pFromData;
  570. int nFromBits;
  571. if ( pFromPackedEntity->IsCompressed() )
  572. {
  573. pFromData = m_pHLTV->UncompressPackedEntity( pFromPackedEntity, nFromBits );
  574. }
  575. else
  576. {
  577. pFromData = pFromPackedEntity->GetData();
  578. nFromBits = pFromPackedEntity->GetNumBits();
  579. }
  580. bf_read fromBuf( "HLTV_ReadEnterPVS1", pFromData, Bits2Bytes( nFromBits ), nFromBits );
  581. bf_write writeBuf( "HLTV_ReadEnterPVS2", packedData, sizeof( packedData ) );
  582. int changedProps[MAX_DATATABLE_PROPS];
  583. // decode baseline, is compressed against zero values
  584. int nChangedProps = RecvTable_MergeDeltas( pToPackedEntity->m_pClientClass->m_pRecvTable,
  585. &fromBuf, u.m_pBuf, &writeBuf, -1, changedProps, false );
  586. // update change tick in ChangeFrameList
  587. if ( pChangeFrame )
  588. {
  589. pChangeFrame->SetChangeTick( changedProps, nChangedProps, pSnapshot->m_nTickCount );
  590. }
  591. if ( m_bSaveMemory )
  592. {
  593. int bits = writeBuf.GetNumBitsWritten();
  594. const char *compressedData = m_pHLTV->CompressPackedEntity(
  595. pToPackedEntity->m_pServerClass,
  596. (char*)writeBuf.GetData(),
  597. bits );
  598. // store as compressed data and don't use mem pools
  599. pToPackedEntity->AllocAndCopyPadded( compressedData, Bits2Bytes(bits) );
  600. pToPackedEntity->SetCompressed();
  601. }
  602. else
  603. {
  604. // store as normal
  605. pToPackedEntity->AllocAndCopyPadded( packedData, writeBuf.GetNumBytesWritten() );
  606. }
  607. u.m_pTo->last_entity = u.m_nNewEntity;
  608. u.m_pTo->transmit_entity.Set( u.m_nNewEntity );
  609. u.NextOldEntity();
  610. }
  611. void CHLTVClientState::ReadPreserveEnt( CEntityReadInfo &u )
  612. {
  613. // copy one of the old entities over to the new packet unchanged
  614. // XXX(JohnS): This was historically checking for NewEntity overflow, though this path does not care (and new entity
  615. // may be -1). The old entity bounds check here seems like what was intended, but since nNewEntity
  616. // should not be overflowed either, I've left that check in case it was guarding against a case I am
  617. // overlooking.
  618. if ( u.m_nOldEntity >= MAX_EDICTS || u.m_nOldEntity < 0 || u.m_nNewEntity >= MAX_EDICTS )
  619. {
  620. Host_Error( "CL_ReadPreserveEnt: Entity out of bounds. Old: %i, New: %i",
  621. u.m_nOldEntity, u.m_nNewEntity );
  622. }
  623. HLTV_CopyExitingEnt( u );
  624. u.NextOldEntity();
  625. }
  626. void CHLTVClientState::ReadDeletions( CEntityReadInfo &u )
  627. {
  628. while ( u.m_pBuf->ReadOneBit()!=0 )
  629. {
  630. int idx = u.m_pBuf->ReadUBitLong( MAX_EDICT_BITS );
  631. Assert( !u.m_pTo->transmit_entity.Get( idx ) );
  632. CFrameSnapshot *pSnapshot = u.m_pTo->GetSnapshot();
  633. CFrameSnapshotEntry *pEntry = &pSnapshot->m_pEntities[idx];
  634. // clear entity references
  635. pEntry->m_nSerialNumber = -1;
  636. pEntry->m_pClass = NULL;
  637. Assert( pEntry->m_pPackedData == INVALID_PACKED_ENTITY_HANDLE );
  638. }
  639. }
  640. int CHLTVClientState::GetConnectionRetryNumber() const
  641. {
  642. if ( tv_autoretry.GetBool() )
  643. {
  644. // in autoretry mode try extra long
  645. return CL_CONNECTION_RETRIES * 4;
  646. }
  647. else
  648. {
  649. return CL_CONNECTION_RETRIES;
  650. }
  651. }
  652. void CHLTVClientState::ConnectionCrashed(const char *reason)
  653. {
  654. CBaseClientState::ConnectionCrashed( reason );
  655. if ( tv_autoretry.GetBool() && m_szRetryAddress[0] )
  656. {
  657. Cbuf_AddText( va( "tv_relay %s\n", m_szRetryAddress ) );
  658. }
  659. }
  660. void CHLTVClientState::ConnectionClosing( const char *reason )
  661. {
  662. CBaseClientState::ConnectionClosing( reason );
  663. if ( tv_autoretry.GetBool() && m_szRetryAddress[0] )
  664. {
  665. Cbuf_AddText( va( "tv_relay %s\n", m_szRetryAddress ) );
  666. }
  667. }
  668. void CHLTVClientState::RunFrame()
  669. {
  670. CBaseClientState::RunFrame();
  671. if ( m_NetChannel && m_NetChannel->IsTimedOut() && IsConnected() )
  672. {
  673. ConMsg ("\nSourceTV connection timed out.\n");
  674. Disconnect( "nSourceTV connection timed out", true );
  675. return;
  676. }
  677. UpdateStats();
  678. }
  679. void CHLTVClientState::UpdateStats()
  680. {
  681. if ( m_nSignonState < SIGNONSTATE_FULL )
  682. {
  683. m_fNextSendUpdateTime = 0.0f;
  684. return;
  685. }
  686. if ( m_fNextSendUpdateTime > net_time )
  687. return;
  688. m_fNextSendUpdateTime = net_time + 8.0f;
  689. int proxies, slots, clients;
  690. m_pHLTV->GetRelayStats( proxies, slots, clients );
  691. proxies += 1; // add self to number of proxies
  692. slots += m_pHLTV->GetMaxClients(); // add own slots
  693. clients += m_pHLTV->GetNumClients(); // add own clients
  694. NET_SetConVar conVars;
  695. NET_SetConVar::cvar_t acvar;
  696. Q_strncpy( acvar.name, "hltv_proxies", sizeof(acvar.name) );
  697. Q_snprintf( acvar.value, sizeof(acvar.value), "%d", proxies );
  698. conVars.m_ConVars.AddToTail( acvar );
  699. Q_strncpy( acvar.name, "hltv_clients", sizeof(acvar.name) );
  700. Q_snprintf( acvar.value, sizeof(acvar.value), "%d", clients );
  701. conVars.m_ConVars.AddToTail( acvar );
  702. Q_strncpy( acvar.name, "hltv_slots", sizeof(acvar.name) );
  703. Q_snprintf( acvar.value, sizeof(acvar.value), "%d", slots );
  704. conVars.m_ConVars.AddToTail( acvar );
  705. Q_strncpy( acvar.name, "hltv_addr", sizeof(acvar.name) );
  706. Q_snprintf( acvar.value, sizeof(acvar.value), "%s:%u", net_local_adr.ToString(true), m_pHLTV->GetUDPPort() );
  707. conVars.m_ConVars.AddToTail( acvar );
  708. m_NetChannel->SendNetMsg( conVars );
  709. }