|
|
//========= 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"
#include "tf_gamerules.h"
#endif
#include "clientsteamcontext.h"
#include "renamed_recvtable_compat.h"
#include "mouthinfo.h"
#include "sourcevr/isourcevirtualreality.h"
#include "client_virtualreality.h"
#include "mumble.h"
#include "vgui_controls/BuildGroup.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;
//=============================================================================
// 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");
#ifdef HL1MP_CLIENT_DLL
static ConVar s_cl_load_hl1_content("cl_load_hl1_content", "0", FCVAR_ARCHIVE, "Mount the content from Half-Life: Source if possible"); #endif
// 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] = 0; 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] = 1; printInfo.color[1] = 1; printInfo.color[2] = 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 sourcevr.dll wasn't found
if ( CommandLine()->CheckParm( "-vr" ) ) 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 (!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
g_ClientVirtualReality.StartupComplete();
#ifdef HL1MP_CLIENT_DLL
if ( s_cl_load_hl1_content.GetBool() && steamapicontext && steamapicontext->SteamApps() ) { char szPath[ MAX_PATH*2 ]; int ccFolder= steamapicontext->SteamApps()->GetAppInstallDir( 280, szPath, sizeof(szPath) ); if ( ccFolder > 0 ) { V_AppendSlash( szPath, sizeof(szPath) ); V_strncat( szPath, "hl1", sizeof( szPath ) );
g_pFullFileSystem->AddSearchPath( szPath, "HL1" ); g_pFullFileSystem->AddSearchPath( szPath, "GAME" ); } } #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(); vgui::BuildGroup::ClearResFileCache();
#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();
#ifndef TF_CLIENT_DLL
// don't want to do this for TF2 because we have particle systems in our
// character loadout screen that can be viewed when we're not connected to a server
g_pParticleSystemMgr->UncacheAllParticleSystems(); #endif
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 *pCrosshair = GET_HUDELEMENT( CHudCrosshair ); if ( pCrosshair ) { pCrosshair->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(); UpdateLocalPlayerVisionFlags();
// 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 ) { if ( GetClientModeNormal() ) { return GetClientModeNormal()->OnDemoRecordStart( pDemoBaseName ); } }
void CHLClient::OnDemoRecordStop() { if ( GetClientModeNormal() ) { return GetClientModeNormal()->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 flVoicePitchScale = 1.f; CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pEntity, flVoicePitchScale, voice_pitch_scale );
int iHalloweenVoiceSpell = 0; if ( TF_IsHolidayActive( kHoliday_HalloweenOrFullMoon ) ) { CALL_ATTRIB_HOOK_INT_ON_OTHER( pEntity, iHalloweenVoiceSpell, halloween_voice_modulation ); }
if ( iHalloweenVoiceSpell > 0 ) { params.pitch *= 0.8f; } else if( flVoicePitchScale != 1.f ) { params.pitch *= flVoicePitchScale; } } } #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, GetUniverse(), k_EAccountTypeIndividual ); } } } return CSteamID(); }
#endif
|