text: //========= Copyright Valve Corporation, All rights reserved. ============//
  //
  // Purpose: 
  //
  // $NoKeywords: $
  //===========================================================================//
  #include "cbase.h"
  #include <crtmemdebug.h>
  #include "vgui_int.h"
  #include "clientmode.h"
  #include "iinput.h"
  #include "iviewrender.h"
  #include "ivieweffects.h"
  #include "ivmodemanager.h"
  #include "prediction.h"
  #include "clientsideeffects.h"
  #include "particlemgr.h"
  #include "steam/steam_api.h"
  #include "initializer.h"
  #include "smoke_fog_overlay.h"
  #include "view.h"
  #include "ienginevgui.h"
  #include "iefx.h"
  #include "enginesprite.h"
  #include "networkstringtable_clientdll.h"
  #include "voice_status.h"
  #include "filesystem.h"
  #include "c_te_legacytempents.h"
  #include "c_rope.h"
  #include "engine/ishadowmgr.h"
  #include "engine/IStaticPropMgr.h"
  #include "hud_basechat.h"
  #include "hud_crosshair.h"
  #include "view_shared.h"
  #include "env_wind_shared.h"
  #include "detailobjectsystem.h"
  #include "clienteffectprecachesystem.h"
  #include "soundenvelope.h"
  #include "c_basetempentity.h"
  #include "materialsystem/imaterialsystemstub.h"
  #include "VGuiMatSurface/IMatSystemSurface.h"
  #include "materialsystem/imaterialsystemhardwareconfig.h"
  #include "c_soundscape.h"
  #include "engine/ivdebugoverlay.h"
  #include "vguicenterprint.h"
  #include "iviewrender_beams.h"
  #include "tier0/vprof.h"
  #include "engine/IEngineTrace.h"
  #include "engine/ivmodelinfo.h"
  #include "physics.h"
  #include "usermessages.h"
  #include "gamestringpool.h"
  #include "c_user_message_register.h"
  #include "IGameUIFuncs.h"
  #include "saverestoretypes.h"
  #include "saverestore.h"
  #include "physics_saverestore.h"
  #include "igameevents.h"
  #include "datacache/idatacache.h"
  #include "datacache/imdlcache.h"
  #include "kbutton.h"
  #include "tier0/icommandline.h"
  #include "gamerules_register.h"
  #include "vgui_controls/AnimationController.h"
  #include "bitmap/tgawriter.h"
  #include "c_world.h"
  #include "perfvisualbenchmark.h"	
  #include "SoundEmitterSystem/isoundemittersystembase.h"
  #include "hud_closecaption.h"
  #include "colorcorrectionmgr.h"
  #include "physpropclientside.h"
  #include "panelmetaclassmgr.h"
  #include "c_vguiscreen.h"
  #include "imessagechars.h"
  #include "game/client/IGameClientExports.h"
  #include "client_factorylist.h"
  #include "ragdoll_shared.h"
  #include "rendertexture.h"
  #include "view_scene.h"
  #include "iclientmode.h"
  #include "con_nprint.h"
  #include "inputsystem/iinputsystem.h"
  #include "appframework/IAppSystemGroup.h"
  #include "scenefilecache/ISceneFileCache.h"
  #include "tier2/tier2dm.h"
  #include "tier3/tier3.h"
  #include "ihudlcd.h"
  #include "toolframework_client.h"
  #include "hltvcamera.h"
  #if defined( REPLAY_ENABLED )
  #include "replay/replaycamera.h"
  #include "replay/replay_ragdoll.h"
  #include "qlimits.h"
  #include "replay/replay.h"
  #include "replay/ireplaysystem.h"
  #include "replay/iclientreplay.h"
  #include "replay/ienginereplay.h"
  #include "replay/ireplaymanager.h"
  #include "replay/ireplayscreenshotmanager.h"
  #include "replay/iclientreplaycontext.h"
  #include "replay/vgui/replayconfirmquitdlg.h"
  #include "replay/vgui/replaybrowsermainpanel.h"
  #include "replay/vgui/replayinputpanel.h"
  #include "replay/vgui/replayperformanceeditor.h"
  #endif
  #include "vgui/ILocalize.h"
  #include "vgui/IVGui.h"
  #include "ixboxsystem.h"
  #include "ipresence.h"
  #include "engine/imatchmaking.h"
  #include "cdll_bounded_cvars.h"
  #include "matsys_controls/matsyscontrols.h"
  #include "gamestats.h"
  #include "particle_parse.h"
  #if defined( TF_CLIENT_DLL )
  #include "rtime.h"
  #include "tf_hud_disconnect_prompt.h"
  #include "../engine/audio/public/sound.h"
  #include "tf_shared_content_manager.h"
  #endif
  #include "clientsteamcontext.h"
  #include "renamed_recvtable_compat.h"
  #include "mouthinfo.h"
  #include "headtrack/isourcevirtualreality.h"
  #include "client_virtualreality.h"
  #include "mumble.h"
  
  // NVNT includes
  #include "hud_macros.h"
  #include "haptics/ihaptics.h"
  #include "haptics/haptic_utils.h"
  #include "haptics/haptic_msgs.h"
  
  #if defined( TF_CLIENT_DLL )
  #include "abuse_report.h"
  #endif
  
  #ifdef USES_ECON_ITEMS
  #include "econ_item_system.h"
  #endif // USES_ECON_ITEMS
  
  #if defined( TF_CLIENT_DLL )
  #include "econ/tool_items/custom_texture_cache.h"
  #endif
  
  #ifdef WORKSHOP_IMPORT_ENABLED
  #include "fbxsystem/fbxsystem.h"
  #endif
  
  extern vgui::IInputInternal *g_InputInternal;
  const char *COM_GetModDirectory(); // return the mod dir (rather than the complete -game param, which can be a path)
  
  //=============================================================================
  // HPE_BEGIN
  // [dwenger] Necessary for stats display
  //=============================================================================
  
  #include "achievements_and_stats_interface.h"
  
  //=============================================================================
  // HPE_END
  //=============================================================================
  
  
  #ifdef PORTAL
  #include "PortalRender.h"
  #endif
  
  #ifdef SIXENSE
  #include "sixense/in_sixense.h"
  #endif
  
  // memdbgon must be the last include file in a .cpp file!!!
  #include "tier0/memdbgon.h"
  
  extern IClientMode *GetClientModeNormal();
  
  // IF YOU ADD AN INTERFACE, EXTERN IT IN THE HEADER FILE.
  IVEngineClient	*engine = NULL;
  IVModelRender *modelrender = NULL;
  IVEfx *effects = NULL;
  IVRenderView *render = NULL;
  IVDebugOverlay *debugoverlay = NULL;
  IMaterialSystemStub *materials_stub = NULL;
  IDataCache *datacache = NULL;
  IVModelInfoClient *modelinfo = NULL;
  IEngineVGui *enginevgui = NULL;
  INetworkStringTableContainer *networkstringtable = NULL;
  ISpatialPartition* partition = NULL;
  IFileSystem *filesystem = NULL;
  IShadowMgr *shadowmgr = NULL;
  IStaticPropMgrClient *staticpropmgr = NULL;
  IEngineSound *enginesound = NULL;
  IUniformRandomStream *random = NULL;
  static CGaussianRandomStream s_GaussianRandomStream;
  CGaussianRandomStream *randomgaussian = &s_GaussianRandomStream;
  ISharedGameRules *sharedgamerules = NULL;
  IEngineTrace *enginetrace = NULL;
  IGameUIFuncs *gameuifuncs = NULL;
  IGameEventManager2 *gameeventmanager = NULL;
  ISoundEmitterSystemBase *soundemitterbase = NULL;
  IInputSystem *inputsystem = NULL;
  ISceneFileCache *scenefilecache = NULL;
  IXboxSystem *xboxsystem = NULL;	// Xbox 360 only
  IMatchmaking *matchmaking = NULL;
  IUploadGameStats *gamestatsuploader = NULL;
  IClientReplayContext *g_pClientReplayContext = NULL;
  #if defined( REPLAY_ENABLED )
  IReplayManager *g_pReplayManager = NULL;
  IReplayMovieManager *g_pReplayMovieManager = NULL;
  IReplayScreenshotManager *g_pReplayScreenshotManager = NULL;
  IReplayPerformanceManager *g_pReplayPerformanceManager = NULL;
  IReplayPerformanceController *g_pReplayPerformanceController = NULL;
  IEngineReplay *g_pEngineReplay = NULL;
  IEngineClientReplay *g_pEngineClientReplay = NULL;
  IReplaySystem *g_pReplay = NULL;
  #endif
  
  IHaptics* haptics = NULL;// NVNT haptics system interface singleton
  
  //=============================================================================
  // HPE_BEGIN
  // [dwenger] Necessary for stats display
  //=============================================================================
  
  AchievementsAndStatsInterface* g_pAchievementsAndStatsInterface = NULL;
  
  //=============================================================================
  // HPE_END
  //=============================================================================
  
  IGameSystem *SoundEmitterSystem();
  IGameSystem *ToolFrameworkClientSystem();
  
  // Engine player info, no game related infos here
  BEGIN_BYTESWAP_DATADESC( player_info_s )
  	DEFINE_ARRAY( name, FIELD_CHARACTER, MAX_PLAYER_NAME_LENGTH ),
  	DEFINE_FIELD( userID, FIELD_INTEGER ),
  	DEFINE_ARRAY( guid, FIELD_CHARACTER, SIGNED_GUID_LEN + 1 ),
  	DEFINE_FIELD( friendsID, FIELD_INTEGER ),
  	DEFINE_ARRAY( friendsName, FIELD_CHARACTER, MAX_PLAYER_NAME_LENGTH ),
  	DEFINE_FIELD( fakeplayer, FIELD_BOOLEAN ),
  	DEFINE_FIELD( ishltv, FIELD_BOOLEAN ),
  #if defined( REPLAY_ENABLED )
  	DEFINE_FIELD( isreplay, FIELD_BOOLEAN ),
  #endif
  	DEFINE_ARRAY( customFiles, FIELD_INTEGER, MAX_CUSTOM_FILES ),
  	DEFINE_FIELD( filesDownloaded, FIELD_INTEGER ),
  END_BYTESWAP_DATADESC()
  
  static bool g_bRequestCacheUsedMaterials = false;
  void RequestCacheUsedMaterials()
  {
  	g_bRequestCacheUsedMaterials = true;
  }
  
  void ProcessCacheUsedMaterials()
  {
  	if ( !g_bRequestCacheUsedMaterials )
  		return;
  
  	g_bRequestCacheUsedMaterials = false;
  	if ( materials )
  	{
          materials->CacheUsedMaterials();
  	}
  }
  
  // String tables
  INetworkStringTable *g_pStringTableParticleEffectNames = NULL;
  INetworkStringTable *g_StringTableEffectDispatch = NULL;
  INetworkStringTable *g_StringTableVguiScreen = NULL;
  INetworkStringTable *g_pStringTableMaterials = NULL;
  INetworkStringTable *g_pStringTableInfoPanel = NULL;
  INetworkStringTable *g_pStringTableClientSideChoreoScenes = NULL;
  INetworkStringTable *g_pStringTableServerMapCycle = NULL;
  
  #ifdef TF_CLIENT_DLL
  INetworkStringTable *g_pStringTableServerPopFiles = NULL;
  INetworkStringTable *g_pStringTableServerMapCycleMvM = NULL;
  #endif
  
  static CGlobalVarsBase dummyvars( true );
  // So stuff that might reference gpGlobals during DLL initialization won't have a NULL pointer.
  // Once the engine calls Init on this DLL, this pointer gets assigned to the shared data in the engine
  CGlobalVarsBase *gpGlobals = &dummyvars;
  class CHudChat;
  class CViewRender;
  extern CViewRender g_DefaultViewRender;
  
  extern void StopAllRumbleEffects( void );
  
  static C_BaseEntityClassList *s_pClassLists = NULL;
  C_BaseEntityClassList::C_BaseEntityClassList()
  {
  	m_pNextClassList = s_pClassLists;
  	s_pClassLists = this;
  }
  C_BaseEntityClassList::~C_BaseEntityClassList()
  {
  }
  
  // Any entities that want an OnDataChanged during simulation register for it here.
  class CDataChangedEvent
  {
  public:
  	CDataChangedEvent() {}
  	CDataChangedEvent( IClientNetworkable *ent, DataUpdateType_t updateType, int *pStoredEvent )
  	{
  		m_pEntity = ent;
  		m_UpdateType = updateType;
  		m_pStoredEvent = pStoredEvent;
  	}
  
  	IClientNetworkable	*m_pEntity;
  	DataUpdateType_t	m_UpdateType;
  	int					*m_pStoredEvent;
  };
  
  ISaveRestoreBlockHandler *GetEntitySaveRestoreBlockHandler();
  ISaveRestoreBlockHandler *GetViewEffectsRestoreBlockHandler();
  
  CUtlLinkedList<CDataChangedEvent, unsigned short> g_DataChangedEvents;
  ClientFrameStage_t g_CurFrameStage = FRAME_UNDEFINED;
  
  
  class IMoveHelper;
  
  void DispatchHudText( const char *pszName );
  
  static ConVar s_CV_ShowParticleCounts("showparticlecounts", "0", 0, "Display number of particles drawn per frame");
  static ConVar s_cl_team("cl_team", "default", FCVAR_USERINFO|FCVAR_ARCHIVE, "Default team when joining a game");
  static ConVar s_cl_class("cl_class", "default", FCVAR_USERINFO|FCVAR_ARCHIVE, "Default class when joining a game");
  
  // Physics system
  bool g_bLevelInitialized;
  bool g_bTextMode = false;
  class IClientPurchaseInterfaceV2 *g_pClientPurchaseInterface = (class IClientPurchaseInterfaceV2 *)(&g_bTextMode + 156);
  
  static ConVar *g_pcv_ThreadMode = NULL;
  
  //-----------------------------------------------------------------------------
  // Purpose: interface for gameui to modify voice bans
  //-----------------------------------------------------------------------------
  class CGameClientExports : public IGameClientExports
  {
  public:
  	// ingame voice manipulation
  	bool IsPlayerGameVoiceMuted(int playerIndex)
  	{
  		return GetClientVoiceMgr()->IsPlayerBlocked(playerIndex);
  	}
  
  	void MutePlayerGameVoice(int playerIndex)
  	{
  		GetClientVoiceMgr()->SetPlayerBlockedState(playerIndex, true);
  	}
  
  	void UnmutePlayerGameVoice(int playerIndex)
  	{
  		GetClientVoiceMgr()->SetPlayerBlockedState(playerIndex, false);
  	}
  
  	void OnGameUIActivated( void )
  	{
  		IGameEvent *event = gameeventmanager->CreateEvent( "gameui_activated" );
  		if ( event )
  		{
  			gameeventmanager->FireEventClientSide( event );
  		}
  	}
  
  	void OnGameUIHidden( void )
  	{
  		IGameEvent *event = gameeventmanager->CreateEvent( "gameui_hidden" );
  		if ( event )
  		{
  			gameeventmanager->FireEventClientSide( event );
  		}
  	}
  
      //=============================================================================
      // HPE_BEGIN
      // [dwenger] Necessary for stats display
      //=============================================================================
  
      void CreateAchievementsPanel( vgui::Panel* pParent )
      {
          if (g_pAchievementsAndStatsInterface)
          {
              g_pAchievementsAndStatsInterface->CreatePanel( pParent );
          }
      }
  
      void DisplayAchievementPanel()
      {
          if (g_pAchievementsAndStatsInterface)
          {
              g_pAchievementsAndStatsInterface->DisplayPanel();
          }
      }
  
      void ShutdownAchievementPanel()
      {
          if (g_pAchievementsAndStatsInterface)
          {
              g_pAchievementsAndStatsInterface->ReleasePanel();
          }
      }
  
  	int GetAchievementsPanelMinWidth( void ) const
  	{
          if ( g_pAchievementsAndStatsInterface )
          {
              return g_pAchievementsAndStatsInterface->GetAchievementsPanelMinWidth();
          }
  
  		return 0;
  	}
  
      //=============================================================================
      // HPE_END
      //=============================================================================
  
  	const char *GetHolidayString()
  	{
  		return UTIL_GetActiveHolidayString();
  	}
  };
  
  EXPOSE_SINGLE_INTERFACE( CGameClientExports, IGameClientExports, GAMECLIENTEXPORTS_INTERFACE_VERSION );
  
  class CClientDLLSharedAppSystems : public IClientDLLSharedAppSystems
  {
  public:
  	CClientDLLSharedAppSystems()
  	{
  		AddAppSystem( "soundemittersystem" DLL_EXT_STRING, SOUNDEMITTERSYSTEM_INTERFACE_VERSION );
  		AddAppSystem( "scenefilecache" DLL_EXT_STRING, SCENE_FILE_CACHE_INTERFACE_VERSION );
  	}
  
  	virtual int	Count()
  	{
  		return m_Systems.Count();
  	}
  	virtual char const *GetDllName( int idx )
  	{
  		return m_Systems[ idx ].m_pModuleName;
  	}
  	virtual char const *GetInterfaceName( int idx )
  	{
  		return m_Systems[ idx ].m_pInterfaceName;
  	}
  private:
  	void AddAppSystem( char const *moduleName, char const *interfaceName )
  	{
  		AppSystemInfo_t sys;
  		sys.m_pModuleName = moduleName;
  		sys.m_pInterfaceName = interfaceName;
  		m_Systems.AddToTail( sys );
  	}
  
  	CUtlVector< AppSystemInfo_t >	m_Systems;
  };
  
  EXPOSE_SINGLE_INTERFACE( CClientDLLSharedAppSystems, IClientDLLSharedAppSystems, CLIENT_DLL_SHARED_APPSYSTEMS );
  
  
  //-----------------------------------------------------------------------------
  // Helper interface for voice.
  //-----------------------------------------------------------------------------
  class CHLVoiceStatusHelper : public IVoiceStatusHelper
  {
  public:
  	virtual void GetPlayerTextColor(int entindex, int color[3])
  	{
  		color[0] = color[1] = color[2] = 128;
  	}
  
  	virtual void UpdateCursorState()
  	{
  	}
  
  	virtual bool			CanShowSpeakerLabels()
  	{
  		return true;
  	}
  };
  static CHLVoiceStatusHelper g_VoiceStatusHelper;
  
  //-----------------------------------------------------------------------------
  // Code to display which entities are having their bones setup each frame.
  //-----------------------------------------------------------------------------
  
  ConVar cl_ShowBoneSetupEnts( "cl_ShowBoneSetupEnts", "0", 0, "Show which entities are having their bones setup each frame." );
  
  class CBoneSetupEnt
  {
  public:
  	char m_ModelName[128];
  	int m_Index;
  	int m_Count;
  };
  
  bool BoneSetupCompare( const CBoneSetupEnt &a, const CBoneSetupEnt &b )
  {
  	return a.m_Index < b.m_Index;
  }
  
  CUtlRBTree<CBoneSetupEnt> g_BoneSetupEnts( BoneSetupCompare );
  
  
  void TrackBoneSetupEnt( C_BaseAnimating *pEnt )
  {
  #ifdef _DEBUG
  	if ( IsRetail() )
  		return;
  		
  	if ( !cl_ShowBoneSetupEnts.GetInt() )
  		return;
  
  	CBoneSetupEnt ent;
  	ent.m_Index = pEnt->entindex();
  	unsigned short i = g_BoneSetupEnts.Find( ent );
  	if ( i == g_BoneSetupEnts.InvalidIndex() )
  	{
  		Q_strncpy( ent.m_ModelName, modelinfo->GetModelName( pEnt->GetModel() ), sizeof( ent.m_ModelName ) );
  		ent.m_Count = 1;
  		g_BoneSetupEnts.Insert( ent );
  	}
  	else
  	{
  		g_BoneSetupEnts[i].m_Count++;
  	}
  #endif
  }
  
  void DisplayBoneSetupEnts()
  {
  #ifdef _DEBUG
  	if ( IsRetail() )
  		return;
  	
  	if ( !cl_ShowBoneSetupEnts.GetInt() )
  		return;
  
  	unsigned short i;
  	int nElements = 0;
  	for ( i=g_BoneSetupEnts.FirstInorder(); i != g_BoneSetupEnts.LastInorder(); i=g_BoneSetupEnts.NextInorder( i ) )
  		++nElements;
  		
  	engine->Con_NPrintf( 0, "%d bone setup ents (name/count/entindex) ------------", nElements );
  
  	con_nprint_s printInfo;
  	printInfo.time_to_live = -1;
  	printInfo.fixed_width_font = true;
  	printInfo.color[0] = printInfo.color[1] = printInfo.color[2] = 1;
  	
  	printInfo.index = 2;
  	for ( i=g_BoneSetupEnts.FirstInorder(); i != g_BoneSetupEnts.LastInorder(); i=g_BoneSetupEnts.NextInorder( i ) )
  	{
  		CBoneSetupEnt *pEnt = &g_BoneSetupEnts[i];
  		
  		if ( pEnt->m_Count >= 3 )
  		{
  			printInfo.color[0] = 1;
  			printInfo.color[1] = printInfo.color[2] = 0;
  		}
  		else if ( pEnt->m_Count == 2 )
  		{
  			printInfo.color[0] = (float)200 / 255;
  			printInfo.color[1] = (float)220 / 255;
  			printInfo.color[2] = 0;
  		}
  		else
  		{
  			printInfo.color[0] = printInfo.color[0] = printInfo.color[0] = 1;
  		}
  		engine->Con_NXPrintf( &printInfo, "%25s / %3d / %3d", pEnt->m_ModelName, pEnt->m_Count, pEnt->m_Index );
  		printInfo.index++;
  	}
  
  	g_BoneSetupEnts.RemoveAll();
  #endif
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: engine to client .dll interface
  //-----------------------------------------------------------------------------
  class CHLClient : public IBaseClientDLL
  {
  public:
  	CHLClient();
  
  	virtual int						Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physicsFactory, CGlobalVarsBase *pGlobals );
  
  	virtual void					PostInit();
  	virtual void					Shutdown( void );
  
  	virtual bool					ReplayInit( CreateInterfaceFn fnReplayFactory );
  	virtual bool					ReplayPostInit();
  
  	virtual void					LevelInitPreEntity( const char *pMapName );
  	virtual void					LevelInitPostEntity();
  	virtual void					LevelShutdown( void );
  
  	virtual ClientClass				*GetAllClasses( void );
  
  	virtual int						HudVidInit( void );
  	virtual void					HudProcessInput( bool bActive );
  	virtual void					HudUpdate( bool bActive );
  	virtual void					HudReset( void );
  	virtual void					HudText( const char * message );
  
  	// Mouse Input Interfaces
  	virtual void					IN_ActivateMouse( void );
  	virtual void					IN_DeactivateMouse( void );
  	virtual void					IN_Accumulate( void );
  	virtual void					IN_ClearStates( void );
  	virtual bool					IN_IsKeyDown( const char *name, bool& isdown );
  	virtual void					IN_OnMouseWheeled( int nDelta );
  	// Raw signal
  	virtual int						IN_KeyEvent( int eventcode, ButtonCode_t keynum, const char *pszCurrentBinding );
  	virtual void					IN_SetSampleTime( float frametime );
  	// Create movement command
  	virtual void					CreateMove ( int sequence_number, float input_sample_frametime, bool active );
  	virtual void					ExtraMouseSample( float frametime, bool active );
  	virtual bool					WriteUsercmdDeltaToBuffer( bf_write *buf, int from, int to, bool isnewcommand );	
  	virtual void					EncodeUserCmdToBuffer( bf_write& buf, int slot );
  	virtual void					DecodeUserCmdFromBuffer( bf_read& buf, int slot );
  
  
  	virtual void					View_Render( vrect_t *rect );
  	virtual void					RenderView( const CViewSetup &view, int nClearFlags, int whatToDraw );
  	virtual void					View_Fade( ScreenFade_t *pSF );
  	
  	virtual void					SetCrosshairAngle( const QAngle& angle );
  
  	virtual void					InitSprite( CEngineSprite *pSprite, const char *loadname );
  	virtual void					ShutdownSprite( CEngineSprite *pSprite );
  
  	virtual int						GetSpriteSize( void ) const;
  
  	virtual void					VoiceStatus( int entindex, qboolean bTalking );
  
  	virtual void					InstallStringTableCallback( const char *tableName );
  
  	virtual void					FrameStageNotify( ClientFrameStage_t curStage );
  
  	virtual bool					DispatchUserMessage( int msg_type, bf_read &msg_data );
  
  	// Save/restore system hooks
  	virtual CSaveRestoreData  *SaveInit( int size );
  	virtual void			SaveWriteFields( CSaveRestoreData *, const char *, void *, datamap_t *, typedescription_t *, int );
  	virtual void			SaveReadFields( CSaveRestoreData *, const char *, void *, datamap_t *, typedescription_t *, int );
  	virtual void			PreSave( CSaveRestoreData * );
  	virtual void			Save( CSaveRestoreData * );
  	virtual void			WriteSaveHeaders( CSaveRestoreData * );
  	virtual void			ReadRestoreHeaders( CSaveRestoreData * );
  	virtual void			Restore( CSaveRestoreData *, bool );
  	virtual void			DispatchOnRestore();
  	virtual void			WriteSaveGameScreenshot( const char *pFilename );
  
  	// Given a list of "S(wavname) S(wavname2)" tokens, look up the localized text and emit
  	//  the appropriate close caption if running with closecaption = 1
  	virtual void			EmitSentenceCloseCaption( char const *tokenstream );
  	virtual void			EmitCloseCaption( char const *captionname, float duration );
  
  	virtual CStandardRecvProxies* GetStandardRecvProxies();
  
  	virtual bool			CanRecordDemo( char *errorMsg, int length ) const;
  
  	virtual void			OnDemoRecordStart( char const* pDemoBaseName );
  	virtual void			OnDemoRecordStop();
  	virtual void			OnDemoPlaybackStart( char const* pDemoBaseName );
  	virtual void			OnDemoPlaybackStop();
  
  	virtual bool			ShouldDrawDropdownConsole();
  
  	// Get client screen dimensions
  	virtual int				GetScreenWidth();
  	virtual int				GetScreenHeight();
  
  	// save game screenshot writing
  	virtual void			WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height, bool bCreatePowerOf2Padded/*=false*/, bool bWriteVTF/*=false*/ );
  
  	// Gets the location of the player viewpoint
  	virtual bool			GetPlayerView( CViewSetup &playerView );
  
  	// Matchmaking
  	virtual void			SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties );
  	virtual uint			GetPresenceID( const char *pIDName );
  	virtual const char		*GetPropertyIdString( const uint id );
  	virtual void			GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes );
  	virtual void			StartStatsReporting( HANDLE handle, bool bArbitrated );
  
  	virtual void			InvalidateMdlCache();
  
  	virtual void			ReloadFilesInList( IFileList *pFilesToReload );
  
  	// Let the client handle UI toggle - if this function returns false, the UI will toggle, otherwise it will not.
  	virtual bool			HandleUiToggle();
  
  	// Allow the console to be shown?
  	virtual bool			ShouldAllowConsole();
  
  	// Get renamed recv tables
  	virtual CRenamedRecvTableInfo	*GetRenamedRecvTableInfos();
  
  	// Get the mouthinfo for the sound being played inside UI panels
  	virtual CMouthInfo		*GetClientUIMouthInfo();
  
  	// Notify the client that a file has been received from the game server
  	virtual void			FileReceived( const char * fileName, unsigned int transferID );
  
  	virtual const char* TranslateEffectForVisionFilter( const char *pchEffectType, const char *pchEffectName );
  	
  	virtual void			ClientAdjustStartSoundParams( struct StartSoundParams_t& params );
  	
  	// Returns true if the disconnect command has been handled by the client
  	virtual bool DisconnectAttempt( void );
  public:
  	void PrecacheMaterial( const char *pMaterialName );
  
  	virtual bool IsConnectedUserInfoChangeAllowed( IConVar *pCvar );
  
  private:
  	void UncacheAllMaterials( );
  	void ResetStringTablePointers();
  
  	CUtlVector< IMaterial * > m_CachedMaterials;
  };
  
  
  CHLClient gHLClient;
  IBaseClientDLL *clientdll = &gHLClient;
  
  EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CHLClient, IBaseClientDLL, CLIENT_DLL_INTERFACE_VERSION, gHLClient );
  
  
  //-----------------------------------------------------------------------------
  // Precaches a material
  //-----------------------------------------------------------------------------
  void PrecacheMaterial( const char *pMaterialName )
  {
  	gHLClient.PrecacheMaterial( pMaterialName );
  }
  
  //-----------------------------------------------------------------------------
  // Converts a previously precached material into an index
  //-----------------------------------------------------------------------------
  int GetMaterialIndex( const char *pMaterialName )
  {
  	if (pMaterialName)
  	{
  		int nIndex = g_pStringTableMaterials->FindStringIndex( pMaterialName );
  		Assert( nIndex >= 0 );
  		if (nIndex >= 0)
  			return nIndex;
  	}
  
  	// This is the invalid string index
  	return 0;
  }
  
  //-----------------------------------------------------------------------------
  // Converts precached material indices into strings
  //-----------------------------------------------------------------------------
  const char *GetMaterialNameFromIndex( int nIndex )
  {
  	if (nIndex != (g_pStringTableMaterials->GetMaxStrings() - 1))
  	{
  		return g_pStringTableMaterials->GetString( nIndex );
  	}
  	else
  	{
  		return NULL;
  	}
  }
  
  
  //-----------------------------------------------------------------------------
  // Precaches a particle system
  //-----------------------------------------------------------------------------
  void PrecacheParticleSystem( const char *pParticleSystemName )
  {
  	g_pStringTableParticleEffectNames->AddString( false, pParticleSystemName );
  	g_pParticleSystemMgr->PrecacheParticleSystem( pParticleSystemName );
  }
  
  
  //-----------------------------------------------------------------------------
  // Converts a previously precached particle system into an index
  //-----------------------------------------------------------------------------
  int GetParticleSystemIndex( const char *pParticleSystemName )
  {
  	if ( pParticleSystemName )
  	{
  		int nIndex = g_pStringTableParticleEffectNames->FindStringIndex( pParticleSystemName );
  		if ( nIndex != INVALID_STRING_INDEX )
  			return nIndex;
  		DevWarning("Client: Missing precache for particle system \"%s\"!\n", pParticleSystemName );
  	}
  
  	// This is the invalid string index
  	return 0;
  }
  
  //-----------------------------------------------------------------------------
  // Converts precached particle system indices into strings
  //-----------------------------------------------------------------------------
  const char *GetParticleSystemNameFromIndex( int nIndex )
  {
  	if ( nIndex < g_pStringTableParticleEffectNames->GetMaxStrings() )
  		return g_pStringTableParticleEffectNames->GetString( nIndex );
  	return "error";
  }
  
  //-----------------------------------------------------------------------------
  // Returns true if host_thread_mode is set to non-zero (and engine is running in threaded mode)
  //-----------------------------------------------------------------------------
  bool IsEngineThreaded()
  {
  	if ( g_pcv_ThreadMode )
  	{
  		return g_pcv_ThreadMode->GetBool();
  	}
  	return false;
  }
  
  //-----------------------------------------------------------------------------
  // Constructor
  //-----------------------------------------------------------------------------
  
  CHLClient::CHLClient() 
  {
  	// Kinda bogus, but the logic in the engine is too convoluted to put it there
  	g_bLevelInitialized = false;
  }
  
  
  extern IGameSystem *ViewportClientSystem();
  
  
  //-----------------------------------------------------------------------------
  ISourceVirtualReality *g_pSourceVR = NULL;
  
  // Purpose: Called when the DLL is first loaded.
  // Input  : engineFactory - 
  // Output : int
  //-----------------------------------------------------------------------------
  int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physicsFactory, CGlobalVarsBase *pGlobals )
  {
  	InitCRTMemDebug();
  	MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f );
  
  
  #ifdef SIXENSE
  	g_pSixenseInput = new SixenseInput;
  #endif
  
  	// Hook up global variables
  	gpGlobals = pGlobals;
  
  	ConnectTier1Libraries( &appSystemFactory, 1 );
  	ConnectTier2Libraries( &appSystemFactory, 1 );
  	ConnectTier3Libraries( &appSystemFactory, 1 );
  
  #ifndef NO_STEAM
  	ClientSteamContext().Activate();
  #endif
  
  	// We aren't happy unless we get all of our interfaces.
  	// please don't collapse this into one monolithic boolean expression (impossible to debug)
  	if ( (engine = (IVEngineClient *)appSystemFactory( VENGINE_CLIENT_INTERFACE_VERSION, NULL )) == NULL )
  		return false;
  	if ( (modelrender = (IVModelRender *)appSystemFactory( VENGINE_HUDMODEL_INTERFACE_VERSION, NULL )) == NULL )
  		return false;
  	if ( (effects = (IVEfx *)appSystemFactory( VENGINE_EFFECTS_INTERFACE_VERSION, NULL )) == NULL )
  		return false;
  	if ( (enginetrace = (IEngineTrace *)appSystemFactory( INTERFACEVERSION_ENGINETRACE_CLIENT, NULL )) == NULL )
  		return false;
  	if ( (render = (IVRenderView *)appSystemFactory( VENGINE_RENDERVIEW_INTERFACE_VERSION, NULL )) == NULL )
  		return false;
  	if ( (debugoverlay = (IVDebugOverlay *)appSystemFactory( VDEBUG_OVERLAY_INTERFACE_VERSION, NULL )) == NULL )
  		return false;
  	if ( (datacache = (IDataCache*)appSystemFactory(DATACACHE_INTERFACE_VERSION, NULL )) == NULL )
  		return false;
  	if ( !mdlcache )
  		return false;
  	if ( (modelinfo = (IVModelInfoClient *)appSystemFactory(VMODELINFO_CLIENT_INTERFACE_VERSION, NULL )) == NULL )
  		return false;
  	if ( (enginevgui = (IEngineVGui *)appSystemFactory(VENGINE_VGUI_VERSION, NULL )) == NULL )
  		return false;
  	if ( (networkstringtable = (INetworkStringTableContainer *)appSystemFactory(INTERFACENAME_NETWORKSTRINGTABLECLIENT,NULL)) == NULL )
  		return false;
  	if ( (partition = (ISpatialPartition *)appSystemFactory(INTERFACEVERSION_SPATIALPARTITION, NULL)) == NULL )
  		return false;
  	if ( (shadowmgr = (IShadowMgr *)appSystemFactory(ENGINE_SHADOWMGR_INTERFACE_VERSION, NULL)) == NULL )
  		return false;
  	if ( (staticpropmgr = (IStaticPropMgrClient *)appSystemFactory(INTERFACEVERSION_STATICPROPMGR_CLIENT, NULL)) == NULL )
  		return false;
  	if ( (enginesound = (IEngineSound *)appSystemFactory(IENGINESOUND_CLIENT_INTERFACE_VERSION, NULL)) == NULL )
  		return false;
  	if ( (filesystem = (IFileSystem *)appSystemFactory(FILESYSTEM_INTERFACE_VERSION, NULL)) == NULL )
  		return false;
  	if ( (random = (IUniformRandomStream *)appSystemFactory(VENGINE_CLIENT_RANDOM_INTERFACE_VERSION, NULL)) == NULL )
  		return false;
  	if ( (gameuifuncs = (IGameUIFuncs * )appSystemFactory( VENGINE_GAMEUIFUNCS_VERSION, NULL )) == NULL )
  		return false;
  	if ( (gameeventmanager = (IGameEventManager2 *)appSystemFactory(INTERFACEVERSION_GAMEEVENTSMANAGER2,NULL)) == NULL )
  		return false;
  	if ( (soundemitterbase = (ISoundEmitterSystemBase *)appSystemFactory(SOUNDEMITTERSYSTEM_INTERFACE_VERSION, NULL)) == NULL )
  		return false;
  	if ( (inputsystem = (IInputSystem *)appSystemFactory(INPUTSYSTEM_INTERFACE_VERSION, NULL)) == NULL )
  		return false;
  	if ( (scenefilecache = (ISceneFileCache *)appSystemFactory( SCENE_FILE_CACHE_INTERFACE_VERSION, NULL )) == NULL )
  		return false;
  	if ( IsX360() && (xboxsystem = (IXboxSystem *)appSystemFactory( XBOXSYSTEM_INTERFACE_VERSION, NULL )) == NULL )
  		return false;
  	if ( IsX360() && (matchmaking = (IMatchmaking *)appSystemFactory( VENGINE_MATCHMAKING_VERSION, NULL )) == NULL )
  		return false;
  #ifndef _XBOX
  	if ( ( gamestatsuploader = (IUploadGameStats *)appSystemFactory( INTERFACEVERSION_UPLOADGAMESTATS, NULL )) == NULL )
  		return false;
  #endif
  
  #if defined( REPLAY_ENABLED )
  	if ( IsPC() && (g_pEngineReplay = (IEngineReplay *)appSystemFactory( ENGINE_REPLAY_INTERFACE_VERSION, NULL )) == NULL )
  		return false;
  	if ( IsPC() && (g_pEngineClientReplay = (IEngineClientReplay *)appSystemFactory( ENGINE_REPLAY_CLIENT_INTERFACE_VERSION, NULL )) == NULL )
  		return false;
  #endif
  
  	if (!g_pMatSystemSurface)
  		return false;
  
  #ifdef WORKSHOP_IMPORT_ENABLED
  	if ( !ConnectDataModel( appSystemFactory ) )
  		return false;
  	if ( InitDataModel() != INIT_OK )
  		return false;
  	InitFbx();
  #endif
  
  	// it's ok if this is NULL. That just means the headtrack.dll wasn't found
  	g_pSourceVR = (ISourceVirtualReality *)appSystemFactory(SOURCE_VIRTUAL_REALITY_INTERFACE_VERSION, NULL);
  
  	factorylist_t factories;
  	factories.appSystemFactory = appSystemFactory;
  	factories.physicsFactory = physicsFactory;
  	FactoryList_Store( factories );
  
  	// Yes, both the client and game .dlls will try to Connect, the soundemittersystem.dll will handle this gracefully
  	if ( !soundemitterbase->Connect( appSystemFactory ) )
  	{
  		return false;
  	}
  
  	if ( CommandLine()->FindParm( "-textmode" ) )
  		g_bTextMode = true;
  
  	if ( CommandLine()->FindParm( "-makedevshots" ) )
  		g_MakingDevShots = true;
  
  	// Not fatal if the material system stub isn't around.
  	materials_stub = (IMaterialSystemStub*)appSystemFactory( MATERIAL_SYSTEM_STUB_INTERFACE_VERSION, NULL );
  
  	if( !g_pMaterialSystemHardwareConfig )
  		return false;
  
  	// Hook up the gaussian random number generator
  	s_GaussianRandomStream.AttachToStream( random );
  
  	// Initialize the console variables.
  	ConVar_Register( FCVAR_CLIENTDLL );
  
  	g_pcv_ThreadMode = g_pCVar->FindVar( "host_thread_mode" );
  
  	// If we are in VR mode do some initial setup work
  	if( UseVR() )
  	{
  		int nViewportWidth, nViewportHeight;
  
  		g_pSourceVR->GetViewportBounds( ISourceVirtualReality::VREye_Left, NULL, NULL, &nViewportWidth, &nViewportHeight );
  		vgui::surface()->SetFullscreenViewport( 0, 0, nViewportWidth, nViewportHeight );
  
  		vgui::ivgui()->SetVRMode( true );
  	}
  
  	if (!Initializer::InitializeAllObjects())
  		return false;
  
  	if (!ParticleMgr()->Init(MAX_TOTAL_PARTICLES, materials))
  		return false;
  
  
  	if (!VGui_Startup( appSystemFactory ))
  		return false;
  
  	vgui::VGui_InitMatSysInterfacesList( "ClientDLL", &appSystemFactory, 1 );
  
  	// Add the client systems.	
  	
  	// Client Leaf System has to be initialized first, since DetailObjectSystem uses it
  	IGameSystem::Add( GameStringSystem() );
  	IGameSystem::Add( SoundEmitterSystem() );
  	IGameSystem::Add( ToolFrameworkClientSystem() );
  	IGameSystem::Add( ClientLeafSystem() );
  	IGameSystem::Add( DetailObjectSystem() );
  	IGameSystem::Add( ViewportClientSystem() );
  	IGameSystem::Add( ClientEffectPrecacheSystem() );
  	IGameSystem::Add( g_pClientShadowMgr );
  	IGameSystem::Add( g_pColorCorrectionMgr );	// NOTE: This must happen prior to ClientThinkList (color correction is updated there)
  	IGameSystem::Add( ClientThinkList() );
  	IGameSystem::Add( ClientSoundscapeSystem() );
  	IGameSystem::Add( PerfVisualBenchmark() );
  	IGameSystem::Add( MumbleSystem() );
  	
  	#if defined( TF_CLIENT_DLL )
  	IGameSystem::Add( CustomTextureToolCacheGameSystem() );
  	IGameSystem::Add( TFSharedContentManager() );
  	#endif
  
  #if defined( TF_CLIENT_DLL )
  	if ( g_AbuseReportMgr != NULL )
  	{
  		IGameSystem::Add( g_AbuseReportMgr );
  	}
  #endif
  
  #if defined( CLIENT_DLL ) && defined( COPY_CHECK_STRESSTEST )
  	IGameSystem::Add( GetPredictionCopyTester() );
  #endif
  
  	modemanager->Init( );
  
  	g_pClientMode->InitViewport();
  
  	gHUD.Init();
  
  	g_pClientMode->Init();
  
  	if ( !IGameSystem::InitAllSystems() )
  		return false;
  
  	g_pClientMode->Enable();
  
  	if ( !view )
  	{
  		view = ( IViewRender * )&g_DefaultViewRender;
  	}
  
  	view->Init();
  	vieweffects->Init();
  
  	C_BaseTempEntity::PrecacheTempEnts();
  
  	input->Init_All();
  
  	VGui_CreateGlobalPanels();
  
  	InitSmokeFogOverlay();
  
  	// Register user messages..
  	CUserMessageRegister::RegisterAll();
  
  	ClientVoiceMgr_Init();
  
  	// Embed voice status icons inside chat element
  	{
  		vgui::VPANEL parent = enginevgui->GetPanel( PANEL_CLIENTDLL );
  		GetClientVoiceMgr()->Init( &g_VoiceStatusHelper, parent );
  	}
  
  	if ( !PhysicsDLLInit( physicsFactory ) )
  		return false;
  
  	g_pGameSaveRestoreBlockSet->AddBlockHandler( GetEntitySaveRestoreBlockHandler() );
  	g_pGameSaveRestoreBlockSet->AddBlockHandler( GetPhysSaveRestoreBlockHandler() );
  	g_pGameSaveRestoreBlockSet->AddBlockHandler( GetViewEffectsRestoreBlockHandler() );
  
  	ClientWorldFactoryInit();
  
  	C_BaseAnimating::InitBoneSetupThreadPool();
  
  #if defined( WIN32 ) && !defined( _X360 )
  	// NVNT connect haptics sytem
  	ConnectHaptics(appSystemFactory);
  #endif
  #ifndef _X360
  	HookHapticMessages(); // Always hook the messages
  #endif
  	return true;
  }
  
  bool CHLClient::ReplayInit( CreateInterfaceFn fnReplayFactory )
  {
  #if defined( REPLAY_ENABLED )
  	if ( !IsPC() )
  		return false;
  	if ( (g_pReplay = (IReplaySystem *)fnReplayFactory( REPLAY_INTERFACE_VERSION, NULL ) ) == NULL )
  		return false;
  	if ( (g_pClientReplayContext = g_pReplay->CL_GetContext()) == NULL )
  		return false;
  
  	return true;
  #else
  	return false;
  #endif
  }
  
  bool CHLClient::ReplayPostInit()
  {
  #if defined( REPLAY_ENABLED )
  	if ( ( g_pReplayManager = g_pClientReplayContext->GetReplayManager() ) == NULL )
  		return false;
  	if ( ( g_pReplayScreenshotManager = g_pClientReplayContext->GetScreenshotManager() ) == NULL )
  		return false;
  	if ( ( g_pReplayPerformanceManager = g_pClientReplayContext->GetPerformanceManager() ) == NULL )
  		return false;
  	if ( ( g_pReplayPerformanceController = g_pClientReplayContext->GetPerformanceController() ) == NULL )
  		return false;
  	if ( ( g_pReplayMovieManager = g_pClientReplayContext->GetMovieManager() ) == NULL )
  		return false;
  	return true;
  #else
  	return false;
  #endif
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Called after client & server DLL are loaded and all systems initialized
  //-----------------------------------------------------------------------------
  void CHLClient::PostInit()
  {
  	IGameSystem::PostInitAllSystems();
  
  #ifdef SIXENSE
  	// allow sixnese input to perform post-init operations
  	g_pSixenseInput->PostInit();
  #endif
  
  	// If we are in VR mode execute headtrack.cfg in PostInit so all the convars will
  	// already be set up
  	if( UseVR() )
  	{
  		// general all-game stuff
  		engine->ExecuteClientCmd( "exec headtrack\\headtrack.cfg" );
  
  		// game specific VR config
  		CUtlString sCmd;
  		sCmd.Format( "exec headtrack_%s.cfg", COM_GetModDirectory() );
  		engine->ExecuteClientCmd( sCmd.Get() );
  
  		engine->ExecuteClientCmd( "vr_start_tracking" );
  
  		vgui::surface()->SetSoftwareCursor( true );
  #if defined(POSIX)
  		ConVarRef m_rawinput( "m_rawinput" );
  		m_rawinput.SetValue( 1 );
  
  		ConVarRef mat_vsync( "mat_vsync" );
  		mat_vsync.SetValue( 0 );
  #endif
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Called when the client .dll is being dismissed
  //-----------------------------------------------------------------------------
  void CHLClient::Shutdown( void )
  {
      if (g_pAchievementsAndStatsInterface)
      {
          g_pAchievementsAndStatsInterface->ReleasePanel();
      }
  
  #ifdef SIXENSE
  	g_pSixenseInput->Shutdown();
  	delete g_pSixenseInput;
  	g_pSixenseInput = NULL;
  #endif
  
  	C_BaseAnimating::ShutdownBoneSetupThreadPool();
  	ClientWorldFactoryShutdown();
  
  	g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetViewEffectsRestoreBlockHandler() );
  	g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetPhysSaveRestoreBlockHandler() );
  	g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetEntitySaveRestoreBlockHandler() );
  
  	ClientVoiceMgr_Shutdown();
  
  	Initializer::FreeAllObjects();
  
  	g_pClientMode->Disable();
  	g_pClientMode->Shutdown();
  
  	input->Shutdown_All();
  	C_BaseTempEntity::ClearDynamicTempEnts();
  	TermSmokeFogOverlay();
  	view->Shutdown();
  	g_pParticleSystemMgr->UncacheAllParticleSystems();
  	UncacheAllMaterials();
  
  	IGameSystem::ShutdownAllSystems();
  	
  	gHUD.Shutdown();
  	VGui_Shutdown();
  	
  	ParticleMgr()->Term();
  	
  	ClearKeyValuesCache();
  
  #ifndef NO_STEAM
  	ClientSteamContext().Shutdown();
  #endif
  
  #ifdef WORKSHOP_IMPORT_ENABLED
  	ShutdownDataModel();
  	DisconnectDataModel();
  	ShutdownFbx();
  #endif
  	
  	// This call disconnects the VGui libraries which we rely on later in the shutdown path, so don't do it
  //	DisconnectTier3Libraries( );
  	DisconnectTier2Libraries( );
  	ConVar_Unregister();
  	DisconnectTier1Libraries( );
  
  	gameeventmanager = NULL;
  
  #if defined( WIN32 ) && !defined( _X360 )
  	// NVNT Disconnect haptics system
  	DisconnectHaptics();
  #endif
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //  Called when the game initializes
  //  and whenever the vid_mode is changed
  //  so the HUD can reinitialize itself.
  // Output : int
  //-----------------------------------------------------------------------------
  int CHLClient::HudVidInit( void )
  {
  	gHUD.VidInit();
  
  	GetClientVoiceMgr()->VidInit();
  
  	return 1;
  }
  
  //-----------------------------------------------------------------------------
  // Method used to allow the client to filter input messages before the 
  // move record is transmitted to the server
  //-----------------------------------------------------------------------------
  void CHLClient::HudProcessInput( bool bActive )
  {
  	g_pClientMode->ProcessInput( bActive );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Called when shared data gets changed, allows dll to modify data
  // Input  : bActive - 
  //-----------------------------------------------------------------------------
  void CHLClient::HudUpdate( bool bActive )
  {
  	float frametime = gpGlobals->frametime;
  
  #if defined( TF_CLIENT_DLL )
  	CRTime::UpdateRealTime();
  #endif
  
  	GetClientVoiceMgr()->Frame( frametime );
  
  	gHUD.UpdateHud( bActive );
  
  	{
  		C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false ); 
  		IGameSystem::UpdateAllSystems( frametime );
  	}
  
  	// run vgui animations
  	vgui::GetAnimationController()->UpdateAnimations( engine->Time() );
  
  	hudlcd->SetGlobalStat( "(time_int)", VarArgs( "%d", (int)gpGlobals->curtime ) );
  	hudlcd->SetGlobalStat( "(time_float)", VarArgs( "%.2f", gpGlobals->curtime ) );
  
  	// I don't think this is necessary any longer, but I will leave it until
  	// I can check into this further.
  	C_BaseTempEntity::CheckDynamicTempEnts();
  
  #ifdef SIXENSE
  	// If we're not connected, update sixense so we can move the mouse cursor when in the menus
  	if( !engine->IsConnected() || engine->IsPaused() )
  	{
  		g_pSixenseInput->SixenseFrame( 0, NULL ); 
  	}
  #endif
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Called to restore to "non"HUD state.
  //-----------------------------------------------------------------------------
  void CHLClient::HudReset( void )
  {
  	gHUD.VidInit();
  	PhysicsReset();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Called to add hud text message
  //-----------------------------------------------------------------------------
  void CHLClient::HudText( const char * message )
  {
  	DispatchHudText( message );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  bool CHLClient::ShouldDrawDropdownConsole()
  {
  #if defined( REPLAY_ENABLED )
  	extern ConVar hud_freezecamhide;
  	extern bool IsTakingAFreezecamScreenshot();
  
  	if ( hud_freezecamhide.GetBool() && IsTakingAFreezecamScreenshot() )
  	{
  		return false;
  	}
  #endif
  
  	return true;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  // Output : ClientClass
  //-----------------------------------------------------------------------------
  ClientClass *CHLClient::GetAllClasses( void )
  {
  	return g_pClientClassHead;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CHLClient::IN_ActivateMouse( void )
  {
  	input->ActivateMouse();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CHLClient::IN_DeactivateMouse( void )
  {
  	input->DeactivateMouse();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CHLClient::IN_Accumulate ( void )
  {
  	input->AccumulateMouse();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CHLClient::IN_ClearStates ( void )
  {
  	input->ClearStates();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Engine can query for particular keys
  // Input  : *name - 
  //-----------------------------------------------------------------------------
  bool CHLClient::IN_IsKeyDown( const char *name, bool& isdown )
  {
  	kbutton_t *key = input->FindKey( name );
  	if ( !key )
  	{
  		return false;
  	}
  	
  	isdown = ( key->state & 1 ) ? true : false;
  
  	// Found the key by name
  	return true;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Engine can issue a key event
  // Input  : eventcode - 
  //			keynum - 
  //			*pszCurrentBinding - 
  void CHLClient::IN_OnMouseWheeled( int nDelta )
  {
  #if defined( REPLAY_ENABLED )
  	CReplayPerformanceEditorPanel *pPerfEditor = ReplayUI_GetPerformanceEditor();
  	if ( pPerfEditor )
  	{
  		pPerfEditor->OnInGameMouseWheelEvent( nDelta );
  	}
  #endif
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Engine can issue a key event
  // Input  : eventcode - 
  //			keynum - 
  //			*pszCurrentBinding - 
  // Output : int
  //-----------------------------------------------------------------------------
  int CHLClient::IN_KeyEvent( int eventcode, ButtonCode_t keynum, const char *pszCurrentBinding )
  {
  	return input->KeyEvent( eventcode, keynum, pszCurrentBinding );
  }
  
  void CHLClient::ExtraMouseSample( float frametime, bool active )
  {
  	Assert( C_BaseEntity::IsAbsRecomputationsEnabled() );
  	Assert( C_BaseEntity::IsAbsQueriesValid() );
  
  	C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false ); 
  
  	MDLCACHE_CRITICAL_SECTION();
  	input->ExtraMouseSample( frametime, active );
  }
  
  void CHLClient::IN_SetSampleTime( float frametime )
  {
  	input->Joystick_SetSampleTime( frametime );
  	input->IN_SetSampleTime( frametime );
  
  #ifdef SIXENSE
  	g_pSixenseInput->ResetFrameTime( frametime );
  #endif
  }
  //-----------------------------------------------------------------------------
  // Purpose: Fills in usercmd_s structure based on current view angles and key/controller inputs
  // Input  : frametime - timestamp for last frame
  //			*cmd - the command to fill in
  //			active - whether the user is fully connected to a server
  //-----------------------------------------------------------------------------
  void CHLClient::CreateMove ( int sequence_number, float input_sample_frametime, bool active )
  {
  
  	Assert( C_BaseEntity::IsAbsRecomputationsEnabled() );
  	Assert( C_BaseEntity::IsAbsQueriesValid() );
  
  	C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false ); 
  
  	MDLCACHE_CRITICAL_SECTION();
  	input->CreateMove( sequence_number, input_sample_frametime, active );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  // Input  : *buf - 
  //			from - 
  //			to - 
  //-----------------------------------------------------------------------------
  bool CHLClient::WriteUsercmdDeltaToBuffer( bf_write *buf, int from, int to, bool isnewcommand )
  {
  	return input->WriteUsercmdDeltaToBuffer( buf, from, to, isnewcommand );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  // Input  : buf - 
  //			buffersize - 
  //			slot - 
  //-----------------------------------------------------------------------------
  void CHLClient::EncodeUserCmdToBuffer( bf_write& buf, int slot )
  {
  	input->EncodeUserCmdToBuffer( buf, slot );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  // Input  : buf - 
  //			buffersize - 
  //			slot - 
  //-----------------------------------------------------------------------------
  void CHLClient::DecodeUserCmdFromBuffer( bf_read& buf, int slot )
  {
  	input->DecodeUserCmdFromBuffer( buf, slot );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CHLClient::View_Render( vrect_t *rect )
  {
  	VPROF( "View_Render" );
  
  	// UNDONE: This gets hit at startup sometimes, investigate - will cause NaNs in calcs inside Render()
  	if ( rect->width == 0 || rect->height == 0 )
  		return;
  
  	view->Render( rect );
  	UpdatePerfStats();
  }
  
  
  //-----------------------------------------------------------------------------
  // Gets the location of the player viewpoint
  //-----------------------------------------------------------------------------
  bool CHLClient::GetPlayerView( CViewSetup &playerView )
  {
  	playerView = *view->GetPlayerViewSetup();
  	return true;
  }
  
  //-----------------------------------------------------------------------------
  // Matchmaking
  //-----------------------------------------------------------------------------
  void CHLClient::SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties )
  {
  	presence->SetupGameProperties( contexts, properties );
  }
  
  uint CHLClient::GetPresenceID( const char *pIDName )
  {
  	return presence->GetPresenceID( pIDName );
  }
  
  const char *CHLClient::GetPropertyIdString( const uint id )
  {
  	return presence->GetPropertyIdString( id );
  }
  
  void CHLClient::GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes )
  {
  	presence->GetPropertyDisplayString( id, value, pOutput, nBytes );
  }
  
  void CHLClient::StartStatsReporting( HANDLE handle, bool bArbitrated )
  {
  	presence->StartStatsReporting( handle, bArbitrated );
  }
  
  //-----------------------------------------------------------------------------
  //
  //-----------------------------------------------------------------------------
  void CHLClient::InvalidateMdlCache()
  {
  	C_BaseAnimating *pAnimating;
  	for ( C_BaseEntity *pEntity = ClientEntityList().FirstBaseEntity(); pEntity; pEntity = ClientEntityList().NextBaseEntity(pEntity) )
  	{
  		pAnimating = dynamic_cast<C_BaseAnimating *>(pEntity);
  		if ( pAnimating )
  		{
  			pAnimating->InvalidateMdlCache();
  		}
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  // Input  : *pSF - 
  //-----------------------------------------------------------------------------
  void CHLClient::View_Fade( ScreenFade_t *pSF )
  {
  	if ( pSF != NULL )
  		vieweffects->Fade( *pSF );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Per level init
  //-----------------------------------------------------------------------------
  void CHLClient::LevelInitPreEntity( char const* pMapName )
  {
  	// HACK: Bogus, but the logic is too complicated in the engine
  	if (g_bLevelInitialized)
  		return;
  	g_bLevelInitialized = true;
  
  	input->LevelInit();
  
  	vieweffects->LevelInit();
  	
  	//Tony; loadup per-map manifests.
  	ParseParticleEffectsMap( pMapName, true );
  	
  	// Tell mode manager that map is changing
  	modemanager->LevelInit( pMapName );
  	ParticleMgr()->LevelInit();
  
  	hudlcd->SetGlobalStat( "(mapname)", pMapName );
  
  	C_BaseTempEntity::ClearDynamicTempEnts();
  	clienteffects->Flush();
  	view->LevelInit();
  	tempents->LevelInit();
  	ResetToneMapping(1.0);
  
  	IGameSystem::LevelInitPreEntityAllSystems(pMapName);
  
  #ifdef USES_ECON_ITEMS
  	GameItemSchema_t *pItemSchema = ItemSystem()->GetItemSchema();
  	if ( pItemSchema )
  	{
  		pItemSchema->BInitFromDelayedBuffer();
  	}
  #endif // USES_ECON_ITEMS
  
  	ResetWindspeed();
  
  #if !defined( NO_ENTITY_PREDICTION )
  	// don't do prediction if single player!
  	// don't set direct because of FCVAR_USERINFO
  	if ( gpGlobals->maxClients > 1 )
  	{
  		if ( !cl_predict->GetInt() )
  		{
  			engine->ClientCmd( "cl_predict 1" );
  		}
  	}
  	else
  	{
  		if ( cl_predict->GetInt() )
  		{
  			engine->ClientCmd( "cl_predict 0" );
  		}
  	}
  #endif
  
  	// Check low violence settings for this map
  	g_RagdollLVManager.SetLowViolence( pMapName );
  
  	gHUD.LevelInit();
  
  #if defined( REPLAY_ENABLED )
  	// Initialize replay ragdoll recorder
  	if ( !engine->IsPlayingDemo() )
  	{
  		CReplayRagdollRecorder::Instance().Init();
  	}
  #endif
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Per level init
  //-----------------------------------------------------------------------------
  void CHLClient::LevelInitPostEntity( )
  {
  	IGameSystem::LevelInitPostEntityAllSystems();
  	C_PhysPropClientside::RecreateAll();
  	internalCenterPrint->Clear();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Reset our global string table pointers
  //-----------------------------------------------------------------------------
  void CHLClient::ResetStringTablePointers()
  {
  	g_pStringTableParticleEffectNames = NULL;
  	g_StringTableEffectDispatch = NULL;
  	g_StringTableVguiScreen = NULL;
  	g_pStringTableMaterials = NULL;
  	g_pStringTableInfoPanel = NULL;
  	g_pStringTableClientSideChoreoScenes = NULL;
  	g_pStringTableServerMapCycle = NULL;
  
  #ifdef TF_CLIENT_DLL
  	g_pStringTableServerPopFiles = NULL;
  	g_pStringTableServerMapCycleMvM = NULL;
  #endif
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Per level de-init
  //-----------------------------------------------------------------------------
  void CHLClient::LevelShutdown( void )
  {
  	// HACK: Bogus, but the logic is too complicated in the engine
  	if (!g_bLevelInitialized)
  		return;
  
  	g_bLevelInitialized = false;
  
  	// Disable abs recomputations when everything is shutting down
  	CBaseEntity::EnableAbsRecomputations( false );
  
  	// Level shutdown sequence.
  	// First do the pre-entity shutdown of all systems
  	IGameSystem::LevelShutdownPreEntityAllSystems();
  
  	C_PhysPropClientside::DestroyAll();
  
  	modemanager->LevelShutdown();
  
  	// Remove temporary entities before removing entities from the client entity list so that the te_* may
  	// clean up before hand.
  	tempents->LevelShutdown();
  
  	// Now release/delete the entities
  	cl_entitylist->Release();
  
  	C_BaseEntityClassList *pClassList = s_pClassLists;
  	while ( pClassList )
  	{
  		pClassList->LevelShutdown();
  		pClassList = pClassList->m_pNextClassList;
  	}
  
  	// Now do the post-entity shutdown of all systems
  	IGameSystem::LevelShutdownPostEntityAllSystems();
  
  	view->LevelShutdown();
  	beams->ClearBeams();
  	ParticleMgr()->RemoveAllEffects();
  	
  	StopAllRumbleEffects();
  
  	gHUD.LevelShutdown();
  
  	internalCenterPrint->Clear();
  
  	messagechars->Clear();
  
  	g_pParticleSystemMgr->UncacheAllParticleSystems();
  	UncacheAllMaterials();
  
  #ifdef _XBOX
  	ReleaseRenderTargets();
  #endif
  
  	// string tables are cleared on disconnect from a server, so reset our global pointers to NULL
  	ResetStringTablePointers();
  
  #if defined( REPLAY_ENABLED )
  	// Shutdown the ragdoll recorder
  	CReplayRagdollRecorder::Instance().Shutdown();
  	CReplayRagdollCache::Instance().Shutdown();
  #endif
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Engine received crosshair offset ( autoaim )
  // Input  : angle - 
  //-----------------------------------------------------------------------------
  void CHLClient::SetCrosshairAngle( const QAngle& angle )
  {
  	CHudCrosshair *crosshair = GET_HUDELEMENT( CHudCrosshair );
  	if ( crosshair )
  	{
  		crosshair->SetCrosshairAngle( angle );
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Helper to initialize sprite from .spr semaphor
  // Input  : *pSprite - 
  //			*loadname - 
  //-----------------------------------------------------------------------------
  void CHLClient::InitSprite( CEngineSprite *pSprite, const char *loadname )
  {
  	if ( pSprite )
  	{
  		pSprite->Init( loadname );
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  // Input  : *pSprite - 
  //-----------------------------------------------------------------------------
  void CHLClient::ShutdownSprite( CEngineSprite *pSprite )
  {
  	if ( pSprite )
  	{
  		pSprite->Shutdown();
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Tells engine how much space to allocate for sprite objects
  // Output : int
  //-----------------------------------------------------------------------------
  int CHLClient::GetSpriteSize( void ) const
  {
  	return sizeof( CEngineSprite );
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  // Input  : entindex - 
  //			bTalking - 
  //-----------------------------------------------------------------------------
  void CHLClient::VoiceStatus( int entindex, qboolean bTalking )
  {
  	GetClientVoiceMgr()->UpdateSpeakerStatus( entindex, !!bTalking );
  }
  
  
  //-----------------------------------------------------------------------------
  // Called when the string table for materials changes
  //-----------------------------------------------------------------------------
  void OnMaterialStringTableChanged( void *object, INetworkStringTable *stringTable, int stringNumber, const char *newString, void const *newData )
  {
  	// Make sure this puppy is precached
  	gHLClient.PrecacheMaterial( newString );
  	RequestCacheUsedMaterials();
  }
  
  
  //-----------------------------------------------------------------------------
  // Called when the string table for particle systems changes
  //-----------------------------------------------------------------------------
  void OnParticleSystemStringTableChanged( void *object, INetworkStringTable *stringTable, int stringNumber, const char *newString, void const *newData )
  {
  	// Make sure this puppy is precached
  	g_pParticleSystemMgr->PrecacheParticleSystem( newString );
  	RequestCacheUsedMaterials();
  }
  
  
  //-----------------------------------------------------------------------------
  // Called when the string table for VGUI changes
  //-----------------------------------------------------------------------------
  void OnVguiScreenTableChanged( void *object, INetworkStringTable *stringTable, int stringNumber, const char *newString, void const *newData )
  {
  	// Make sure this puppy is precached
  	vgui::Panel *pPanel = PanelMetaClassMgr()->CreatePanelMetaClass( newString, 100, NULL, NULL );
  	if ( pPanel )
  		PanelMetaClassMgr()->DestroyPanelMetaClass( pPanel );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Preload the string on the client (if single player it should already be in the cache from the server!!!)
  // Input  : *object - 
  //			*stringTable - 
  //			stringNumber - 
  //			*newString - 
  //			*newData - 
  //-----------------------------------------------------------------------------
  void OnSceneStringTableChanged( void *object, INetworkStringTable *stringTable, int stringNumber, const char *newString, void const *newData )
  {
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Hook up any callbacks here, the table definition has been parsed but 
  //  no data has been added yet
  //-----------------------------------------------------------------------------
  void CHLClient::InstallStringTableCallback( const char *tableName )
  {
  	// Here, cache off string table IDs
  	if (!Q_strcasecmp(tableName, "VguiScreen"))
  	{
  		// Look up the id 
  		g_StringTableVguiScreen = networkstringtable->FindTable( tableName );
  
  		// When the material list changes, we need to know immediately
  		g_StringTableVguiScreen->SetStringChangedCallback( NULL, OnVguiScreenTableChanged );
  	}
  	else if (!Q_strcasecmp(tableName, "Materials"))
  	{
  		// Look up the id 
  		g_pStringTableMaterials = networkstringtable->FindTable( tableName );
  
  		// When the material list changes, we need to know immediately
  		g_pStringTableMaterials->SetStringChangedCallback( NULL, OnMaterialStringTableChanged );
  	}
  	else if ( !Q_strcasecmp( tableName, "EffectDispatch" ) )
  	{
  		g_StringTableEffectDispatch = networkstringtable->FindTable( tableName );
  	}
  	else if ( !Q_strcasecmp( tableName, "InfoPanel" ) )
  	{
  		g_pStringTableInfoPanel = networkstringtable->FindTable( tableName );
  	}
  	else if ( !Q_strcasecmp( tableName, "Scenes" ) )
  	{
  		g_pStringTableClientSideChoreoScenes = networkstringtable->FindTable( tableName );
  		g_pStringTableClientSideChoreoScenes->SetStringChangedCallback( NULL, OnSceneStringTableChanged );
  	}
  	else if ( !Q_strcasecmp( tableName, "ParticleEffectNames" ) )
  	{
  		g_pStringTableParticleEffectNames = networkstringtable->FindTable( tableName );
  		networkstringtable->SetAllowClientSideAddString( g_pStringTableParticleEffectNames, true );
  		// When the particle system list changes, we need to know immediately
  		g_pStringTableParticleEffectNames->SetStringChangedCallback( NULL, OnParticleSystemStringTableChanged );
  	}
  	else if ( !Q_strcasecmp( tableName, "ServerMapCycle" ) )
  	{
  		g_pStringTableServerMapCycle = networkstringtable->FindTable( tableName );
  	}
  #ifdef TF_CLIENT_DLL
  	else if ( !Q_strcasecmp( tableName, "ServerPopFiles" ) )
  	{
  		g_pStringTableServerPopFiles = networkstringtable->FindTable( tableName );
  	}
  	else if ( !Q_strcasecmp( tableName, "ServerMapCycleMvM" ) )
  	{
  		g_pStringTableServerMapCycleMvM = networkstringtable->FindTable( tableName );
  	}
  #endif
  
  	InstallStringTableCallback_GameRules();
  }
  
  
  //-----------------------------------------------------------------------------
  // Material precache
  //-----------------------------------------------------------------------------
  void CHLClient::PrecacheMaterial( const char *pMaterialName )
  {
  	Assert( pMaterialName );
  
  	int nLen = Q_strlen( pMaterialName );
  	char *pTempBuf = (char*)stackalloc( nLen + 1 );
  	memcpy( pTempBuf, pMaterialName, nLen + 1 );
  	char *pFound = Q_strstr( pTempBuf, ".vmt\0" );
  	if ( pFound )
  	{
  		*pFound = 0;
  	}
  		
  	IMaterial *pMaterial = materials->FindMaterial( pTempBuf, TEXTURE_GROUP_PRECACHED );
  	if ( !IsErrorMaterial( pMaterial ) )
  	{
  		pMaterial->IncrementReferenceCount();
  		m_CachedMaterials.AddToTail( pMaterial );
  	}
  	else
  	{
  		if (IsOSX())
  		{
  			printf("\n ##### CHLClient::PrecacheMaterial could not find material %s (%s)", pMaterialName, pTempBuf );
  		}
  	}
  }
  
  void CHLClient::UncacheAllMaterials( )
  {
  	for (int i = m_CachedMaterials.Count(); --i >= 0; )
  	{
  		m_CachedMaterials[i]->DecrementReferenceCount();
  	}
  	m_CachedMaterials.RemoveAll();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  // Input  : *pszName - 
  //			iSize - 
  //			*pbuf - 
  // Output : Returns true on success, false on failure.
  //-----------------------------------------------------------------------------
  bool CHLClient::DispatchUserMessage( int msg_type, bf_read &msg_data )
  {
  	return usermessages->DispatchUserMessage( msg_type, msg_data );
  }
  
  
  void SimulateEntities()
  {
  	VPROF_BUDGET("Client SimulateEntities", VPROF_BUDGETGROUP_CLIENT_SIM);
  
  	// Service timer events (think functions).
    	ClientThinkList()->PerformThinkFunctions();
  
  	// TODO: make an ISimulateable interface so C_BaseNetworkables can simulate?
  	{
  		VPROF_("C_BaseEntity::Simulate", 1, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT);
  		C_BaseEntityIterator iterator;
  		C_BaseEntity *pEnt;
  		while ( (pEnt = iterator.Next()) != NULL )
  		{
  			pEnt->Simulate();
  		}
  	}
  }
  
  
  bool AddDataChangeEvent( IClientNetworkable *ent, DataUpdateType_t updateType, int *pStoredEvent )
  {
  	VPROF( "AddDataChangeEvent" );
  
  	Assert( ent );
  	// Make sure we don't already have an event queued for this guy.
  	if ( *pStoredEvent >= 0 )
  	{
  		Assert( g_DataChangedEvents[*pStoredEvent].m_pEntity == ent );
  
  		// DATA_UPDATE_CREATED always overrides DATA_UPDATE_CHANGED.
  		if ( updateType == DATA_UPDATE_CREATED )
  			g_DataChangedEvents[*pStoredEvent].m_UpdateType = updateType;
  	
  		return false;
  	}
  	else
  	{
  		*pStoredEvent = g_DataChangedEvents.AddToTail( CDataChangedEvent( ent, updateType, pStoredEvent ) );
  		return true;
  	}
  }
  
  
  void ClearDataChangedEvent( int iStoredEvent )
  {
  	if ( iStoredEvent != -1 )
  		g_DataChangedEvents.Remove( iStoredEvent );
  }
  
  
  void ProcessOnDataChangedEvents()
  {
  	VPROF_("ProcessOnDataChangedEvents", 1, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT);
  	FOR_EACH_LL( g_DataChangedEvents, i )
  	{
  		CDataChangedEvent *pEvent = &g_DataChangedEvents[i];
  
  		// Reset their stored event identifier.		
  		*pEvent->m_pStoredEvent = -1;
  
  		// Send the event.
  		IClientNetworkable *pNetworkable = pEvent->m_pEntity;
  		pNetworkable->OnDataChanged( pEvent->m_UpdateType );
  	}
  
  	g_DataChangedEvents.Purge();
  }
  
  
  void UpdateClientRenderableInPVSStatus()
  {
  	// Vis for this view should already be setup at this point.
  
  	// For each client-only entity, notify it if it's newly coming into the PVS.
  	CUtlLinkedList<CClientEntityList::CPVSNotifyInfo,unsigned short> &theList = ClientEntityList().GetPVSNotifiers();
  	FOR_EACH_LL( theList, i )
  	{
  		CClientEntityList::CPVSNotifyInfo *pInfo = &theList[i];
  
  		if ( pInfo->m_InPVSStatus & INPVS_YES )
  		{
  			// Ok, this entity already thinks it's in the PVS. No need to notify it.
  			// We need to set the INPVS_YES_THISFRAME flag if it's in this frame at all, so we 
  			// don't tell the entity it's not in the PVS anymore at the end of the frame.
  			if ( !( pInfo->m_InPVSStatus & INPVS_THISFRAME ) )
  			{
  				if ( g_pClientLeafSystem->IsRenderableInPVS( pInfo->m_pRenderable ) )
  				{
  					pInfo->m_InPVSStatus |= INPVS_THISFRAME;
  				}
  			}
  		}
  		else
  		{
  			// This entity doesn't think it's in the PVS yet. If it is now in the PVS, let it know.
  			if ( g_pClientLeafSystem->IsRenderableInPVS( pInfo->m_pRenderable ) )
  			{
  				pInfo->m_InPVSStatus |= ( INPVS_YES | INPVS_THISFRAME | INPVS_NEEDSNOTIFY );
  			}
  		}
  	}	
  }
  
  void UpdatePVSNotifiers()
  {
  	MDLCACHE_CRITICAL_SECTION();
  
  	// At this point, all the entities that were rendered in the previous frame have INPVS_THISFRAME set
  	// so we can tell the entities that aren't in the PVS anymore so.
  	CUtlLinkedList<CClientEntityList::CPVSNotifyInfo,unsigned short> &theList = ClientEntityList().GetPVSNotifiers();
  	FOR_EACH_LL( theList, i )
  	{
  		CClientEntityList::CPVSNotifyInfo *pInfo = &theList[i];
  
  		// If this entity thinks it's in the PVS, but it wasn't in the PVS this frame, tell it so.
  		if ( pInfo->m_InPVSStatus & INPVS_YES )
  		{
  			if ( pInfo->m_InPVSStatus & INPVS_THISFRAME )
  			{
  				if ( pInfo->m_InPVSStatus & INPVS_NEEDSNOTIFY )
  				{
  					pInfo->m_pNotify->OnPVSStatusChanged( true );
  				}
  				// Clear it for the next time around.
  				pInfo->m_InPVSStatus &= ~( INPVS_THISFRAME | INPVS_NEEDSNOTIFY );
  			}
  			else
  			{
  				pInfo->m_InPVSStatus &= ~INPVS_YES;
  				pInfo->m_pNotify->OnPVSStatusChanged( false );
  			}
  		}
  	}
  }
  
  
  void OnRenderStart()
  {
  	VPROF( "OnRenderStart" );
  	MDLCACHE_CRITICAL_SECTION();
  	MDLCACHE_COARSE_LOCK();
  
  #ifdef PORTAL
  	g_pPortalRender->UpdatePortalPixelVisibility(); //updating this one or two lines before querying again just isn't cutting it. Update as soon as it's cheap to do so.
  #endif
  
  	partition->SuppressLists( PARTITION_ALL_CLIENT_EDICTS, true );
  	C_BaseEntity::SetAbsQueriesValid( false );
  
  	Rope_ResetCounters();
  
  	// Interpolate server entities and move aiments.
  	{
  		PREDICTION_TRACKVALUECHANGESCOPE( "interpolation" );
  		C_BaseEntity::InterpolateServerEntities();
  	}
  
  	{
  		// vprof node for this bloc of math
  		VPROF( "OnRenderStart: dirty bone caches");
  		// Invalidate any bone information.
  		C_BaseAnimating::InvalidateBoneCaches();
  
  		C_BaseEntity::SetAbsQueriesValid( true );
  		C_BaseEntity::EnableAbsRecomputations( true );
  
  		// Enable access to all model bones except view models.
  		// This is necessary for aim-ent computation to occur properly
  		C_BaseAnimating::PushAllowBoneAccess( true, false, "OnRenderStart->CViewRender::SetUpView" ); // pops in CViewRender::SetUpView
  
  		// FIXME: This needs to be done before the player moves; it forces
  		// aiments the player may be attached to to forcibly update their position
  		C_BaseEntity::MarkAimEntsDirty();
  	}
  
  	// Make sure the camera simulation happens before OnRenderStart, where it's used.
  	// NOTE: the only thing that happens in CAM_Think is thirdperson related code.
  	input->CAM_Think();
  
  	// This will place the player + the view models + all parent
  	// entities	at the correct abs position so that their attachment points
  	// are at the correct location
  	view->OnRenderStart();
  
  	RopeManager()->OnRenderStart();
  	
  	// This will place all entities in the correct position in world space and in the KD-tree
  	C_BaseAnimating::UpdateClientSideAnimations();
  
  	partition->SuppressLists( PARTITION_ALL_CLIENT_EDICTS, false );
  
  	// Process OnDataChanged events.
  	ProcessOnDataChangedEvents();
  
  	// Reset the overlay alpha. Entities can change the state of this in their think functions.
  	g_SmokeFogOverlayAlpha = 0;	
  
  	// This must occur prior to SimulatEntities,
  	// which is where the client thinks for c_colorcorrection + c_colorcorrectionvolumes
  	// update the color correction weights.
  	// FIXME: The place where IGameSystem::Update is called should be in here
  	// so we don't have to explicitly call ResetColorCorrectionWeights + SimulateEntities, etc.
  	g_pColorCorrectionMgr->ResetColorCorrectionWeights();
  
  	// Simulate all the entities.
  	SimulateEntities();
  	PhysicsSimulate();
  
  	C_BaseAnimating::ThreadedBoneSetup();
  
  	{
  		VPROF_("Client TempEnts", 0, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT);
  		// This creates things like temp entities.
  		engine->FireEvents();
  
  		// Update temp entities
  		tempents->Update();
  
  		// Update temp ent beams...
  		beams->UpdateTempEntBeams();
  		
  		// Lock the frame from beam additions
  		SetBeamCreationAllowed( false );
  	}
  
  	// Update particle effects (eventually, the effects should use Simulate() instead of having
  	// their own update system).
  	{
  		// Enable FP exceptions here when FP_EXCEPTIONS_ENABLED is defined,
  		// to help track down bad math.
  		FPExceptionEnabler enableExceptions;
  		VPROF_BUDGET( "ParticleMgr()->Simulate", VPROF_BUDGETGROUP_PARTICLE_SIMULATION );
  		ParticleMgr()->Simulate( gpGlobals->frametime );
  	}
  
  	// Now that the view model's position is setup and aiments are marked dirty, update
  	// their positions so they're in the leaf system correctly.
  	C_BaseEntity::CalcAimEntPositions();
  
  	// For entities marked for recording, post bone messages to IToolSystems
  	if ( ToolsEnabled() )
  	{
  		C_BaseEntity::ToolRecordEntities();
  	}
  
  #if defined( REPLAY_ENABLED )
  	// This will record any ragdolls if Replay mode is enabled on the server
  	CReplayRagdollRecorder::Instance().Think();
  	CReplayRagdollCache::Instance().Think();
  #endif
  
  	// Finally, link all the entities into the leaf system right before rendering.
  	C_BaseEntity::AddVisibleEntities();
  }
  
  
  void OnRenderEnd()
  {
  	// Disallow access to bones (access is enabled in CViewRender::SetUpView).
  	C_BaseAnimating::PopBoneAccess( "CViewRender::SetUpView->OnRenderEnd" );
  
  	UpdatePVSNotifiers();
  
  	DisplayBoneSetupEnts();
  }
  
  
  
  void CHLClient::FrameStageNotify( ClientFrameStage_t curStage )
  {
  	g_CurFrameStage = curStage;
  
  	switch( curStage )
  	{
  	default:
  		break;
  
  	case FRAME_RENDER_START:
  		{
  			VPROF( "CHLClient::FrameStageNotify FRAME_RENDER_START" );
  
  			// Last thing before rendering, run simulation.
  			OnRenderStart();
  		}
  		break;
  		
  	case FRAME_RENDER_END:
  		{
  			VPROF( "CHLClient::FrameStageNotify FRAME_RENDER_END" );
  			OnRenderEnd();
  
  			PREDICTION_SPEWVALUECHANGES();
  		}
  		break;
  		
  	case FRAME_NET_UPDATE_START:
  		{
  			VPROF( "CHLClient::FrameStageNotify FRAME_NET_UPDATE_START" );
  			// disabled all recomputations while we update entities
  			C_BaseEntity::EnableAbsRecomputations( false );
  			C_BaseEntity::SetAbsQueriesValid( false );
  			Interpolation_SetLastPacketTimeStamp( engine->GetLastTimeStamp() );
  			partition->SuppressLists( PARTITION_ALL_CLIENT_EDICTS, true );
  
  			PREDICTION_STARTTRACKVALUE( "netupdate" );
  		}
  		break;
  	case FRAME_NET_UPDATE_END:
  		{
  			ProcessCacheUsedMaterials();
  
  			// reenable abs recomputation since now all entities have been updated
  			C_BaseEntity::EnableAbsRecomputations( true );
  			C_BaseEntity::SetAbsQueriesValid( true );
  			partition->SuppressLists( PARTITION_ALL_CLIENT_EDICTS, false );
  
  			PREDICTION_ENDTRACKVALUE();
  		}
  		break;
  	case FRAME_NET_UPDATE_POSTDATAUPDATE_START:
  		{
  			VPROF( "CHLClient::FrameStageNotify FRAME_NET_UPDATE_POSTDATAUPDATE_START" );
  			PREDICTION_STARTTRACKVALUE( "postdataupdate" );
  		}
  		break;
  	case FRAME_NET_UPDATE_POSTDATAUPDATE_END:
  		{
  			VPROF( "CHLClient::FrameStageNotify FRAME_NET_UPDATE_POSTDATAUPDATE_END" );
  			PREDICTION_ENDTRACKVALUE();
  			// Let prediction copy off pristine data
  			prediction->PostEntityPacketReceived();
  			HLTVCamera()->PostEntityPacketReceived();
  #if defined( REPLAY_ENABLED )
  			ReplayCamera()->PostEntityPacketReceived();
  #endif
  		}
  		break;
  	case FRAME_START:
  		{
  			// Mark the frame as open for client fx additions
  			SetFXCreationAllowed( true );
  			SetBeamCreationAllowed( true );
  			C_BaseEntity::CheckCLInterpChanged();
  		}
  		break;
  	}
  }
  
  CSaveRestoreData *SaveInit( int size );
  
  // Save/restore system hooks
  CSaveRestoreData  *CHLClient::SaveInit( int size )
  {
  	return ::SaveInit(size);
  }
  
  void CHLClient::SaveWriteFields( CSaveRestoreData *pSaveData, const char *pname, void *pBaseData, datamap_t *pMap, typedescription_t *pFields, int fieldCount )
  {
  	CSave saveHelper( pSaveData );
  	saveHelper.WriteFields( pname, pBaseData, pMap, pFields, fieldCount );
  }
  
  void CHLClient::SaveReadFields( CSaveRestoreData *pSaveData, const char *pname, void *pBaseData, datamap_t *pMap, typedescription_t *pFields, int fieldCount )
  {
  	CRestore restoreHelper( pSaveData );
  	restoreHelper.ReadFields( pname, pBaseData, pMap, pFields, fieldCount );
  }
  
  void CHLClient::PreSave( CSaveRestoreData *s )
  {
  	g_pGameSaveRestoreBlockSet->PreSave( s );
  }
  
  void CHLClient::Save( CSaveRestoreData *s )
  {
  	CSave saveHelper( s );
  	g_pGameSaveRestoreBlockSet->Save( &saveHelper );
  }
  
  void CHLClient::WriteSaveHeaders( CSaveRestoreData *s )
  {
  	CSave saveHelper( s );
  	g_pGameSaveRestoreBlockSet->WriteSaveHeaders( &saveHelper );
  	g_pGameSaveRestoreBlockSet->PostSave();
  }
  
  void CHLClient::ReadRestoreHeaders( CSaveRestoreData *s )
  {
  	CRestore restoreHelper( s );
  	g_pGameSaveRestoreBlockSet->PreRestore();
  	g_pGameSaveRestoreBlockSet->ReadRestoreHeaders( &restoreHelper );
  }
  
  void CHLClient::Restore( CSaveRestoreData *s, bool b )
  {
  	CRestore restore(s);
  	g_pGameSaveRestoreBlockSet->Restore( &restore, b );
  	g_pGameSaveRestoreBlockSet->PostRestore();
  }
  
  static CUtlVector<EHANDLE> g_RestoredEntities;
  
  void AddRestoredEntity( C_BaseEntity *pEntity )
  {
  	if ( !pEntity )
  		return;
  
  	g_RestoredEntities.AddToTail( EHANDLE(pEntity) );
  }
  
  void CHLClient::DispatchOnRestore()
  {
  	for ( int i = 0; i < g_RestoredEntities.Count(); i++ )
  	{
  		if ( g_RestoredEntities[i] != NULL )
  		{
  			MDLCACHE_CRITICAL_SECTION();
  			g_RestoredEntities[i]->OnRestore();
  		}
  	}
  	g_RestoredEntities.RemoveAll();
  }
  
  void CHLClient::WriteSaveGameScreenshot( const char *pFilename )
  {
  	view->WriteSaveGameScreenshot( pFilename );
  }
  
  // Given a list of "S(wavname) S(wavname2)" tokens, look up the localized text and emit
  //  the appropriate close caption if running with closecaption = 1
  void CHLClient::EmitSentenceCloseCaption( char const *tokenstream )
  {
  	extern ConVar closecaption;
  	
  	if ( !closecaption.GetBool() )
  		return;
  
  	CHudCloseCaption *hudCloseCaption = GET_HUDELEMENT( CHudCloseCaption );
  	if ( hudCloseCaption )
  	{
  #ifdef HOE_DLL
  		hudCloseCaption->ProcessSentenceCaptionStream( tokenstream, "", 0 );
  #else // HOE_DLL
  		hudCloseCaption->ProcessSentenceCaptionStream( tokenstream );
  #endif // HOE_DLL
  	}
  }
  
  
  void CHLClient::EmitCloseCaption( char const *captionname, float duration )
  {
  #ifdef HOE_DLL
  	// The engine.dll calls this when the server calls enginesound->EmitSentenceByIndex.
  	// We don't know which entity is playing the sentence and can't get its CC icon.
  	// So now the server parses sentences.txt and sends the caption to the client.
  	return; ///////////////////////////////////////////
  #else // HOE_DLL
  	extern ConVar closecaption;
  
  	if ( !closecaption.GetBool() )
  		return;
  
  	CHudCloseCaption *hudCloseCaption = GET_HUDELEMENT( CHudCloseCaption );
  	if ( hudCloseCaption )
  	{
  		hudCloseCaption->ProcessCaption( captionname, duration );
  	}
  #endif // HOE_DLL
  }
  
  CStandardRecvProxies* CHLClient::GetStandardRecvProxies()
  {
  	return &g_StandardRecvProxies;
  }
  
  bool CHLClient::CanRecordDemo( char *errorMsg, int length ) const
  {
  	if ( GetClientModeNormal() )
  	{
  		return GetClientModeNormal()->CanRecordDemo( errorMsg, length );
  	}
  
  	return true;
  }
  
  void CHLClient::OnDemoRecordStart( char const* pDemoBaseName )
  {
  }
  
  void CHLClient::OnDemoRecordStop()
  {
  }
  
  void CHLClient::OnDemoPlaybackStart( char const* pDemoBaseName )
  {
  #if defined( REPLAY_ENABLED )
  	// Load any ragdoll override frames from disk
  	char szRagdollFile[MAX_OSPATH];
  	V_snprintf( szRagdollFile, sizeof(szRagdollFile), "%s.dmx", pDemoBaseName );
  	CReplayRagdollCache::Instance().Init( szRagdollFile );
  #endif
  }
  
  void CHLClient::OnDemoPlaybackStop()
  {
  #ifdef DEMOPOLISH_ENABLED
  	if ( DemoPolish_GetController().m_bInit )
  	{
  		DemoPolish_GetController().Shutdown();
  	}
  #endif
  
  #if defined( REPLAY_ENABLED )
  	CReplayRagdollCache::Instance().Shutdown();
  #endif
  }
  
  int CHLClient::GetScreenWidth()
  {
  	return ScreenWidth();
  }
  
  int CHLClient::GetScreenHeight()
  {
  	return ScreenHeight();
  }
  
  // NEW INTERFACES
  // save game screenshot writing
  void CHLClient::WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height, bool bCreatePowerOf2Padded/*=false*/,
  											   bool bWriteVTF/*=false*/ )
  {
  	view->WriteSaveGameScreenshotOfSize( pFilename, width, height, bCreatePowerOf2Padded, bWriteVTF );
  }
  
  // See RenderViewInfo_t
  void CHLClient::RenderView( const CViewSetup &setup, int nClearFlags, int whatToDraw )
  {
  	VPROF("RenderView");
  	view->RenderView( setup, nClearFlags, whatToDraw );
  }
  
  void ReloadSoundEntriesInList( IFileList *pFilesToReload );
  
  //-----------------------------------------------------------------------------
  // For sv_pure mode. The filesystem figures out which files the client needs to reload to be "pure" ala the server's preferences.
  //-----------------------------------------------------------------------------
  void CHLClient::ReloadFilesInList( IFileList *pFilesToReload )
  {
  	ReloadParticleEffectsInList( pFilesToReload );
  	ReloadSoundEntriesInList( pFilesToReload );
  }
  
  bool CHLClient::HandleUiToggle()
  {
  #if defined( REPLAY_ENABLED )
  	if ( !g_pEngineReplay || !g_pEngineReplay->IsSupportedModAndPlatform() )
  		return false;
  
  	CReplayPerformanceEditorPanel *pEditor = ReplayUI_GetPerformanceEditor();
  	if ( !pEditor )
  		return false;
  
  	pEditor->HandleUiToggle();
  
  	return true;
  
  #else
  	return false;
  #endif
  }
  
  bool CHLClient::ShouldAllowConsole()
  {
  	return true;
  }
  
  CRenamedRecvTableInfo *CHLClient::GetRenamedRecvTableInfos()
  {
  	return g_pRenamedRecvTableInfoHead;
  }
  
  CMouthInfo g_ClientUIMouth;
  // Get the mouthinfo for the sound being played inside UI panels
  CMouthInfo *CHLClient::GetClientUIMouthInfo()
  {
  	return &g_ClientUIMouth;
  }
  
  void CHLClient::FileReceived( const char * fileName, unsigned int transferID )
  {
  	if ( g_pGameRules )
  	{
  		g_pGameRules->OnFileReceived( fileName, transferID );
  	}
  }
  
  void CHLClient::ClientAdjustStartSoundParams( StartSoundParams_t& params )
  {
  #ifdef TF_CLIENT_DLL
  	CBaseEntity *pEntity = ClientEntityList().GetEnt( params.soundsource );
  
  	// A player speaking
  	if ( params.entchannel == CHAN_VOICE && GameRules() && pEntity && pEntity->IsPlayer() )
  	{
  		// Use high-pitched voices for other players if the local player has an item that allows them to hear it (Pyro Goggles)
  		if ( !GameRules()->IsLocalPlayer( params.soundsource ) && IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_PYRO ) )
  		{
  			params.pitch *= 1.3f;
  		}
  		// Halloween voice futzery?
  		else
  		{
  			float flHeadScale = 1.f;
  			CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pEntity, flHeadScale, head_scale );
  
  			int iHalloweenVoiceSpell = 0;
  			CALL_ATTRIB_HOOK_INT_ON_OTHER( pEntity, iHalloweenVoiceSpell, halloween_voice_modulation );
  			if ( iHalloweenVoiceSpell > 0 )
  			{
  				params.pitch *= 0.8f;
  			}
  			else if( flHeadScale != 1.f )
  			{
  				// Big head, deep voice
  				if( flHeadScale > 1.f )
  				{
  					params.pitch *= 0.8f;
  				}
  				else	// Small head, high voice
  				{
  					params.pitch *= 1.3f;
  				}
  			}
  		}
  	}
  #endif
  }
  
  const char* CHLClient::TranslateEffectForVisionFilter( const char *pchEffectType, const char *pchEffectName )
  {
  	if ( !GameRules() )
  		return pchEffectName;
  
  	return GameRules()->TranslateEffectForVisionFilter( pchEffectType, pchEffectName );
  }
  
  bool CHLClient::DisconnectAttempt( void )
  {
  	bool bRet = false;
  
  #if defined( TF_CLIENT_DLL )
  	bRet = HandleDisconnectAttempt();
  #endif
  
  	return bRet;
  }
  
  bool CHLClient::IsConnectedUserInfoChangeAllowed( IConVar *pCvar )
  {
  	return GameRules() ? GameRules()->IsConnectedUserInfoChangeAllowed( NULL ) : true;
  }
  
  #ifndef NO_STEAM
  
  CSteamID GetSteamIDForPlayerIndex( int iPlayerIndex )
  {
  	player_info_t pi;
  	if ( steamapicontext && steamapicontext->SteamUtils() )
  	{
  		if ( engine->GetPlayerInfo( iPlayerIndex, &pi ) )
  		{
  			if ( pi.friendsID )
  			{
  				return CSteamID( pi.friendsID, 1, steamapicontext->SteamUtils()->GetConnectedUniverse(), k_EAccountTypeIndividual );
  			}
  		}
  	}
  	return CSteamID();
  }
  
  #endif
  