aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/cdll_client_int.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/client/cdll_client_int.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/client/cdll_client_int.cpp')
-rw-r--r--mp/src/game/client/cdll_client_int.cpp2635
1 files changed, 2635 insertions, 0 deletions
diff --git a/mp/src/game/client/cdll_client_int.cpp b/mp/src/game/client/cdll_client_int.cpp
new file mode 100644
index 00000000..0e96b11c
--- /dev/null
+++ b/mp/src/game/client/cdll_client_int.cpp
@@ -0,0 +1,2635 @@
+//========= 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 "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"
+#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 );
+ }
+
+ 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() );
+ #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 )
+ {
+ hudCloseCaption->ProcessSentenceCaptionStream( tokenstream );
+ }
+}
+
+
+void CHLClient::EmitCloseCaption( char const *captionname, float duration )
+{
+ extern ConVar closecaption;
+
+ if ( !closecaption.GetBool() )
+ return;
+
+ CHudCloseCaption *hudCloseCaption = GET_HUDELEMENT( CHudCloseCaption );
+ if ( hudCloseCaption )
+ {
+ hudCloseCaption->ProcessCaption( captionname, duration );
+ }
+}
+
+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