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.

997 lines
27 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #ifndef DEDICATED
  7. #include "screen.h"
  8. #include "cl_main.h"
  9. #include "iprediction.h"
  10. #include "proto_oob.h"
  11. #include "demo.h"
  12. #include "tier0/icommandline.h"
  13. #include "ispatialpartitioninternal.h"
  14. #include "GameEventManager.h"
  15. #include "cdll_engine_int.h"
  16. #include "voice.h"
  17. #include "host_cmd.h"
  18. #include "server.h"
  19. #include "convar.h"
  20. #include "dt_recv_eng.h"
  21. #include "dt_common_eng.h"
  22. #include "LocalNetworkBackdoor.h"
  23. #include "vox.h"
  24. #include "sound.h"
  25. #include "r_efx.h"
  26. #include "r_local.h"
  27. #include "decal_private.h"
  28. #include "vgui_baseui_interface.h"
  29. #include "host_state.h"
  30. #include "cl_ents_parse.h"
  31. #include "eiface.h"
  32. #include "server.h"
  33. #include "cl_demoactionmanager.h"
  34. #include "decal.h"
  35. #include "r_decal.h"
  36. #include "materialsystem/imaterial.h"
  37. #include "EngineSoundInternal.h"
  38. #include "master.h"
  39. #include "ivideomode.h"
  40. #include "download.h"
  41. #include "GameUI/IGameUI.h"
  42. #if defined( REPLAY_ENABLED )
  43. #include "replayhistorymanager.h"
  44. #endif
  45. #include "cl_demo.h"
  46. #include "audio_pch.h"
  47. #include "paint.h"
  48. // memdbgon must be the last include file in a .cpp file!!!
  49. #include "tier0/memdbgon.h"
  50. extern IVEngineClient *engineClient;
  51. extern CNetworkStringTableContainer *networkStringTableContainerClient;
  52. extern CNetworkStringTableContainer *networkStringTableContainerServer;
  53. static ConVar cl_allowupload ( "cl_allowupload", "1", FCVAR_ARCHIVE, "Client uploads customization files" );
  54. static ConVar cl_voice_filter( "cl_voice_filter", "", 0, "Filter voice by name substring" ); // filter incoming voice data
  55. ConVar cl_voice_hltv_buffer_time("cl_voice_hltv_buffer_time", "0.3", 0, "Amount of time between receiving voice data and playing the audio in hltv");
  56. ConVar cl_voice_buffer_time("cl_voice_buffer_time", "0.04", 0, "Amount of time between receiving voice data and playing the audio");
  57. extern ConCommand quit;
  58. void CClientState::ConnectionClosing( const char * reason )
  59. {
  60. // if connected, shut down host
  61. if ( m_nSignonState > SIGNONSTATE_NONE )
  62. {
  63. ConMsg( "Disconnect: %s.\n", reason );
  64. if ( !Q_stricmp( reason, INVALID_STEAM_TICKET ) )
  65. {
  66. g_eSteamLoginFailure = STEAMLOGINFAILURE_BADTICKET;
  67. }
  68. else if ( !Q_stricmp( reason, INVALID_STEAM_LOGON ) )
  69. {
  70. g_eSteamLoginFailure = STEAMLOGINFAILURE_NOSTEAMLOGIN;
  71. }
  72. else if ( !Q_stricmp( reason, INVALID_STEAM_LOGGED_IN_ELSEWHERE ) )
  73. {
  74. g_eSteamLoginFailure = STEAMLOGINFAILURE_LOGGED_IN_ELSEWHERE;
  75. }
  76. else if ( !Q_stricmp( reason, INVALID_STEAM_VACBANSTATE ) )
  77. {
  78. g_eSteamLoginFailure = STEAMLOGINFAILURE_VACBANNED;
  79. }
  80. else
  81. {
  82. g_eSteamLoginFailure = STEAMLOGINFAILURE_NONE;
  83. }
  84. // If the reason is a localized string, pass it raw.
  85. if ( reason && reason[0] == '#' )
  86. COM_ExplainDisconnection( true, "%s", reason );
  87. else
  88. COM_ExplainDisconnection( true, "Disconnect: %s.\n", reason );
  89. SCR_EndLoadingPlaque();
  90. Host_Disconnect(true);
  91. if ( (reason != NULL) && (Q_stricmp( reason, "Server shutting down" ) == 0) && //if disconnect reason is server shutdown
  92. (CommandLine()->FindParm( "-quitonservershutdown" ) != 0) ) //and we want to quit the game whenever the server shuts down (assists quick iteration)
  93. {
  94. Host_Shutdown(); //quit the game
  95. }
  96. }
  97. }
  98. void CClientState::ConnectionCrashed( const char * reason )
  99. {
  100. // if connected, shut down host
  101. if ( m_nSignonState > SIGNONSTATE_NONE )
  102. {
  103. // If the reason is a localized string, pass it raw.
  104. if(reason && reason[0] == '#')
  105. COM_ExplainDisconnection( true, "%s", reason );
  106. else
  107. COM_ExplainDisconnection( true, "Disconnect: %s.\n", reason );
  108. SCR_EndLoadingPlaque();
  109. Host_Disconnect(true);
  110. }
  111. }
  112. void CClientState::FileRequested(const char *fileName, unsigned int transferID, bool isReplayDemoFile )
  113. {
  114. ConMsg( "File '%s' requested from server %s.\n", fileName, m_NetChannel->GetAddress() );
  115. if ( !cl_allowupload.GetBool() )
  116. {
  117. ConMsg( "File uploading disabled.\n" );
  118. m_NetChannel->DenyFile( fileName, transferID, isReplayDemoFile );
  119. return;
  120. }
  121. // TODO check if file valid for uploading
  122. m_NetChannel->SendFile( fileName, transferID, isReplayDemoFile );
  123. }
  124. void CClientState::FileReceived( const char * fileName, unsigned int transferID, bool isReplayDemoFile )
  125. {
  126. // check if the client donwload manager requested this file
  127. CL_FileReceived( fileName, transferID, isReplayDemoFile );
  128. }
  129. void CClientState::FileDenied(const char *fileName, unsigned int transferID, bool isReplayDemoFile )
  130. {
  131. // check if the file download manager requested that file
  132. CL_FileDenied( fileName, transferID, isReplayDemoFile );
  133. }
  134. void CClientState::PacketStart( int incoming_sequence, int outgoing_acknowledged )
  135. {
  136. // Ack'd incoming messages.
  137. m_nCurrentSequence = incoming_sequence;
  138. command_ack = outgoing_acknowledged;
  139. }
  140. void CClientState::PacketEnd()
  141. {
  142. //
  143. // we don't know if it is ok to save a demo message until
  144. // after we have parsed the frame
  145. //
  146. // Play any sounds we received this packet
  147. CL_DispatchSounds();
  148. // Did we get any messages this tick (i.e., did we call PreEntityPacketReceived)?
  149. if ( GetServerTickCount() != m_nDeltaTick )
  150. return;
  151. // How many commands total did we run this frame
  152. int commands_acknowledged = command_ack - last_command_ack;
  153. // COM_Log( "GetBaseLocalClient().log", "Server ack'd %i commands this frame\n", commands_acknowledged );
  154. //Msg( "%i/%i CL_PostReadMessages: last ack %i most recent %i acked %i commands\n",
  155. // host_framecount, GetBaseLocalClient().tickcount,
  156. // GetBaseLocalClient().last_command_ack,
  157. // GetBaseLocalClient().netchan->outgoing_sequence - 1,
  158. // commands_acknowledged );
  159. // Highest command parsed from messages
  160. last_command_ack = command_ack;
  161. last_server_tick = GetServerTickCount();
  162. // Let prediction copy off pristine data and report any errors, etc.
  163. g_pClientSidePrediction->PostNetworkDataReceived( commands_acknowledged );
  164. demoaction->DispatchEvents();
  165. }
  166. void CClientState::Disconnect( bool bShowMainMenu )
  167. {
  168. CBaseClientState::Disconnect( bShowMainMenu );
  169. if ( m_bSplitScreenUser )
  170. return;
  171. // clear any map hacks
  172. {
  173. static ConVarRef map_wants_save_disable( "map_wants_save_disable" );
  174. map_wants_save_disable.SetValue( 0 );
  175. }
  176. // stop any demo activities
  177. demoplayer->StopPlayback();
  178. demorecorder->StopRecording();
  179. #if defined( REPLAY_ENABLED )
  180. extern IReplayHistoryManager *g_pClientReplayHistoryManager;
  181. g_pClientReplayHistoryManager->StopDownloads();
  182. #endif
  183. S_StopAllSounds( true );
  184. R_DecalTermAll();
  185. if ( m_nMaxClients > 1 )
  186. {
  187. if ( EngineVGui()->IsConsoleVisible() == false )
  188. {
  189. // start progress bar immediately for multiplayer level transitions
  190. EngineVGui()->EnabledProgressBarForNextLoad();
  191. }
  192. }
  193. CL_ClearState();
  194. // End any in-progress downloads
  195. CL_HTTPStop_f();
  196. // stop loading progress bar
  197. if ( bShowMainMenu )
  198. {
  199. SCR_EndLoadingPlaque();
  200. }
  201. // notify game ui dll of out-of-in-game status
  202. EngineVGui()->NotifyOfServerDisconnect();
  203. HostState_OnClientDisconnected();
  204. // if we played a demo from the startdemos list, play next one
  205. if ( GetBaseLocalClient().demonum != -1 )
  206. {
  207. CL_NextDemo();
  208. }
  209. }
  210. static bool s_bClientWaitingForHltvReplayTick = false;
  211. bool CClientState::NETMsg_Tick( const CNETMsg_Tick& msg )
  212. {
  213. if ( g_ClientDLL )
  214. {
  215. // Notify the client that we are just about to tick over.
  216. g_ClientDLL->OnTickPre( host_tickcount );
  217. }
  218. int tick = msg.tick();
  219. {
  220. if ( m_nHltvReplayDelay )
  221. {
  222. if ( !msg.hltv_replay_flags() )
  223. DevMsg( "%d. Msg_Tick %d cl:delayed sv:real-time\n", GetClientTickCount(), tick );
  224. }
  225. else
  226. {
  227. if ( msg.hltv_replay_flags() )
  228. DevMsg( "%d. Msg_Tick %d cl:real-time sv:replay\n", GetClientTickCount(), tick );
  229. }
  230. }
  231. if ( m_nHltvReplayDelay && !msg.hltv_replay_flags() )
  232. {
  233. // client is in hltv replay state, but server doesn't remember it - maybe there was a connection issue or something.
  234. DevMsg( "Inconsistent Client Replay state: tick without replay during replay. Force Stop Replay.\n" );
  235. s_bClientWaitingForHltvReplayTick = true;
  236. StopHltvReplay();
  237. }
  238. m_NetChannel->SetRemoteFramerate(
  239. CNETMsg_Tick_t::FrametimeToFloat( msg.host_computationtime() ),
  240. CNETMsg_Tick_t::FrametimeToFloat( msg.host_computationtime_std_deviation() ),
  241. CNETMsg_Tick_t::FrametimeToFloat( msg.host_framestarttime_std_deviation() ) );
  242. m_ClockDriftMgr.SetServerTick( tick );
  243. // Remember this for GetLastTimeStamp().
  244. m_flLastServerTickTime = tick * host_state.interval_per_tick;
  245. // Use the server tick while reading network data (used for interpolation samples, etc).
  246. g_ClientGlobalVariables.tickcount = tick;
  247. g_ClientGlobalVariables.curtime = tick * host_state.interval_per_tick;
  248. g_ClientGlobalVariables.frametime = (tick - oldtickcount) * host_state.interval_per_tick; // We used to call GetFrameTime() here, but 'insimulation' is always
  249. // true so we have this code right in here to keep it simple.
  250. if ( s_bClientWaitingForHltvReplayTick && g_ClientDLL )
  251. {
  252. if ( m_nHltvReplayDelay )
  253. {
  254. // we're starting replay. Clean up decals from the future
  255. R_DecalTermNew( host_state.worldmodel->brush.pShared, tick );
  256. }
  257. g_ClientDLL->OnHltvReplayTick();
  258. s_bClientWaitingForHltvReplayTick = false;
  259. }
  260. return true;
  261. }
  262. bool CClientState::NETMsg_StringCmd( const CNETMsg_StringCmd& msg )
  263. {
  264. // Even though this is just forwarding to the base class, do not remove this function.
  265. // There are multiple implementations of CClientState and the one in cl_null.cpp
  266. // stubs this function out as a simple 'return true;'.
  267. return BaseClass::NETMsg_StringCmd( msg );
  268. }
  269. bool CClientState::SVCMsg_ServerInfo( const CSVCMsg_ServerInfo& msg )
  270. {
  271. // Reset client state
  272. CL_ClearState();
  273. if ( !CBaseClientState::SVCMsg_ServerInfo( msg ) )
  274. {
  275. Disconnect(true);
  276. return false;
  277. }
  278. if ( demoplayer->IsPlayingBack() )
  279. {
  280. // Because a server doesn't run during
  281. // demoplayback, but the decal system relies on this...
  282. m_nServerCount = gHostSpawnCount;
  283. }
  284. else
  285. {
  286. // tell demo recorder that new map is loaded and we are receiving
  287. // it's signon data (will be written into extra demo header file)
  288. demorecorder->SetSignonState( SIGNONSTATE_NEW );
  289. }
  290. // is server a HLTV proxy ?
  291. ishltv = msg.is_hltv();
  292. #if defined( REPLAY_ENABLED )
  293. // is server a replay proxy ?
  294. isreplay = msg.is_replay();
  295. #endif
  296. // The CRC of the server map must match the CRC of the client map. or else
  297. // the client is probably cheating.
  298. serverCRC = msg.map_crc();
  299. // The client side DLL CRC check.
  300. serverClientSideDllCRC = msg.client_crc();
  301. g_ClientGlobalVariables.maxClients = m_nMaxClients;
  302. g_ClientGlobalVariables.network_protocol = msg.protocol();
  303. #ifdef SHARED_NET_STRING_TABLES
  304. // use same instance of StringTableContainer as the server does
  305. m_StringTableContainer = networkStringTableContainerServer;
  306. CL_HookClientStringTables();
  307. #else
  308. // use own instance of StringTableContainer
  309. m_StringTableContainer = networkStringTableContainerClient;
  310. #endif
  311. CL_ReallocateDynamicData( m_nMaxClients );
  312. if ( sv.IsPaused() )
  313. {
  314. if ( msg.tick_interval() != host_state.interval_per_tick )
  315. {
  316. Host_Error( "Expecting interval_per_tick %f, got %f\n",
  317. host_state.interval_per_tick, msg.tick_interval() );
  318. return false;
  319. }
  320. }
  321. else
  322. {
  323. host_state.interval_per_tick = msg.tick_interval();
  324. }
  325. // Re-init hud video, especially if we changed game directories
  326. ClientDLL_HudVidInit();
  327. // Don't verify the map and player .mdl crc's until after any missing resources have
  328. // been downloaded. This will still occur before requesting the rest of the signon.
  329. gHostSpawnCount = m_nServerCount;
  330. videomode->MarkClientViewRectDirty(); // leave intermission full screen
  331. return true;
  332. }
  333. bool CClientState::SVCMsg_ClassInfo( const CSVCMsg_ClassInfo& msg )
  334. {
  335. if ( msg.create_on_client() )
  336. {
  337. if ( !demoplayer->IsPlayingBack() )
  338. {
  339. // Create all of the send tables locally
  340. DataTable_CreateClientTablesFromServerTables();
  341. // Now create all of the server classes locally, too
  342. DataTable_CreateClientClassInfosFromServerClasses( this );
  343. // store the current data tables in demo file to make sure
  344. // they are the same during playback
  345. demorecorder->RecordServerClasses( serverGameDLL->GetAllServerClasses() );
  346. }
  347. LinkClasses(); // link server and client classes
  348. }
  349. else
  350. {
  351. CBaseClientState::SVCMsg_ClassInfo( msg );
  352. }
  353. bool bAllowMismatches = ( g_pClientDemoPlayer && g_pClientDemoPlayer->IsPlayingBack() );
  354. if ( !RecvTable_CreateDecoders( serverGameDLL->GetStandardSendProxies(), bAllowMismatches ) ) // create receive table decoders
  355. {
  356. Host_EndGame( true, "CL_ParseClassInfo_EndClasses: CreateDecoders failed.\n" );
  357. return false;
  358. }
  359. if ( !demoplayer->IsPlayingBack() )
  360. {
  361. CLocalNetworkBackdoor::InitFastCopy();
  362. }
  363. return true;
  364. }
  365. bool CClientState::SVCMsg_SetPause( const CSVCMsg_SetPause& msg )
  366. {
  367. CBaseClientState::SVCMsg_SetPause( msg );
  368. return true;
  369. }
  370. bool CClientState::SVCMsg_VoiceInit( const CSVCMsg_VoiceInit& msg )
  371. {
  372. #if !defined( NO_VOICE )
  373. if( msg.codec().size() == 0 )
  374. {
  375. Voice_Deinit();
  376. }
  377. else
  378. {
  379. #define SPEEX_QUALITY 4
  380. Voice_Init( msg.codec().c_str(), msg.has_version() ? msg.version() : SPEEX_QUALITY );
  381. }
  382. #endif
  383. return true;
  384. }
  385. ConVar voice_debugfeedback( "voice_debugfeedback", "0" );
  386. bool CClientState::SVCMsg_VoiceData( const CSVCMsg_VoiceData &msg )
  387. {
  388. #if defined ( _GAMECONSOLE )
  389. FOR_EACH_VALID_SPLITSCREEN_PLAYER( i )
  390. {
  391. if ( msg.client() == GetLocalClient( i ).m_nPlayerSlot )
  392. return true;
  393. }
  394. ConVarRef voice_verbose( "voice_verbose" );
  395. if ( voice_verbose.GetBool() )
  396. {
  397. Msg( "* CClientState::ProcessVoiceData: playing SVC_VoiceData from %s with %u bytes\n", msg.GetNetChannel()->GetAddress(), msg.voice_data_size() );
  398. }
  399. Audio_GetXVoice()->PlayIncomingVoiceData( msg.xuid(), (const byte*)&msg.voice_data[0], msg.voice_data_size(), bAudible );
  400. if ( voice_debugfeedback.GetBool() )
  401. {
  402. Msg( "%f Received voice from: %d [%d bytes]\n", realtime, msg->m_nFromClient + 1, dwLength );
  403. }
  404. return true;
  405. #endif
  406. #if !defined( NO_VOICE )
  407. if ( voice_debugfeedback.GetBool() )
  408. {
  409. Msg( "Received voice from: %d\n", msg.client() + 1 );
  410. }
  411. int iEntity = msg.client() + 1;
  412. if ( iEntity == (m_nPlayerSlot + 1) )
  413. {
  414. Voice_LocalPlayerTalkingAck( m_nSplitScreenSlot );
  415. }
  416. player_info_t playerinfo;
  417. engineClient->GetPlayerInfo( iEntity, &playerinfo );
  418. CSteamID voicePlayer( playerinfo.xuid );
  419. if ( Q_strlen( cl_voice_filter.GetString() ) > 0 && Q_strstr( playerinfo.name, cl_voice_filter.GetString() ) == NULL )
  420. return true;
  421. // Data length can be zero when the server is just acking a client's voice data.
  422. if ( msg.voice_data().size() == 0 )
  423. return true;
  424. if ( !Voice_SystemEnabled() )
  425. return true;
  426. bool bIsCaster = msg.has_caster() && msg.caster();
  427. // if this voice data is for a caster that is not enabled, then bail
  428. if ( bIsCaster && !Voice_CasterEnabled( voicePlayer.GetAccountID() ) )
  429. return true;
  430. // if voice is enabled or it's a caster and caster voice is enabled.
  431. if ( Voice_Enabled() || ( Voice_CasterEnabled( voicePlayer.GetAccountID() ) && bIsCaster ) )
  432. {
  433. // Have we already initialized the channels for this guy?
  434. int nChannel = Voice_GetChannel( iEntity );
  435. if ( nChannel == VOICE_CHANNEL_ERROR )
  436. {
  437. // Create a channel in the voice engine and a channel in the sound engine for this guy.
  438. float flBufferTime = GetBaseLocalClient().ishltv ? cl_voice_hltv_buffer_time.GetFloat() : cl_voice_buffer_time.GetFloat();
  439. nChannel = Voice_AssignChannel( iEntity, msg.proximity(), bIsCaster, flBufferTime );
  440. if ( nChannel == VOICE_CHANNEL_ERROR )
  441. {
  442. // If they used -nosound, then it's not a problem.
  443. if ( S_IsInitted() )
  444. {
  445. ConDMsg( "ProcessVoiceData: Voice_AssignChannel failed for client %d!\n", iEntity - 1 );
  446. }
  447. return true;
  448. }
  449. }
  450. // Give the voice engine the data (it in turn gives it to the mixer for the sound engine).
  451. Voice_AddIncomingData( nChannel,
  452. &msg.voice_data()[0],
  453. msg.voice_data().size(),
  454. msg.has_section_number() ? msg.section_number() : 0,
  455. msg.has_sequence_bytes() ? msg.sequence_bytes() : 0,
  456. msg.has_uncompressed_sample_offset() ? msg.uncompressed_sample_offset() : 0,
  457. ( msg.has_format() && ( msg.format() == VOICEDATA_FORMAT_STEAM ) ) ? VoiceFormat_Steam : VoiceFormat_Engine );
  458. }
  459. #endif
  460. return true;
  461. };
  462. bool CClientState::SVCMsg_Prefetch( const CSVCMsg_Prefetch& msg )
  463. {
  464. char const *soundname = GetBaseLocalClient().GetSoundName( msg.sound_index() );
  465. if ( soundname && soundname [ 0 ] )
  466. {
  467. EngineSoundClient()->PrefetchSound( soundname );
  468. }
  469. return true;
  470. }
  471. bool CClientState::SVCMsg_Sounds( const CSVCMsg_Sounds& msg )
  472. {
  473. SoundInfo_t defaultSound;
  474. SoundInfo_t *pDeltaSound = &defaultSound;
  475. SoundInfo_t sound;
  476. int nNumSounds = msg.sounds_size();
  477. for ( int i=0; i<nNumSounds; i++ )
  478. {
  479. const CSVCMsg_Sounds::sounddata_t& SoundData = msg.sounds( i );
  480. sound.ReadDelta( pDeltaSound, SoundData );
  481. pDeltaSound = &sound; // copy delta values
  482. if ( msg.reliable_sound() )
  483. {
  484. // client is incrementing the reliable sequence numbers itself
  485. m_nSoundSequence = ( m_nSoundSequence + 1 ) & SOUND_SEQNUMBER_MASK;
  486. Assert ( sound.nSequenceNumber == 0 );
  487. sound.nSequenceNumber = m_nSoundSequence;
  488. }
  489. // Add all received sounds to sorted queue (sounds may arrive in multiple messages),
  490. // will be processed after all packets have been completely parsed
  491. CL_AddSound( sound );
  492. }
  493. // check given length against read bits
  494. return true;
  495. }
  496. bool CClientState::SVCMsg_FixAngle( const CSVCMsg_FixAngle &msg )
  497. {
  498. const CMsgQAngle& angle = msg.angle();
  499. QAngle qangle( angle.x(), angle.y(), angle.z() );
  500. for (int i=0 ; i<3 ; i++)
  501. {
  502. // Clamp between -180 and 180
  503. if (qangle[i]>180)
  504. {
  505. qangle[i] -= 360;
  506. }
  507. }
  508. if ( msg.relative() )
  509. {
  510. // Update running counter
  511. addangletotal += qangle[YAW];
  512. AddAngle a;
  513. a.total = addangletotal;
  514. a.starttime = m_flLastServerTickTime;
  515. addangle.AddToTail( a );
  516. }
  517. else
  518. {
  519. viewangles = qangle;
  520. }
  521. return true;
  522. }
  523. bool CClientState::SVCMsg_CrosshairAngle( const CSVCMsg_CrosshairAngle& msg )
  524. {
  525. const CMsgQAngle& angle = msg.angle();
  526. const QAngle qangle( angle.x(), angle.y(), angle.z() );
  527. g_ClientDLL->SetCrosshairAngle( qangle );
  528. return true;
  529. }
  530. bool CClientState::SVCMsg_BSPDecal( const CSVCMsg_BSPDecal& msg )
  531. {
  532. model_t * model;
  533. if ( msg.entity_index() )
  534. {
  535. model = GetModel( msg.model_index() );
  536. }
  537. else
  538. {
  539. model = host_state.worldmodel;
  540. if ( !model )
  541. {
  542. Warning( "ProcessBSPDecal: Trying to project on world before host_state.worldmodel is set!!!\n" );
  543. }
  544. }
  545. if ( model == NULL )
  546. {
  547. IMaterial *mat = Draw_DecalMaterial( msg.decal_texture_index() );
  548. char const *matname = "???";
  549. if ( mat )
  550. {
  551. matname = mat->GetName();
  552. }
  553. Warning( "Warning! Static BSP decal (%s), on NULL model index %i for entity index %i.\n",
  554. matname,
  555. msg.model_index(),
  556. msg.entity_index() );
  557. return true;
  558. }
  559. if (r_decals.GetInt())
  560. {
  561. const CMsgVector& pos = msg.pos();
  562. const Vector vecPos( pos.x(), pos.y(), pos.z() );
  563. g_pEfx->DecalShoot(
  564. msg.decal_texture_index(),
  565. msg.entity_index(),
  566. model,
  567. vec3_origin,
  568. vec3_angle,
  569. vecPos,
  570. NULL,
  571. msg.low_priority() ? 0 : FDECAL_PERMANENT );
  572. }
  573. return true;
  574. }
  575. bool CClientState::SVCMsg_GameEvent(const CSVCMsg_GameEvent& msg)
  576. {
  577. IGameEvent *event = g_GameEventManager.UnserializeEvent( msg );
  578. if ( !event )
  579. {
  580. DevMsg("CClientState::ProcessGameEvent: UnserializeKeyValue failed.\n" );
  581. return true;
  582. }
  583. if ( msg.passthrough() == 1 )
  584. {
  585. // this should only come to clients while they have replay in progress
  586. event->SetBool( "realtime_passthrough", true );
  587. }
  588. g_GameEventManager.FireEventClientSide( event );
  589. return true;
  590. }
  591. bool CClientState::SVCMsg_UserMessage( const CSVCMsg_UserMessage &msg)
  592. {
  593. if ( !g_ClientDLL->DispatchUserMessage( msg.msg_type(), msg.passthrough(), msg.msg_data().size(), &msg.msg_data()[0] ) )
  594. {
  595. ConMsg( "Couldn't dispatch user message (%i)\n", msg.msg_type() );
  596. return false;
  597. }
  598. return true;
  599. }
  600. bool CClientState::SVCMsg_EntityMsg( const CSVCMsg_EntityMsg& msg )
  601. {
  602. // Look up entity
  603. IClientNetworkable *entity = entitylist->GetClientNetworkable( msg.ent_index() );
  604. if ( !entity )
  605. {
  606. int idx = queuedmessage.AddToTail();
  607. CQueuedEntityMessage *pMessage = &queuedmessage[idx];
  608. pMessage->m_msg.CopyFrom( msg );
  609. return true;
  610. }
  611. // route to entity
  612. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  613. bf_read entMsg;
  614. entMsg.StartReading( msg.ent_data().data(), msg.ent_data().size() );
  615. entity->ReceiveMessage( msg.class_id(), entMsg );
  616. return true;
  617. }
  618. bool CClientState::SVCMsg_PacketEntities( const CSVCMsg_PacketEntities &msg )
  619. {
  620. CL_PreprocessEntities(); // setup client prediction
  621. if ( !msg.is_delta() )
  622. {
  623. // Delta too old or is initial message
  624. // we can start recording now that we've received an uncompressed packet
  625. demorecorder->SetSignonState( SIGNONSTATE_FULL );
  626. // Tell prediction that we're recreating entities due to an uncompressed packet arriving
  627. if ( g_pClientSidePrediction )
  628. {
  629. g_pClientSidePrediction->OnReceivedUncompressedPacket();
  630. }
  631. }
  632. else
  633. {
  634. if ( m_nDeltaTick == -1 )
  635. {
  636. // we requested a full update but still got a delta compressed packet. ignore it.
  637. return true;
  638. }
  639. }
  640. TRACE_PACKET(( "CL Receive (%d <-%d)\n", m_nCurrentSequence, msg.delta_from() ));
  641. TRACE_PACKET(( "CL Num Ents (%d)\n", msg.updated_entries() ));
  642. if ( g_pLocalNetworkBackdoor )
  643. {
  644. if ( m_nSignonState == SIGNONSTATE_SPAWN )
  645. {
  646. // We are done with signon sequence.
  647. SetSignonState( SIGNONSTATE_FULL, m_nServerCount, NULL );
  648. }
  649. // ignore message, all entities are transmitted using fast local memcopy routines
  650. m_nDeltaTick = GetServerTickCount();
  651. return true;
  652. }
  653. if ( !CL_ProcessPacketEntities( msg ) )
  654. return false;
  655. return CBaseClientState::SVCMsg_PacketEntities( msg );
  656. }
  657. bool CClientState::SVCMsg_TempEntities( const CSVCMsg_TempEntities &msg )
  658. {
  659. bool bReliable = msg.reliable();
  660. float fire_time = GetBaseLocalClient().GetTime();
  661. // delay firing temp ents by cl_interp in multiplayer or demoplayback
  662. if ( GetBaseLocalClient().m_nMaxClients > 1 || demoplayer->IsPlayingBack() )
  663. {
  664. float flInterpAmount = GetClientInterpAmount();
  665. fire_time += flInterpAmount;
  666. }
  667. int numEntries = msg.num_entries();
  668. if ( numEntries == 0 )
  669. {
  670. bReliable = true;
  671. numEntries = 1;
  672. }
  673. int flags = bReliable ? FEV_RELIABLE : 0;
  674. // Don't actually queue unreliable events if playing a demo and skipping ahead
  675. if ( !bReliable && demoplayer->IsSkipping() )
  676. {
  677. return true;
  678. }
  679. bf_read buffer( &msg.entity_data()[0], msg.entity_data().size() );
  680. int classID = -1;
  681. void *from = NULL;
  682. C_ServerClassInfo *pServerClass = NULL;
  683. ClientClass *pClientClass = NULL;
  684. ALIGN4 unsigned char data[CEventInfo::MAX_EVENT_DATA] ALIGN4_POST;
  685. bf_write toBuf( data, sizeof(data) );
  686. CEventInfo *ei = NULL;
  687. CUtlFixedLinkedList< CEventInfo > &eventList = GetBaseLocalClient().events;
  688. class CAutoCleanupHandle
  689. {
  690. public:
  691. explicit CAutoCleanupHandle( SerializedEntityHandle_t handle ) : m_Handle( handle )
  692. {
  693. }
  694. ~CAutoCleanupHandle()
  695. {
  696. g_pSerializedEntities->ReleaseSerializedEntity( m_Handle );
  697. }
  698. private:
  699. SerializedEntityHandle_t m_Handle;
  700. };
  701. SerializedEntityHandle_t incoming = g_pSerializedEntities->AllocateSerializedEntity(__FILE__, __LINE__);
  702. CAutoCleanupHandle cleanup( incoming );
  703. for (int i = 0; i < numEntries; i++ )
  704. {
  705. float delay = 0.0f;
  706. if ( buffer.ReadOneBit() )
  707. {
  708. delay = (float)buffer.ReadSBitLong( 8 ) / 100.0f;
  709. }
  710. toBuf.Reset();
  711. SerializedEntityHandle_t merged = g_pSerializedEntities->AllocateSerializedEntity(__FILE__, __LINE__);
  712. if ( buffer.ReadOneBit() )
  713. {
  714. from = NULL; // full update
  715. classID = buffer.ReadUBitLong( m_nServerClassBits ); // classID
  716. // Look up the client class, etc.
  717. // Match the server classes to the client classes.
  718. pServerClass = m_pServerClasses ? &m_pServerClasses[ classID - 1 ] : NULL;
  719. if ( !pServerClass )
  720. {
  721. DevMsg("CL_QueueEvent: missing server class info for %i.\n", classID - 1 );
  722. return false;
  723. }
  724. // See if the client .dll has a handler for this class
  725. pClientClass = FindClientClass( pServerClass->m_ClassName );
  726. if ( !pClientClass || !pClientClass->m_pRecvTable )
  727. {
  728. DevMsg("CL_QueueEvent: missing client receive table for %s.\n", pServerClass->m_ClassName );
  729. return false;
  730. }
  731. // Incoming data
  732. RecvTable_ReadFieldList( pClientClass->m_pRecvTable, buffer, incoming, -1, false );
  733. RecvTable_MergeDeltas( pClientClass->m_pRecvTable, SERIALIZED_ENTITY_HANDLE_INVALID, incoming, merged );
  734. }
  735. else
  736. {
  737. Assert( eventList.Tail() != eventList.InvalidIndex() );
  738. CEventInfo *previous = &eventList[ eventList.Tail() ];
  739. RecvTable_ReadFieldList( pClientClass->m_pRecvTable, buffer, incoming, -1, false );
  740. RecvTable_MergeDeltas( pClientClass->m_pRecvTable, previous->m_Packed, incoming, merged );
  741. }
  742. // Add a slot
  743. ei = &GetBaseLocalClient().events[ GetBaseLocalClient().events.AddToTail() ];
  744. Assert( ei );
  745. ei->classID = classID;
  746. ei->fire_delay = fire_time + delay;
  747. ei->flags = flags;
  748. ei->pClientClass = pClientClass;
  749. ei->m_Packed = merged;
  750. }
  751. return true;
  752. }
  753. bool CClientState::SVCMsg_PaintmapData( const CSVCMsg_PaintmapData& msg )
  754. {
  755. int nDword = ( Bits2Bytes( msg.paintmap().size() ) + 3 ) / 4;
  756. CUtlVector< uint32 > data;
  757. data.SetCount( nDword );
  758. bf_read dataIn;
  759. dataIn.ReadBits( const_cast<char*>(msg.paintmap().data()), msg.paintmap().size() );
  760. //handle endian issue between platforms
  761. CByteswap swap;
  762. swap.ActivateByteSwapping( !CByteswap::IsMachineBigEndian() );
  763. swap.SwapBufferToTargetEndian( data.Base(), data.Base(), nDword );
  764. if ( data.Count() > 0 )
  765. {
  766. g_PaintManager.LoadPaintmapDataRLE( data );
  767. }
  768. return true;
  769. }
  770. bool CClientState::SVCMsg_HltvReplay( const CSVCMsg_HltvReplay &msg )
  771. {
  772. VPROF( "HltvReplayStart" );
  773. DevMsg( "%d. Msg_HltvReplay %s->%s\n", GetClientTickCount(), m_nHltvReplayDelay ? "replay" : "real-time", msg.delay() ? "replay" : "real-time" );
  774. int nWasDelay = m_nHltvReplayDelay;
  775. m_nHltvReplayDelay = msg.delay();
  776. m_nHltvReplayStopAt = msg.replay_stop_at();
  777. m_nHltvReplayStartAt = msg.replay_start_at();
  778. float flRate = msg.replay_slowdown_rate();
  779. if ( flRate > 0 )
  780. {
  781. m_nHltvReplaySlowdownBeginAt = msg.replay_slowdown_begin();
  782. m_nHltvReplaySlowdownEndAt = msg.replay_slowdown_end();
  783. m_flHltvReplaySlowdownRate = flRate;
  784. }
  785. else
  786. {
  787. m_nHltvReplaySlowdownBeginAt = 0;
  788. m_nHltvReplaySlowdownEndAt = 0;
  789. m_flHltvReplaySlowdownRate = 1.0f;
  790. }
  791. if ( g_ClientDLL )
  792. {
  793. g_ClientDLL->OnHltvReplay( msg );
  794. s_bClientWaitingForHltvReplayTick = true; // waiting for a tick message after the hltv replay either starts or stops: it will carry the new tick to time replay fades etc.
  795. }
  796. if ( !m_nHltvReplayDelay != !nWasDelay )
  797. {
  798. // clean up frame history, because we're about to start new history.
  799. // this is only useful when we're switching the timeline between HLTV and non-HLTV streams:
  800. // the same frame encodes different information in these two modes, and we can't decode delta frames in one timeline based on the full frames in another.
  801. // It's tolerable from networking perspective because every time we switch the mode, the server forces a full frame update immediately after this message.
  802. // It's NOT VALID to delete client frames when we don't switch the modes, because the server WILL NOT send a full frame update
  803. DeleteClientFrames( -1 );
  804. }
  805. return true;
  806. }
  807. #endif // swds