You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2222 lines
62 KiB
2222 lines
62 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// 4-23-98 |
|
// JOHN: implementation of interface between client-side DLL and game engine. |
|
// The cdll shouldn't have to know anything about networking or file formats. |
|
// This file is Win32-dependant |
|
// |
|
//=============================================================================// |
|
|
|
#include "client_pch.h" |
|
#include "getintersectingsurfaces_struct.h" |
|
#include "gl_model_private.h" |
|
#include "surfinfo.h" |
|
#include "vstdlib/random.h" |
|
#include "cdll_int.h" |
|
#include "cmodel_engine.h" |
|
#include "tmessage.h" |
|
#include "console.h" |
|
#include "snd_audio_source.h" |
|
#include <vgui_controls/Controls.h> |
|
#include <vgui/IInput.h> |
|
#include "iengine.h" |
|
#include "keys.h" |
|
#include "con_nprint.h" |
|
#include "tier0/vprof.h" |
|
#include "sound.h" |
|
#include "gl_rmain.h" |
|
#include "proto_version.h" |
|
#include "client_class.h" |
|
#include "gl_rsurf.h" |
|
#include "server.h" |
|
#include "r_local.h" |
|
#include "lightcache.h" |
|
#include "gl_matsysiface.h" |
|
#include "materialsystem/imaterialsystemhardwareconfig.h" |
|
#include "materialsystem/materialsystem_config.h" |
|
#include "materialsystem/imaterial.h" |
|
#include "materialsystem/imaterialvar.h" |
|
#include "materialsystem/itexture.h" |
|
#include "istudiorender.h" |
|
#include "l_studio.h" |
|
#include "voice.h" |
|
#include "enginestats.h" |
|
#include "testscriptmgr.h" |
|
#include "r_areaportal.h" |
|
#include "host.h" |
|
#include "host_cmd.h" |
|
#include "vox.h" |
|
#include "iprediction.h" |
|
#include "icliententitylist.h" |
|
#include "eiface.h" |
|
#include "ivguicenterprint.h" |
|
#include "engine/IClientLeafSystem.h" |
|
#include "dt_recv_eng.h" |
|
#include <vgui/IVGui.h> |
|
#include "sys_dll.h" |
|
#include "vphysics_interface.h" |
|
#include "materialsystem/imesh.h" |
|
#include "IOcclusionSystem.h" |
|
#include "filesystem_engine.h" |
|
#include "tier0/icommandline.h" |
|
#include "client_textmessage.h" |
|
#include "host_saverestore.h" |
|
#include "cl_main.h" |
|
#include "demo.h" |
|
#include "appframework/ilaunchermgr.h" |
|
#include "vgui_baseui_interface.h" |
|
#include "LocalNetworkBackdoor.h" |
|
#include "lightcache.h" |
|
#include "vgui/ISystem.h" |
|
#include "ivideomode.h" |
|
#include "icolorcorrectiontools.h" |
|
#include "toolframework/itoolframework.h" |
|
#include "engine/view_sharedv1.h" |
|
#include "view.h" |
|
#include "game/client/iclientrendertargets.h" |
|
#include "tier2/tier2.h" |
|
#include "matchmaking.h" |
|
#include "inputsystem/iinputsystem.h" |
|
#include "iachievementmgr.h" |
|
#include "profile.h" |
|
#include "cl_steamauth.h" |
|
#include "download.h" |
|
#include "replay/iclientreplay.h" |
|
#include "demofile.h" |
|
#include "igame.h" |
|
#include "iclientvirtualreality.h" |
|
#include "sourcevr/isourcevirtualreality.h" |
|
#include "cl_check_process.h" |
|
#include "enginethreads.h" |
|
|
|
#if defined( REPLAY_ENABLED ) |
|
#include "replay_internal.h" |
|
#include "replay/replaylib.h" |
|
#endif |
|
|
|
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
//----------------------------------------------------------------------------- |
|
// forward declarations |
|
//----------------------------------------------------------------------------- |
|
IMaterial* BrushModel_GetLightingAndMaterial( const Vector &start, |
|
const Vector &end, Vector &diffuseLightColor, Vector &baseColor ); |
|
const char *Key_NameForBinding( const char *pBinding ); |
|
void CL_GetBackgroundLevelName( char *pszBackgroundName, int bufSize, bool bMapName ); |
|
CreateInterfaceFn g_ClientFactory = NULL; |
|
extern CGlobalVars g_ServerGlobalVariables; |
|
|
|
//----------------------------------------------------------------------------- |
|
// globals |
|
//----------------------------------------------------------------------------- |
|
CSysModule *g_ClientDLLModule = NULL; // also used by materialproxyfactory.cpp |
|
bool g_bClientGameDLLGreaterThanV13; |
|
|
|
void AddIntersectingLeafSurfaces( mleaf_t *pLeaf, GetIntersectingSurfaces_Struct *pStruct ) |
|
{ |
|
SurfaceHandle_t *pHandle = &host_state.worldbrush->marksurfaces[pLeaf->firstmarksurface]; |
|
for ( int iSurf=0; iSurf < pLeaf->nummarksurfaces; iSurf++ ) |
|
{ |
|
SurfaceHandle_t surfID = pHandle[iSurf]; |
|
ASSERT_SURF_VALID( surfID ); |
|
|
|
if ( MSurf_Flags(surfID) & SURFDRAW_SKY ) |
|
continue; |
|
|
|
// Make sure we haven't already processed this one. |
|
bool foundSurf = false; |
|
for(int iTest=0; iTest < pStruct->m_nSetInfos; iTest++) |
|
{ |
|
if(pStruct->m_pInfos[iTest].m_pEngineData == (void *)surfID) |
|
{ |
|
foundSurf = true; |
|
break; |
|
} |
|
} |
|
if ( foundSurf ) |
|
continue; |
|
|
|
// Make sure there's output room. |
|
if(pStruct->m_nSetInfos >= pStruct->m_nMaxInfos) |
|
return; |
|
SurfInfo *pOut = &pStruct->m_pInfos[pStruct->m_nSetInfos]; |
|
pOut->m_nVerts = 0; |
|
pOut->m_pEngineData = (void *)surfID; |
|
|
|
// Build vertex list and bounding box. |
|
Vector vMin( 1000000.0f, 1000000.0f, 1000000.0f); |
|
Vector vMax(-1000000.0f, -1000000.0f, -1000000.0f); |
|
for(int iVert=0; iVert < MSurf_VertCount( surfID ); iVert++) |
|
{ |
|
int vertIndex = pStruct->m_pModel->brush.pShared->vertindices[MSurf_FirstVertIndex( surfID ) + iVert]; |
|
|
|
pOut->m_Verts[pOut->m_nVerts] = pStruct->m_pModel->brush.pShared->vertexes[vertIndex].position; |
|
vMin = vMin.Min(pOut->m_Verts[pOut->m_nVerts]); |
|
vMax = vMax.Max(pOut->m_Verts[pOut->m_nVerts]); |
|
|
|
++pOut->m_nVerts; |
|
if(pOut->m_nVerts >= MAX_SURFINFO_VERTS) |
|
break; |
|
} |
|
|
|
// See if the sphere intersects the box. |
|
int iDim=0; |
|
for(; iDim < 3; iDim++) |
|
{ |
|
if(((*pStruct->m_pCenter)[iDim]+pStruct->m_Radius) < vMin[iDim] || |
|
((*pStruct->m_pCenter)[iDim]-pStruct->m_Radius) > vMax[iDim]) |
|
{ |
|
break; |
|
} |
|
} |
|
|
|
if(iDim == 3) |
|
{ |
|
// (Couldn't reject the sphere in the loop above). |
|
pOut->m_Plane = MSurf_GetForwardFacingPlane( surfID ); |
|
++pStruct->m_nSetInfos; |
|
} |
|
} |
|
} |
|
|
|
void GetIntersectingSurfaces_R( |
|
GetIntersectingSurfaces_Struct *pStruct, |
|
mnode_t *pNode |
|
) |
|
{ |
|
if(pStruct->m_nSetInfos >= pStruct->m_nMaxInfos) |
|
return; |
|
|
|
// Ok, this is a leaf. Check its surfaces. |
|
if(pNode->contents >= 0) |
|
{ |
|
mleaf_t *pLeaf = (mleaf_t*)pNode; |
|
|
|
if(pStruct->m_bOnlyVisible && pStruct->m_pCenterPVS) |
|
{ |
|
if(pLeaf->cluster < 0) |
|
return; |
|
|
|
if(!(pStruct->m_pCenterPVS[pLeaf->cluster>>3] & (1 << (pLeaf->cluster&7)))) |
|
return; |
|
} |
|
|
|
// First, add tris from displacements. |
|
for ( int i = 0; i < pLeaf->dispCount; i++ ) |
|
{ |
|
IDispInfo *pDispInfo = MLeaf_Disaplcement( pLeaf, i ); |
|
pDispInfo->GetIntersectingSurfaces( pStruct ); |
|
} |
|
|
|
// Next, add brush tris. |
|
AddIntersectingLeafSurfaces( pLeaf, pStruct ); |
|
return; |
|
} |
|
|
|
// Recurse. |
|
float dot; |
|
cplane_t *plane = pNode->plane; |
|
if ( plane->type < 3 ) |
|
{ |
|
dot = (*pStruct->m_pCenter)[plane->type] - plane->dist; |
|
} |
|
else |
|
{ |
|
dot = pStruct->m_pCenter->Dot(plane->normal) - plane->dist; |
|
} |
|
|
|
// Recurse into child nodes. |
|
if(dot > -pStruct->m_Radius) |
|
GetIntersectingSurfaces_R(pStruct, pNode->children[SIDE_FRONT]); |
|
|
|
if(dot < pStruct->m_Radius) |
|
GetIntersectingSurfaces_R(pStruct, pNode->children[SIDE_BACK]); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// slow routine to draw a physics model |
|
// NOTE: very slow code!!! just for debugging! |
|
//----------------------------------------------------------------------------- |
|
void DebugDrawPhysCollide( const CPhysCollide *pCollide, IMaterial *pMaterial, matrix3x4_t& transform, const color32 &color, bool drawAxes ) |
|
{ |
|
if ( !pMaterial ) |
|
{ |
|
pMaterial = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER); |
|
} |
|
|
|
CMatRenderContextPtr pRenderContext( materials ); |
|
|
|
Vector *outVerts; |
|
int vertCount = physcollision->CreateDebugMesh( pCollide, &outVerts ); |
|
if ( vertCount ) |
|
{ |
|
IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); |
|
|
|
CMeshBuilder meshBuilder; |
|
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, vertCount/3 ); |
|
|
|
for ( int j = 0; j < vertCount; j++ ) |
|
{ |
|
Vector out; |
|
VectorTransform( outVerts[j].Base(), transform, out.Base() ); |
|
meshBuilder.Position3fv( out.Base() ); |
|
meshBuilder.Color4ub( color.r, color.g, color.b, color.a ); |
|
meshBuilder.TexCoord2f( 0, 0, 0 ); |
|
meshBuilder.AdvanceVertex(); |
|
} |
|
meshBuilder.End(); |
|
pMesh->Draw(); |
|
} |
|
physcollision->DestroyDebugMesh( vertCount, outVerts ); |
|
|
|
// draw the axes |
|
if ( drawAxes ) |
|
{ |
|
Vector xaxis(10,0,0), yaxis(0,10,0), zaxis(0,0,10); |
|
Vector center; |
|
Vector out; |
|
|
|
MatrixGetColumn( transform, 3, center ); |
|
IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); |
|
CMeshBuilder meshBuilder; |
|
meshBuilder.Begin( pMesh, MATERIAL_LINES, 3 ); |
|
|
|
// X |
|
meshBuilder.Position3fv( center.Base() ); |
|
meshBuilder.Color4ub( 255, 0, 0, 255 ); |
|
meshBuilder.TexCoord2f( 0, 0, 0 ); |
|
meshBuilder.AdvanceVertex(); |
|
VectorTransform( xaxis.Base(), transform, out.Base() ); |
|
meshBuilder.Position3fv( out.Base() ); |
|
meshBuilder.Color4ub( 255, 0, 0, 255 ); |
|
meshBuilder.TexCoord2f( 0, 0, 0 ); |
|
meshBuilder.AdvanceVertex(); |
|
|
|
// Y |
|
meshBuilder.Position3fv( center.Base() ); |
|
meshBuilder.Color4ub( 0, 255, 0, 255 ); |
|
meshBuilder.TexCoord2f( 0, 0, 0 ); |
|
meshBuilder.AdvanceVertex(); |
|
VectorTransform( yaxis.Base(), transform, out.Base() ); |
|
meshBuilder.Position3fv( out.Base() ); |
|
meshBuilder.Color4ub( 0, 255, 0, 255 ); |
|
meshBuilder.TexCoord2f( 0, 0, 0 ); |
|
meshBuilder.AdvanceVertex(); |
|
|
|
// Z |
|
meshBuilder.Position3fv( center.Base() ); |
|
meshBuilder.Color4ub( 0, 0, 255, 255 ); |
|
meshBuilder.TexCoord2f( 0, 0, 0 ); |
|
meshBuilder.AdvanceVertex(); |
|
VectorTransform( zaxis.Base(), transform, out.Base() ); |
|
meshBuilder.Position3fv( out.Base() ); |
|
meshBuilder.Color4ub( 0, 0, 255, 255 ); |
|
meshBuilder.TexCoord2f( 0, 0, 0 ); |
|
meshBuilder.AdvanceVertex(); |
|
meshBuilder.End(); |
|
pMesh->Draw(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
// implementation of IVEngineHud |
|
// |
|
//----------------------------------------------------------------------------- |
|
|
|
// UNDONE: Move this to hud export code, subsume previous functions |
|
class CEngineClient : public IVEngineClient |
|
{ |
|
public: |
|
CEngineClient(); |
|
|
|
int GetIntersectingSurfaces( |
|
const model_t *model, |
|
const Vector &vCenter, |
|
const float radius, |
|
const bool bOnlyVisible, |
|
SurfInfo *pInfos, |
|
const int nMaxInfos); |
|
|
|
Vector GetLightForPoint(const Vector &pos, bool bClamp); |
|
Vector GetLightForPointFast(const Vector &pos, bool bClamp); |
|
const char *ParseFile( const char *data, char *token, int maxlen ); |
|
virtual bool CopyLocalFile( const char *source, const char *destination ); |
|
void GetScreenSize( int& w, int &h ); |
|
void ServerCmd( const char *szCmdString, bool bReliable ); |
|
void ClientCmd( const char *szCmdString ); |
|
void ClientCmd_Unrestricted( const char *szCmdString ); |
|
void SetRestrictServerCommands( bool bRestrict ); |
|
void SetRestrictClientCommands( bool bRestrict ); |
|
bool GetPlayerInfo( int ent_num, player_info_t *pinfo ); |
|
client_textmessage_t *TextMessageGet( const char *pName ); |
|
bool Con_IsVisible( void ); |
|
int GetLocalPlayer( void ); |
|
float GetLastTimeStamp( void ); |
|
const model_t *LoadModel( const char *pName, bool bProp ); |
|
void UnloadModel( const model_t *model, bool bProp ); |
|
CSentence *GetSentence( CAudioSource *pAudioSource ); |
|
float GetSentenceLength( CAudioSource *pAudioSource ); |
|
bool IsStreaming( CAudioSource *pAudioSource ) const; |
|
void AddPhonemeFile( const char *pszPhonemeFile ); |
|
|
|
// FIXME, move entirely to client .dll |
|
void GetViewAngles( QAngle& va ); |
|
void SetViewAngles( QAngle& va ); |
|
int GetMaxClients( void ); |
|
void Key_Event( ButtonCode_t key, int down ); |
|
const char *Key_LookupBinding( const char *pBinding ); |
|
const char *Key_LookupBindingExact( const char *pBinding ); |
|
const char *Key_BindingForKey( ButtonCode_t code ); |
|
void StartKeyTrapMode( void ); |
|
bool CheckDoneKeyTrapping( ButtonCode_t &key ); |
|
bool IsInGame( void ); |
|
bool IsConnected( void ); |
|
bool IsDrawingLoadingImage( void ); |
|
void Con_NPrintf( int pos, const char *fmt, ... ); |
|
void Con_NXPrintf( const struct con_nprint_s *info, const char *fmt, ... ); |
|
IMaterial *TraceLineMaterialAndLighting( const Vector &start, const Vector &end, |
|
Vector &diffuseLightColor, Vector &baseColor ); |
|
int IsBoxVisible( const Vector& mins, const Vector& maxs ); |
|
int IsBoxInViewCluster( const Vector& mins, const Vector& maxs ); |
|
|
|
float Time(); |
|
void Sound_ExtraUpdate( void ); |
|
|
|
bool CullBox ( const Vector& mins, const Vector& maxs ); |
|
const char *GetGameDirectory( void ); |
|
const VMatrix& WorldToScreenMatrix(); |
|
const VMatrix& WorldToViewMatrix(); |
|
|
|
// Loads a game lump off disk |
|
int GameLumpVersion( int lumpId ) const; |
|
int GameLumpSize( int lumpId ) const; |
|
bool LoadGameLump( int lumpId, void* pBuffer, int size ); |
|
|
|
// Returns the number of leaves in the level |
|
int LevelLeafCount() const; |
|
virtual ISpatialQuery* GetBSPTreeQuery(); |
|
|
|
// Convert texlight to gamma... |
|
virtual void LinearToGamma( float* linear, float* gamma ); |
|
|
|
// Get the lightstyle value |
|
virtual float LightStyleValue( int style ); |
|
virtual void DrawPortals(); |
|
|
|
// Computes light due to dynamic lighting at a point |
|
// If the normal isn't specified, then it'll return the maximum lighting |
|
virtual void ComputeDynamicLighting( Vector const& pt, Vector const* pNormal, Vector& color ); |
|
|
|
// Computes light due to dynamic lighting at a point |
|
// If the normal isn't specified, then it'll return the maximum lighting |
|
// If pBoxColors is specified (it's an array of 6), then it'll copy the light contribution at each box side. |
|
virtual void ComputeLighting( const Vector& pt, const Vector* pNormal, bool bClamp, Vector& color, Vector *pBoxColors ); |
|
|
|
// Returns the color of the ambient light |
|
virtual void GetAmbientLightColor( Vector& color ); |
|
|
|
// Returns the dx support level |
|
virtual int GetDXSupportLevel(); |
|
|
|
virtual bool SupportsHDR(); |
|
virtual void Mat_Stub( IMaterialSystem *pMatSys ); |
|
|
|
// menu display |
|
virtual void GetChapterName( char *pchBuff, int iMaxLength ); |
|
virtual char const *GetLevelName( void ); |
|
virtual int GetLevelVersion( void ); |
|
virtual bool IsLevelMainMenuBackground( void ); |
|
virtual void GetMainMenuBackgroundName( char *dest, int destlen ); |
|
|
|
// Occlusion system control |
|
virtual void SetOcclusionParameters( const OcclusionParams_t ¶ms ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Takes a trackerID and returns which player slot that user is in |
|
// returns 0 if no player found with that ID |
|
//----------------------------------------------------------------------------- |
|
virtual int GetPlayerForUserID(int userID); |
|
#if !defined( NO_VOICE ) |
|
virtual struct IVoiceTweak_s *GetVoiceTweakAPI( void ); |
|
#endif |
|
virtual void EngineStats_BeginFrame( void ); |
|
virtual void EngineStats_EndFrame( void ); |
|
virtual void FireEvents(); |
|
virtual void CheckPoint( const char *pName ); |
|
virtual int GetLeavesArea( int *pLeaves, int nLeaves ); |
|
virtual bool DoesBoxTouchAreaFrustum( const Vector &mins, const Vector &maxs, int iArea ); |
|
|
|
// Sets the hearing origin |
|
virtual void SetAudioState( const AudioState_t &audioState ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
// Sentence API |
|
// |
|
//----------------------------------------------------------------------------- |
|
|
|
virtual int SentenceGroupPick( int groupIndex, char *name, int nameLen ); |
|
virtual int SentenceGroupPickSequential( int groupIndex, char *name, int nameLen, int sentenceIndex, int reset ); |
|
virtual int SentenceIndexFromName( const char *pSentenceName ); |
|
virtual const char *SentenceNameFromIndex( int sentenceIndex ); |
|
virtual int SentenceGroupIndexFromName( const char *pGroupName ); |
|
virtual const char *SentenceGroupNameFromIndex( int groupIndex ); |
|
virtual float SentenceLength( int sentenceIndex ); |
|
virtual void DebugDrawPhysCollide( const CPhysCollide *pCollide, IMaterial *pMaterial, matrix3x4_t& transform, const color32 &color ); |
|
|
|
// Activates/deactivates an occluder... |
|
virtual void ActivateOccluder( int nOccluderIndex, bool bActive ); |
|
virtual bool IsOccluded( const Vector &vecAbsMins, const Vector &vecAbsMaxs ); |
|
virtual void *SaveAllocMemory( size_t num, size_t size ); |
|
virtual void SaveFreeMemory( void *pSaveMem ); |
|
virtual INetChannelInfo *GetNetChannelInfo( void ); |
|
virtual bool IsPlayingDemo( void ); |
|
virtual bool IsRecordingDemo( void ); |
|
virtual bool IsPlayingTimeDemo( void ); |
|
virtual int GetDemoRecordingTick( void ); |
|
virtual int GetDemoPlaybackTick( void ); |
|
virtual int GetDemoPlaybackStartTick( void ); |
|
virtual float GetDemoPlaybackTimeScale( void ); |
|
virtual int GetDemoPlaybackTotalTicks( void ); |
|
virtual bool IsPaused( void ); |
|
virtual bool IsTakingScreenshot( void ); |
|
virtual bool IsHLTV( void ); |
|
virtual void GetVideoModes( int &nCount, vmode_s *&pModes ); |
|
virtual void GetUILanguage( char *dest, int destlen ); |
|
|
|
// Can skybox be seen from a particular point? |
|
virtual SkyboxVisibility_t IsSkyboxVisibleFromPoint( const Vector &vecPoint ); |
|
|
|
virtual const char* GetMapEntitiesString(); |
|
virtual bool IsInEditMode( void ); |
|
virtual bool IsInCommentaryMode( void ); |
|
virtual float GetScreenAspectRatio(); |
|
|
|
virtual unsigned int GetEngineBuildNumber() { return PROTOCOL_VERSION; } |
|
virtual const char * GetProductVersionString() { return GetSteamInfIDVersionInfo().szVersionString; } |
|
virtual void GrabPreColorCorrectedFrame( int x, int y, int width, int height ); |
|
virtual bool IsHammerRunning( ) const; |
|
|
|
// Stuffs the cmd into the buffer & executes it immediately (vs ClientCmd() which executes it next frame) |
|
virtual void ExecuteClientCmd( const char *szCmdString ); |
|
|
|
virtual bool MapHasHDRLighting( void) ; |
|
virtual int GetAppID(); |
|
|
|
virtual void SetOverlayBindProxy( int iOverlayID, void *pBindProxy ); |
|
|
|
virtual bool CopyFrameBufferToMaterial( const char *pMaterialName ); |
|
|
|
// Matchmaking |
|
void ChangeTeam( const char *pTeamName ); |
|
virtual void ReadConfiguration( const bool readDefault = false ); |
|
|
|
virtual void SetAchievementMgr( IAchievementMgr *pAchievementMgr ); |
|
virtual IAchievementMgr *GetAchievementMgr(); |
|
|
|
virtual bool MapLoadFailed( void ); |
|
virtual void SetMapLoadFailed( bool bState ); |
|
|
|
virtual bool IsLowViolence(); |
|
virtual const char *GetMostRecentSaveGame( void ); |
|
virtual void SetMostRecentSaveGame( const char *lpszFilename ); |
|
|
|
virtual void StartXboxExitingProcess(); |
|
virtual bool IsSaveInProgress(); |
|
|
|
virtual uint OnStorageDeviceAttached( void ); |
|
virtual void OnStorageDeviceDetached( void ); |
|
|
|
virtual void ResetDemoInterpolation( void ); |
|
|
|
virtual bool REMOVED_SteamRefreshLogin( const char *password, bool isSecure ) { return false; } |
|
virtual bool REMOVED_SteamProcessCall( bool & finished ) { return false; } |
|
|
|
virtual ISPSharedMemory *GetSinglePlayerSharedMemorySpace( const char *handle, int ent_num = MAX_EDICTS ); |
|
|
|
virtual void SetGamestatsData( CGamestatsData *pGamestatsData ); |
|
virtual CGamestatsData *GetGamestatsData(); |
|
|
|
#if defined( USE_SDL ) |
|
virtual void GetMouseDelta( int &x, int &y, bool bIgnoreNextMouseDelta ); |
|
#endif |
|
|
|
virtual void ServerCmdKeyValues( KeyValues *pKeyValues ); |
|
|
|
virtual bool IsSkippingPlayback( void ); |
|
virtual bool IsLoadingDemo( void ); |
|
|
|
virtual bool IsPlayingDemoALocallyRecordedDemo(); |
|
|
|
virtual uint GetProtocolVersion( void ); |
|
|
|
virtual bool IsWindowedMode( void ); |
|
|
|
virtual void FlashWindow(); |
|
virtual int GetClientVersion() const; // engines build |
|
virtual bool IsActiveApp(); |
|
virtual void DisconnectInternal(); |
|
|
|
virtual int GetInstancesRunningCount( ); |
|
|
|
virtual float GetPausedExpireTime( void ) OVERRIDE; |
|
|
|
virtual bool StartDemoRecording( const char *pszFilename, const char *pszFolder = NULL ); |
|
virtual void StopDemoRecording( void ); |
|
virtual void TakeScreenshot( const char *pszFilename, const char *pszFolder = NULL ); |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Singleton |
|
//----------------------------------------------------------------------------- |
|
static CEngineClient s_VEngineClient; |
|
IVEngineClient *engineClient = &s_VEngineClient; |
|
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineClient, IVEngineClient, VENGINE_CLIENT_INTERFACE_VERSION, s_VEngineClient ); |
|
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineClient, IVEngineClient013, VENGINE_CLIENT_INTERFACE_VERSION_13, s_VEngineClient ); |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Constructor |
|
//----------------------------------------------------------------------------- |
|
CEngineClient::CEngineClient() |
|
{ |
|
} |
|
|
|
int CEngineClient::GetIntersectingSurfaces( |
|
const model_t *model, |
|
const Vector &vCenter, |
|
const float radius, |
|
const bool bOnlyVisible, |
|
SurfInfo *pInfos, |
|
const int nMaxInfos) |
|
{ |
|
if ( !model ) |
|
return 0; |
|
|
|
byte pvs[MAX_MAP_LEAFS/8]; |
|
GetIntersectingSurfaces_Struct theStruct; |
|
theStruct.m_pModel = ( model_t * )model; |
|
theStruct.m_pCenter = &vCenter; |
|
theStruct.m_pCenterPVS = CM_Vis( pvs, sizeof(pvs), CM_LeafCluster( CM_PointLeafnum( vCenter ) ), DVIS_PVS ); |
|
theStruct.m_Radius = radius; |
|
theStruct.m_bOnlyVisible = bOnlyVisible; |
|
theStruct.m_pInfos = pInfos; |
|
theStruct.m_nMaxInfos = nMaxInfos; |
|
theStruct.m_nSetInfos = 0; |
|
|
|
// Go down the BSP. |
|
GetIntersectingSurfaces_R( |
|
&theStruct, |
|
&model->brush.pShared->nodes[ model->brush.firstnode ] ); |
|
|
|
return theStruct.m_nSetInfos; |
|
} |
|
|
|
Vector CEngineClient::GetLightForPoint(const Vector &pos, bool bClamp) |
|
{ |
|
Vector vRet; |
|
ComputeLighting( pos, NULL, bClamp, vRet, NULL ); |
|
return vRet; |
|
} |
|
|
|
Vector CEngineClient::GetLightForPointFast(const Vector &pos, bool bClamp) |
|
{ |
|
Vector vRet; |
|
int leafIndex = CM_PointLeafnum(pos); |
|
vRet.Init(); |
|
Vector cube[6]; |
|
Mod_LeafAmbientColorAtPos( cube, pos, leafIndex ); |
|
for ( int i = 0; i < 6; i++ ) |
|
{ |
|
vRet.x = fpmax(vRet.x, cube[i].x ); |
|
vRet.y = fpmax(vRet.y, cube[i].y ); |
|
vRet.z = fpmax(vRet.z, cube[i].z ); |
|
} |
|
if ( bClamp ) |
|
{ |
|
if ( vRet.x > 1.0f ) |
|
vRet.x = 1.0f; |
|
if ( vRet.y > 1.0f ) |
|
vRet.y = 1.0f; |
|
if ( vRet.z > 1.0f ) |
|
vRet.z = 1.0f; |
|
} |
|
return vRet; |
|
} |
|
|
|
const char *CEngineClient::ParseFile( const char *data, char *token, int maxlen ) |
|
{ |
|
return ::COM_ParseFile( data, token, maxlen ); |
|
} |
|
|
|
bool CEngineClient::CopyLocalFile( const char *source, const char *destination ) |
|
{ |
|
return ::COM_CopyFile( source, destination ); |
|
} |
|
|
|
void CEngineClient::GetScreenSize( int& w, int &h ) |
|
{ |
|
CMatRenderContextPtr pRenderContext( materials ); |
|
pRenderContext->GetWindowSize( w, h ); |
|
} |
|
|
|
void CEngineClient::ServerCmd( const char *szCmdString, bool bReliable ) |
|
{ |
|
// info handling |
|
char buf[255]; |
|
Q_snprintf( buf, sizeof( buf ), "cmd %s", szCmdString ); |
|
|
|
CCommand args; |
|
args.Tokenize( buf ); |
|
Cmd_ForwardToServer( args, bReliable ); |
|
} |
|
|
|
void CEngineClient::ClientCmd( const char *szCmdString ) |
|
{ |
|
// Check that we can add the two execution markers |
|
if ( cl.m_bRestrictClientCommands && !Cbuf_HasRoomForExecutionMarkers( 2 ) ) |
|
{ |
|
AssertMsg( false, "CEngineClient::ClientCmd called but there is no room for the execution markers. Ignoring command." ); |
|
return; |
|
} |
|
|
|
// Only let them run commands marked with FCVAR_CLIENTCMD_CAN_EXECUTE. |
|
if ( cl.m_bRestrictClientCommands ) |
|
Cbuf_AddTextWithMarkers( eCmdExecutionMarker_Enable_FCVAR_CLIENTCMD_CAN_EXECUTE, szCmdString, eCmdExecutionMarker_Disable_FCVAR_CLIENTCMD_CAN_EXECUTE ); |
|
else |
|
Cbuf_AddText( szCmdString ); |
|
} |
|
|
|
void CEngineClient::ClientCmd_Unrestricted( const char *szCmdString ) |
|
{ |
|
Cbuf_AddText( szCmdString ); |
|
} |
|
|
|
void CEngineClient::SetRestrictServerCommands( bool bRestrict ) |
|
{ |
|
cl.m_bRestrictServerCommands = bRestrict; |
|
} |
|
|
|
void CEngineClient::SetRestrictClientCommands( bool bRestrict ) |
|
{ |
|
cl.m_bRestrictClientCommands = bRestrict; |
|
} |
|
|
|
void CEngineClient::ExecuteClientCmd( const char *szCmdString ) |
|
{ |
|
Cbuf_AddText( szCmdString ); |
|
Cbuf_Execute(); |
|
} |
|
|
|
bool CEngineClient::GetPlayerInfo( int ent_num, player_info_t *pinfo ) |
|
{ |
|
ent_num--; // player list if offset by 1 from ents |
|
|
|
if ( ent_num >= cl.m_nMaxClients || ent_num < 0 ) |
|
{ |
|
Q_memset( pinfo, 0, sizeof( player_info_t ) ); |
|
return false; |
|
} |
|
|
|
Assert( cl.m_pUserInfoTable ); |
|
if ( !cl.m_pUserInfoTable ) |
|
{ |
|
Q_memset( pinfo, 0, sizeof( player_info_t ) ); |
|
return false; |
|
} |
|
|
|
Assert( ent_num < cl.m_pUserInfoTable->GetNumStrings() ); |
|
if ( ent_num >= cl.m_pUserInfoTable->GetNumStrings() ) |
|
{ |
|
Q_memset( pinfo, 0, sizeof( player_info_t ) ); |
|
return false; |
|
} |
|
|
|
int cubPlayerInfo; |
|
player_info_t *pi = (player_info_t*) cl.m_pUserInfoTable->GetStringUserData( ent_num, &cubPlayerInfo ); |
|
|
|
if ( !pi || cubPlayerInfo < sizeof( player_info_t ) ) |
|
{ |
|
Q_memset( pinfo, 0, sizeof( player_info_t ) ); |
|
return false; |
|
} |
|
|
|
Q_memcpy( pinfo, pi, sizeof( player_info_t ) ); |
|
|
|
// Fixup from network order (little endian) |
|
CByteswap byteswap; |
|
byteswap.SetTargetBigEndian( false ); |
|
byteswap.SwapFieldsToTargetEndian( pinfo ); |
|
|
|
return true; |
|
} |
|
|
|
client_textmessage_t *CEngineClient::TextMessageGet( const char *pName ) |
|
{ |
|
return ::TextMessageGet( pName ); |
|
} |
|
|
|
bool CEngineClient::Con_IsVisible( void ) |
|
{ |
|
return ::Con_IsVisible(); |
|
} |
|
|
|
int CEngineClient::GetLocalPlayer( void ) |
|
{ |
|
return cl.m_nPlayerSlot + 1; |
|
} |
|
|
|
float CEngineClient::GetLastTimeStamp( void ) |
|
{ |
|
return cl.m_flLastServerTickTime; |
|
} |
|
|
|
bool CEngineClient::MapHasHDRLighting( void) |
|
{ |
|
return modelloader->LastLoadedMapHasHDRLighting(); |
|
} |
|
|
|
const model_t *CEngineClient::LoadModel( const char *pName, bool bProp ) |
|
{ |
|
return modelloader->GetModelForName( pName, bProp ? IModelLoader::FMODELLOADER_DETAILPROP : IModelLoader::FMODELLOADER_CLIENTDLL ); |
|
} |
|
|
|
CSentence *CEngineClient::GetSentence( CAudioSource *pAudioSource ) |
|
{ |
|
if (pAudioSource) |
|
{ |
|
return pAudioSource->GetSentence(); |
|
} |
|
return NULL; |
|
} |
|
|
|
void AddPhonemesFromFile( const char *pszFileName ); |
|
|
|
void CEngineClient::AddPhonemeFile( const char *pszPhonemeFile ) |
|
{ |
|
AddPhonemesFromFile( pszPhonemeFile ); |
|
} |
|
|
|
float CEngineClient::GetSentenceLength( CAudioSource *pAudioSource ) |
|
{ |
|
if (pAudioSource && pAudioSource->SampleRate() > 0 ) |
|
{ |
|
float length = (float)pAudioSource->SampleCount() / (float)pAudioSource->SampleRate(); |
|
return length; |
|
} |
|
return 0.0f; |
|
} |
|
|
|
bool CEngineClient::IsStreaming( CAudioSource *pAudioSource ) const |
|
{ |
|
if ( pAudioSource ) |
|
{ |
|
return pAudioSource->IsStreaming(); |
|
} |
|
return false; |
|
} |
|
|
|
// FIXME, move entirely to client .dll |
|
void CEngineClient::GetViewAngles( QAngle& va ) |
|
{ |
|
VectorCopy( cl.viewangles, va ); |
|
} |
|
|
|
void CEngineClient::SetViewAngles( QAngle& va ) |
|
{ |
|
cl.viewangles.x = AngleNormalize( va.x ); |
|
cl.viewangles.y = AngleNormalize( va.y ); |
|
cl.viewangles.z = AngleNormalize( va.z ); |
|
Assert( !IS_NAN(cl.viewangles.x ) ); |
|
Assert( !IS_NAN(cl.viewangles.y ) ); |
|
Assert( !IS_NAN(cl.viewangles.z ) ); |
|
} |
|
|
|
int CEngineClient::GetMaxClients( void ) |
|
{ |
|
return cl.m_nMaxClients; |
|
} |
|
|
|
void CEngineClient::SetMapLoadFailed( bool bState ) |
|
{ |
|
g_ServerGlobalVariables.bMapLoadFailed = bState; |
|
} |
|
|
|
bool CEngineClient::MapLoadFailed( void ) |
|
{ |
|
return g_ServerGlobalVariables.bMapLoadFailed; |
|
} |
|
|
|
void CEngineClient::ReadConfiguration( const bool readDefault /*= false*/ ) |
|
{ |
|
Host_ReadConfiguration(); |
|
} |
|
|
|
const char *CEngineClient::Key_LookupBinding( const char *pBinding ) |
|
{ |
|
return ::Key_NameForBinding( pBinding ); |
|
} |
|
|
|
const char *CEngineClient::Key_LookupBindingExact( const char *pBinding ) |
|
{ |
|
return ::Key_NameForBindingExact( pBinding ); |
|
} |
|
|
|
const char *CEngineClient::Key_BindingForKey( ButtonCode_t code ) |
|
{ |
|
return ::Key_BindingForKey( code ); |
|
} |
|
|
|
void CEngineClient::StartKeyTrapMode( void ) |
|
{ |
|
Key_StartTrapMode(); |
|
} |
|
|
|
bool CEngineClient::CheckDoneKeyTrapping( ButtonCode_t &code ) |
|
{ |
|
return Key_CheckDoneTrapping( code ); |
|
} |
|
|
|
bool CEngineClient::IsInGame( void ) |
|
{ |
|
return cl.IsActive(); |
|
} |
|
|
|
bool CEngineClient::IsConnected( void ) |
|
{ |
|
return cl.IsConnected(); |
|
} |
|
|
|
bool CEngineClient::IsDrawingLoadingImage( void ) |
|
{ |
|
return scr_drawloading; |
|
} |
|
|
|
void CEngineClient::Con_NPrintf( int pos, const char *fmt, ... ) |
|
{ |
|
va_list argptr; |
|
char text[4096]; |
|
va_start (argptr, fmt); |
|
Q_vsnprintf(text, sizeof( text ), fmt, argptr); |
|
va_end (argptr); |
|
|
|
::Con_NPrintf( pos, "%s", text ); |
|
} |
|
|
|
void CEngineClient::Con_NXPrintf( const struct con_nprint_s *info, const char *fmt, ... ) |
|
{ |
|
va_list argptr; |
|
char text[4096]; |
|
va_start (argptr, fmt); |
|
Q_vsnprintf(text, sizeof( text ), fmt, argptr); |
|
va_end (argptr); |
|
|
|
::Con_NXPrintf( info, "%s", text ); |
|
} |
|
|
|
IMaterial *CEngineClient::TraceLineMaterialAndLighting( const Vector &start, const Vector &end, |
|
Vector &diffuseLightColor, Vector &baseColor ) |
|
{ |
|
return BrushModel_GetLightingAndMaterial( start, end, diffuseLightColor, baseColor ); |
|
} |
|
|
|
int CEngineClient::IsBoxVisible( const Vector& mins, const Vector& maxs ) |
|
{ |
|
return CM_BoxVisible( mins, maxs, Map_VisCurrent(), CM_ClusterPVSSize() ); |
|
} |
|
|
|
int CEngineClient::IsBoxInViewCluster( const Vector& mins, const Vector& maxs ) |
|
{ |
|
// See comments in Map_VisCurrentCluster for why we might get a negative number. |
|
int curCluster = Map_VisCurrentCluster(); |
|
if ( curCluster < 0 ) |
|
return false; |
|
|
|
byte pvs[MAX_MAP_LEAFS/8]; |
|
const byte *ppvs = CM_Vis( pvs, sizeof(pvs), curCluster, DVIS_PVS ); |
|
return CM_BoxVisible(mins, maxs, ppvs, sizeof(pvs) ); |
|
} |
|
|
|
float CEngineClient::Time() |
|
{ |
|
return Sys_FloatTime(); |
|
} |
|
|
|
void CEngineClient::Sound_ExtraUpdate( void ) |
|
{ |
|
// On xbox this is not necessary except for long pauses, so unhook this one |
|
if ( IsX360() ) |
|
return; |
|
|
|
VPROF_BUDGET( "CEngineClient::Sound_ExtraUpdate()", VPROF_BUDGETGROUP_OTHER_SOUND ); |
|
|
|
S_ExtraUpdate(); |
|
} |
|
|
|
bool CEngineClient::CullBox ( const Vector& mins, const Vector& maxs ) |
|
{ |
|
return R_CullBoxSkipNear( mins, maxs, g_Frustum ); |
|
} |
|
|
|
const char *CEngineClient::GetGameDirectory( void ) |
|
{ |
|
return com_gamedir; |
|
} |
|
|
|
const VMatrix& CEngineClient::WorldToScreenMatrix() |
|
{ |
|
// FIXME: this is only valid if we're currently rendering. If not, it should use the player, or it really should pass one in. |
|
return g_EngineRenderer->WorldToScreenMatrix(); |
|
} |
|
|
|
const VMatrix& CEngineClient::WorldToViewMatrix() |
|
{ |
|
// FIXME: this is only valid if we're currently rendering. If not, it should use the player, or it really should pass one in. |
|
return g_EngineRenderer->ViewMatrix(); |
|
} |
|
|
|
// Loads a game lump off disk |
|
int CEngineClient::GameLumpVersion( int lumpId ) const |
|
{ |
|
return Mod_GameLumpVersion( lumpId ); |
|
} |
|
|
|
int CEngineClient::GameLumpSize( int lumpId ) const |
|
{ |
|
return Mod_GameLumpSize( lumpId ); |
|
} |
|
|
|
bool CEngineClient::LoadGameLump( int lumpId, void* pBuffer, int size ) |
|
{ |
|
return Mod_LoadGameLump( lumpId, pBuffer, size ); |
|
} |
|
|
|
// Returns the number of leaves in the level |
|
int CEngineClient::LevelLeafCount() const |
|
{ |
|
return host_state.worldbrush->numleafs; |
|
} |
|
|
|
ISpatialQuery* CEngineClient::GetBSPTreeQuery() |
|
{ |
|
return g_pToolBSPTree; |
|
} |
|
|
|
// Convert texlight to gamma... |
|
void CEngineClient::LinearToGamma( float* linear, float* gamma ) |
|
{ |
|
gamma[0] = LinearToTexture( linear[0] ) / 255.0f; |
|
gamma[1] = LinearToTexture( linear[1] ) / 255.0f; |
|
gamma[2] = LinearToTexture( linear[2] ) / 255.0f; |
|
} |
|
|
|
// Get the lightstyle value |
|
float CEngineClient::LightStyleValue( int style ) |
|
{ |
|
return ::LightStyleValue( style ); |
|
} |
|
|
|
|
|
void CEngineClient::DrawPortals() |
|
{ |
|
R_DrawPortals(); |
|
} |
|
|
|
// Computes light due to dynamic lighting at a point |
|
// If the normal isn't specified, then it'll return the maximum lighting |
|
void CEngineClient::ComputeDynamicLighting( Vector const& pt, Vector const* pNormal, Vector& color ) |
|
{ |
|
::ComputeDynamicLighting( pt, pNormal, color ); |
|
} |
|
|
|
// Computes light due to dynamic lighting at a point |
|
// If the normal isn't specified, then it'll return the maximum lighting |
|
void CEngineClient::ComputeLighting( const Vector& pt, const Vector* pNormal, bool bClamp, Vector& color, Vector *pBoxColors ) |
|
{ |
|
::ComputeLighting( pt, pNormal, bClamp, color, pBoxColors ); |
|
} |
|
|
|
// Returns the color of the ambient light |
|
void CEngineClient::GetAmbientLightColor( Vector& color ) |
|
{ |
|
dworldlight_t* pWorldLight = FindAmbientLight(); |
|
if (!pWorldLight) |
|
color.Init( 0, 0, 0 ); |
|
else |
|
VectorCopy( pWorldLight->intensity, color ); |
|
} |
|
|
|
// Returns the dx support level |
|
int CEngineClient::GetDXSupportLevel() |
|
{ |
|
return g_pMaterialSystemHardwareConfig->GetDXSupportLevel(); |
|
} |
|
|
|
bool CEngineClient::SupportsHDR() |
|
{ |
|
// deprecated. |
|
// Assert( 0 ); |
|
return false; |
|
} |
|
|
|
void CEngineClient::Mat_Stub( IMaterialSystem *pMatSys ) |
|
{ |
|
materials = pMatSys; |
|
|
|
// Pass the call to the model renderer. |
|
if ( g_pStudioRender ) |
|
g_pStudioRender->Mat_Stub( pMatSys ); |
|
} |
|
|
|
void CEngineClient::GetChapterName( char *pchBuff, int iMaxLength ) |
|
{ |
|
serverGameDLL->GetSaveComment( pchBuff, iMaxLength, 0.0f, 0.0f, true ); |
|
} |
|
|
|
char const *CEngineClient::GetLevelName( void ) |
|
{ |
|
if ( sv.IsDedicated() ) |
|
{ |
|
return "Dedicated Server"; |
|
} |
|
else if ( !cl.IsConnected() ) |
|
{ |
|
return ""; |
|
} |
|
|
|
return cl.m_szLevelFileName; |
|
} |
|
|
|
int CEngineClient::GetLevelVersion( void ) |
|
{ |
|
return g_ServerGlobalVariables.mapversion; |
|
} |
|
|
|
bool CEngineClient::IsLevelMainMenuBackground( void ) |
|
{ |
|
return sv.IsLevelMainMenuBackground(); |
|
} |
|
|
|
void CEngineClient::GetMainMenuBackgroundName( char *dest, int destlen ) |
|
{ |
|
CL_GetBackgroundLevelName( dest, destlen, false ); |
|
} |
|
|
|
// Occlusion system control |
|
void CEngineClient::SetOcclusionParameters( const OcclusionParams_t ¶ms ) |
|
{ |
|
OcclusionSystem()->SetOcclusionParameters( params.m_flMaxOccludeeArea, params.m_flMinOccluderArea ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Takes a trackerID and returns which player slot that user is in |
|
// returns 0 if no player found with that ID |
|
//----------------------------------------------------------------------------- |
|
int CEngineClient::GetPlayerForUserID(int userID) |
|
{ |
|
if ( !cl.m_pUserInfoTable ) |
|
return 0; |
|
|
|
// We are occasionally getting crashes here where it looks like cl.m_nMaxClients |
|
// is larger than the number of items in cl.m_pUserInfoTable. Callstack: |
|
// engine.dll CEngineClient::GetPlayerForUserID |
|
// client.dll CTFHudDeathNotice::OnGameEvent |
|
// client.dll CHudBaseDeathNotice::FireGameEvent |
|
// client.dll CTFHudDeathNotice::FireGameEvent |
|
// engine.dll CGameEventManager::FireEventIntern |
|
// engine.dll CGameEventManager::FireEventClientSide |
|
// engine.dll CClientState::ProcessGameEvent |
|
// So add check to make sure we don't go over m_pUserInfoTable size. |
|
int nMaxClients = Min( cl.m_nMaxClients, cl.m_pUserInfoTable->GetNumStrings() ); |
|
for ( int i = 0; i < nMaxClients; i++ ) |
|
{ |
|
player_info_t *pi = (player_info_t*) cl.m_pUserInfoTable->GetStringUserData( i, NULL ); |
|
|
|
if ( !pi ) |
|
continue; |
|
|
|
// Fixup from network order (little endian) |
|
if ( LittleLong( pi->userID ) == userID ) |
|
{ |
|
// return as entity index |
|
return (i+1); |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
#if !defined( NO_VOICE ) |
|
struct IVoiceTweak_s *CEngineClient::GetVoiceTweakAPI( void ) |
|
{ |
|
return &g_VoiceTweakAPI; |
|
} |
|
#endif |
|
|
|
void CEngineClient::EngineStats_BeginFrame( void ) |
|
{ |
|
g_EngineStats.BeginFrame(); |
|
} |
|
|
|
void CEngineClient::EngineStats_EndFrame( void ) |
|
{ |
|
g_EngineStats.EndFrame(); |
|
} |
|
|
|
void CEngineClient::FireEvents() |
|
{ |
|
// Run any events queued up for this frame |
|
CL_FireEvents(); |
|
} |
|
|
|
void CEngineClient::CheckPoint( const char *pName ) |
|
{ |
|
GetTestScriptMgr()->CheckPoint( pName ); |
|
} |
|
|
|
int CEngineClient::GetLeavesArea( int *pLeaves, int nLeaves ) |
|
{ |
|
if ( nLeaves == 0 ) |
|
return -1; |
|
|
|
int iArea = host_state.worldbrush->leafs[pLeaves[0]].area; |
|
for ( int i=1; i < nLeaves; i++ ) |
|
{ |
|
int iTestArea = host_state.worldbrush->leafs[pLeaves[i]].area; |
|
if ( iTestArea != iArea ) |
|
return -1; |
|
} |
|
|
|
return iArea; |
|
} |
|
|
|
bool CEngineClient::DoesBoxTouchAreaFrustum( const Vector &mins, const Vector &maxs, int iArea ) |
|
{ |
|
const Frustum_t *pFrustum = GetAreaFrustum( iArea ); |
|
return !R_CullBoxSkipNear( mins, maxs, *pFrustum ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Sets the hearing origin |
|
//----------------------------------------------------------------------------- |
|
void CEngineClient::SetAudioState( const AudioState_t &audioState ) |
|
{ |
|
Host_SetAudioState( audioState ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
// Sentence API |
|
// |
|
//----------------------------------------------------------------------------- |
|
|
|
int CEngineClient::SentenceGroupPick( int groupIndex, char *name, int nameLen ) |
|
{ |
|
return VOX_GroupPick( groupIndex, name, nameLen ); |
|
} |
|
|
|
|
|
int CEngineClient::SentenceGroupPickSequential( int groupIndex, char *name, int nameLen, int sentenceIndex, int reset ) |
|
{ |
|
return VOX_GroupPickSequential( groupIndex, name, nameLen, sentenceIndex, reset ); |
|
} |
|
|
|
int CEngineClient::SentenceIndexFromName( const char *pSentenceName ) |
|
{ |
|
int sentenceIndex = -1; |
|
|
|
VOX_LookupString( pSentenceName, &sentenceIndex ); |
|
|
|
return sentenceIndex; |
|
} |
|
|
|
const char *CEngineClient::SentenceNameFromIndex( int sentenceIndex ) |
|
{ |
|
return VOX_SentenceNameFromIndex( sentenceIndex ); |
|
} |
|
|
|
|
|
int CEngineClient::SentenceGroupIndexFromName( const char *pGroupName ) |
|
{ |
|
return VOX_GroupIndexFromName( pGroupName ); |
|
} |
|
|
|
const char *CEngineClient::SentenceGroupNameFromIndex( int groupIndex ) |
|
{ |
|
return VOX_GroupNameFromIndex( groupIndex ); |
|
} |
|
|
|
|
|
float CEngineClient::SentenceLength( int sentenceIndex ) |
|
{ |
|
return VOX_SentenceLength( sentenceIndex ); |
|
} |
|
|
|
void CEngineClient::DebugDrawPhysCollide( const CPhysCollide *pCollide, IMaterial *pMaterial, matrix3x4_t& transform, const color32 &color ) |
|
{ |
|
::DebugDrawPhysCollide( pCollide, pMaterial, transform, color, false ); |
|
} |
|
|
|
// Activates/deactivates an occluder... |
|
void CEngineClient::ActivateOccluder( int nOccluderIndex, bool bActive ) |
|
{ |
|
OcclusionSystem()->ActivateOccluder( nOccluderIndex, bActive ); |
|
} |
|
|
|
bool CEngineClient::IsOccluded( const Vector &vecAbsMins, const Vector &vecAbsMaxs ) |
|
{ |
|
return OcclusionSystem()->IsOccluded( vecAbsMins, vecAbsMaxs ); |
|
} |
|
|
|
void *CEngineClient::SaveAllocMemory( size_t num, size_t size ) |
|
{ |
|
return ::SaveAllocMemory( num, size ); |
|
} |
|
|
|
void CEngineClient::SaveFreeMemory( void *pSaveMem ) |
|
{ |
|
::SaveFreeMemory( pSaveMem ); |
|
} |
|
|
|
INetChannelInfo *CEngineClient::GetNetChannelInfo( void ) |
|
{ |
|
return (INetChannelInfo*)cl.m_NetChannel; |
|
} |
|
|
|
bool CEngineClient::IsPlayingDemo( void ) |
|
{ |
|
return demoplayer->IsPlayingBack(); |
|
} |
|
|
|
bool CEngineClient::IsRecordingDemo( void ) |
|
{ |
|
return demorecorder->IsRecording(); |
|
} |
|
|
|
bool CEngineClient::IsPlayingTimeDemo( void ) |
|
{ |
|
return demoplayer->IsPlayingTimeDemo(); |
|
} |
|
|
|
bool CEngineClient::IsPaused( void ) |
|
{ |
|
return cl.IsPaused(); |
|
} |
|
|
|
bool CEngineClient::IsTakingScreenshot( void ) |
|
{ |
|
return cl_takesnapshot; |
|
} |
|
|
|
int CEngineClient::GetDemoRecordingTick( void ) |
|
{ |
|
return demorecorder->GetRecordingTick(); |
|
} |
|
|
|
int CEngineClient::GetDemoPlaybackTick( void ) |
|
{ |
|
return demoplayer->GetPlaybackTick(); |
|
} |
|
|
|
int CEngineClient::GetDemoPlaybackStartTick( void ) |
|
{ |
|
return demoplayer->GetPlaybackStartTick(); |
|
} |
|
|
|
float CEngineClient::GetDemoPlaybackTimeScale( void ) |
|
{ |
|
return demoplayer->GetPlaybackTimeScale(); |
|
} |
|
|
|
int CEngineClient::GetDemoPlaybackTotalTicks( void ) |
|
{ |
|
return demoplayer->GetTotalTicks(); |
|
} |
|
|
|
bool CEngineClient::IsHLTV( void ) |
|
{ |
|
return cl.ishltv; |
|
} |
|
|
|
void CEngineClient::GetVideoModes( int &nCount, vmode_s *&pModes ) |
|
{ |
|
nCount = videomode->GetModeCount(); |
|
pModes = videomode->GetMode( 0 ); |
|
} |
|
|
|
void CEngineClient::GetUILanguage( char *dest, int destlen ) |
|
{ |
|
const char *pStr = cl_language.GetString(); |
|
if ( pStr ) |
|
{ |
|
V_strncpy( dest, pStr, destlen ); |
|
} |
|
else if ( IsX360() ) |
|
{ |
|
dest[0] = 0; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Can skybox be seen from a particular point? |
|
//----------------------------------------------------------------------------- |
|
SkyboxVisibility_t CEngineClient::IsSkyboxVisibleFromPoint( const Vector &vecPoint ) |
|
{ |
|
// In the mat_fullbright 1 case, it's always visible |
|
// (we may have no lighting in the level, and vrad is where LEAF_FLAGS_SKY is computed) |
|
if ( g_pMaterialSystemConfig->nFullbright == 1 ) |
|
return SKYBOX_3DSKYBOX_VISIBLE; |
|
|
|
int nLeaf = CM_PointLeafnum( vecPoint ); |
|
int nFlags = GetCollisionBSPData()->map_leafs[nLeaf].flags; |
|
if ( nFlags & LEAF_FLAGS_SKY ) |
|
return SKYBOX_3DSKYBOX_VISIBLE; |
|
return ( nFlags & LEAF_FLAGS_SKY2D ) ? SKYBOX_2DSKYBOX_VISIBLE : SKYBOX_NOT_VISIBLE; |
|
} |
|
|
|
const char* CEngineClient::GetMapEntitiesString() |
|
{ |
|
return CM_EntityString(); |
|
} |
|
|
|
bool CEngineClient::IsInEditMode( void ) |
|
{ |
|
return g_bInEditMode; |
|
} |
|
|
|
bool CEngineClient::IsInCommentaryMode( void ) |
|
{ |
|
return g_bInCommentaryMode; |
|
} |
|
|
|
float CEngineClient::GetScreenAspectRatio() |
|
{ |
|
return GetScreenAspect( ); |
|
} |
|
|
|
int CEngineClient::GetAppID() |
|
{ |
|
return GetSteamAppID(); |
|
} |
|
|
|
void CEngineClient::SetOverlayBindProxy( int iOverlayID, void *pBindProxy ) |
|
{ |
|
OverlayMgr()->SetOverlayBindProxy( iOverlayID, pBindProxy ); |
|
} |
|
|
|
void CEngineClient::ChangeTeam( const char *pTeamName ) |
|
{ |
|
g_pMatchmaking->ChangeTeam( pTeamName ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns true if copy occured |
|
//----------------------------------------------------------------------------- |
|
bool CEngineClient::CopyFrameBufferToMaterial( const char *pMaterialName ) |
|
{ |
|
if ( !IsX360() ) |
|
{ |
|
// not for PC |
|
Assert( 0 ); |
|
return false; |
|
} |
|
|
|
IMaterial *pMaterial = materials->FindMaterial( pMaterialName, TEXTURE_GROUP_OTHER ); |
|
if ( pMaterial->IsErrorMaterial() ) |
|
{ |
|
// unknown material |
|
return false; |
|
} |
|
|
|
bool bFound; |
|
IMaterialVar *pMaterialVar = pMaterial->FindVar( "$baseTexture", &bFound, false ); |
|
if ( !bFound || pMaterialVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE ) |
|
{ |
|
// lack of expected $basetexture |
|
return false; |
|
} |
|
|
|
ITexture *pTexture = pMaterialVar->GetTextureValue(); |
|
if ( !pTexture || !pTexture->IsRenderTarget() ) |
|
{ |
|
// base texture is not a render target |
|
return false; |
|
} |
|
|
|
CMatRenderContextPtr pRenderContext( materials ); |
|
|
|
int width, height; |
|
pRenderContext->GetRenderTargetDimensions( width, height ); |
|
if ( width != pTexture->GetActualWidth() || height != pTexture->GetActualHeight() ) |
|
{ |
|
// better be matched, not supporting a disparate blit in this context |
|
// disparate blit may very well use same RT we are trying to copy into |
|
return false; |
|
} |
|
|
|
pRenderContext->CopyRenderTargetToTexture( pTexture ); |
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Used by the color correction UI |
|
//----------------------------------------------------------------------------- |
|
void CEngineClient::GrabPreColorCorrectedFrame( int x, int y, int width, int height ) |
|
{ |
|
colorcorrectiontools->GrabPreColorCorrectedFrame( x, y, width, height ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Is hammer running? |
|
//----------------------------------------------------------------------------- |
|
bool CEngineClient::IsHammerRunning( ) const |
|
{ |
|
return IsPC() ? InEditMode() : false; |
|
} |
|
|
|
extern IAchievementMgr *g_pAchievementMgr; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Sets achievement mgr |
|
//----------------------------------------------------------------------------- |
|
void CEngineClient::SetAchievementMgr( IAchievementMgr *pAchievementMgr ) |
|
{ |
|
g_pAchievementMgr = pAchievementMgr; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Gets achievement mgr |
|
//----------------------------------------------------------------------------- |
|
IAchievementMgr *CEngineClient::GetAchievementMgr() |
|
{ |
|
return g_pAchievementMgr; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Called by the client to determine violence settings for things like ragdoll |
|
// fading. |
|
//----------------------------------------------------------------------------- |
|
bool CEngineClient::IsLowViolence() |
|
{ |
|
return g_bLowViolence; |
|
} |
|
|
|
const char *CEngineClient::GetMostRecentSaveGame( void ) |
|
{ |
|
return saverestore->GetMostRecentlyLoadedFileName(); |
|
} |
|
|
|
void CEngineClient::SetMostRecentSaveGame( const char *lpszFilename ) |
|
{ |
|
saverestore->SetMostRecentSaveGame( lpszFilename ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Called by gameui to hint the engine that an exiting process has started. |
|
// The Engine needs to stabilize to a safe quiet state. More frames are going |
|
// to and have to run, but the true exit will occur. |
|
//----------------------------------------------------------------------------- |
|
void CEngineClient::StartXboxExitingProcess() |
|
{ |
|
if ( IsPC() ) |
|
{ |
|
// not for PC |
|
return; |
|
} |
|
|
|
g_pInputSystem->StopRumble(); |
|
|
|
// save out the achievements |
|
g_pAchievementMgr->SaveGlobalStateIfDirty( false ); |
|
|
|
S_StopAllSounds( true ); |
|
|
|
// Shutdown QMS, need to go back to single threaded |
|
Host_AllowQueuedMaterialSystem( false ); |
|
} |
|
|
|
bool CEngineClient::IsSaveInProgress() |
|
{ |
|
return saverestore->IsSaveInProgress(); |
|
} |
|
|
|
extern IXboxSystem *g_pXboxSystem; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
uint CEngineClient::OnStorageDeviceAttached( void ) |
|
{ |
|
return g_pXboxSystem->OpenContainers(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEngineClient::OnStorageDeviceDetached( void ) |
|
{ |
|
XBX_SetStorageDeviceId( XBX_INVALID_STORAGE_ID ); |
|
g_pXboxSystem->CloseContainers(); |
|
} |
|
|
|
|
|
ISPSharedMemory *CEngineClient::GetSinglePlayerSharedMemorySpace( const char *szName, int ent_num ) |
|
{ |
|
// TODO(nillerusr): it this necessary? Implement later if so |
|
return NULL; //g_pSinglePlayerSharedMemoryManager->GetSharedMemory( szName, ent_num ); |
|
} |
|
|
|
void CEngineClient::ResetDemoInterpolation( void ) |
|
{ |
|
if( demorecorder->IsRecording() ) |
|
demorecorder->ResetDemoInterpolation(); |
|
if (demoplayer->IsPlayingBack() ) |
|
demoplayer->ResetDemoInterpolation(); |
|
} |
|
|
|
|
|
extern CGamestatsData *g_pGamestatsData; |
|
void CEngineClient::SetGamestatsData( CGamestatsData *pGamestatsData ) |
|
{ |
|
g_pGamestatsData = pGamestatsData; |
|
} |
|
|
|
CGamestatsData *CEngineClient::GetGamestatsData() |
|
{ |
|
return g_pGamestatsData; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
#if defined( USE_SDL ) |
|
|
|
void CEngineClient::GetMouseDelta( int &x, int &y, bool bIgnoreNextMouseDelta ) |
|
{ |
|
g_pLauncherMgr->GetMouseDelta( x, y, bIgnoreNextMouseDelta ); |
|
} |
|
|
|
#endif |
|
|
|
|
|
void CEngineClient::ServerCmdKeyValues( KeyValues *pKeyValues ) |
|
{ |
|
cl.SendServerCmdKeyValues( pKeyValues ); |
|
} |
|
|
|
bool CEngineClient::IsSkippingPlayback( void ) |
|
{ |
|
return demoplayer->IsSkipping(); |
|
} |
|
|
|
bool CEngineClient::IsLoadingDemo( void ) |
|
{ |
|
return demoplayer->IsLoading(); |
|
} |
|
|
|
bool CEngineClient::IsPlayingDemoALocallyRecordedDemo() |
|
{ |
|
return IsPlayingDemo() && |
|
demoplayer && |
|
demoplayer->GetDemoFile() && |
|
!V_strnicmp( demoplayer->GetDemoFile()->m_DemoHeader.servername, "localhost", 9 ); |
|
} |
|
|
|
uint CEngineClient::GetProtocolVersion() |
|
{ |
|
if ( demoplayer && demoplayer->IsPlayingBack() ) |
|
{ |
|
return demoplayer->GetProtocolVersion(); |
|
} |
|
return PROTOCOL_VERSION; |
|
} |
|
|
|
bool CEngineClient::IsWindowedMode() |
|
{ |
|
return videomode->IsWindowedMode(); |
|
} |
|
|
|
int CEngineClient::GetClientVersion() const |
|
{ |
|
return GetSteamInfIDVersionInfo().ClientVersion; |
|
} |
|
|
|
bool CEngineClient::IsActiveApp( void ) |
|
{ |
|
return game->IsActiveApp(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Previously ConCommand disconnect |
|
//----------------------------------------------------------------------------- |
|
void CEngineClient::DisconnectInternal( void ) |
|
{ |
|
Disconnect(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// The client DLL serves out this interface |
|
//----------------------------------------------------------------------------- |
|
IBaseClientDLL *g_ClientDLL = NULL; |
|
IClientVirtualReality *g_pClientVR = NULL; |
|
IPrediction *g_pClientSidePrediction = NULL; |
|
IClientRenderTargets *g_pClientRenderTargets = NULL; |
|
IClientEntityList *entitylist = NULL; |
|
ICenterPrint *centerprint = NULL; |
|
IClientLeafSystemEngine *clientleafsystem = NULL; |
|
bool g_bClientLeafSystemV1; |
|
ClientClass *g_pClientClassHead = NULL; |
|
IClientReplay *g_pClientReplay = NULL; |
|
|
|
ClientClass *ClientDLL_GetAllClasses( void ) |
|
{ |
|
if ( g_ClientDLL ) |
|
return g_ClientDLL->GetAllClasses(); |
|
else |
|
return g_pClientClassHead; |
|
} |
|
|
|
static void ClientDLL_InitRecvTableMgr() |
|
{ |
|
// Register all the receive tables. |
|
RecvTable *pRecvTables[MAX_DATATABLES]; |
|
int nRecvTables = 0; |
|
for ( ClientClass *pCur = ClientDLL_GetAllClasses(); pCur; pCur=pCur->m_pNext ) |
|
{ |
|
ErrorIfNot( |
|
nRecvTables < ARRAYSIZE( pRecvTables ), |
|
("ClientDLL_InitRecvTableMgr: overflowed MAX_DATATABLES") |
|
); |
|
|
|
pRecvTables[nRecvTables] = pCur->m_pRecvTable; |
|
++nRecvTables; |
|
} |
|
|
|
RecvTable_Init( pRecvTables, nRecvTables ); |
|
} |
|
|
|
|
|
static void ClientDLL_ShutdownRecvTableMgr() |
|
{ |
|
RecvTable_Term(); |
|
} |
|
|
|
CreateInterfaceFn ClientDLL_GetFactory( void ) |
|
{ |
|
return g_ClientFactory; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Loads the client DLL |
|
// Input : - |
|
//----------------------------------------------------------------------------- |
|
bool ClientDLL_Load() |
|
{ |
|
Assert ( !g_ClientDLLModule ); |
|
|
|
// Check the signature on the client dll. If this fails we load it anyway but put this client |
|
// into insecure mode so it won't connect to secure servers and get VAC banned |
|
if ( !Host_AllowLoadModule( "client.dll", "GAMEBIN", true ) ) |
|
{ |
|
// not supposed to load this but we will anyway |
|
Host_DisallowSecureServers(); |
|
Host_AllowLoadModule( "client.dll","GAMEBIN", true ); |
|
} |
|
|
|
g_ClientDLLModule = g_pFileSystem->LoadModule( "client", "GAMEBIN", false ); |
|
if ( g_ClientDLLModule ) |
|
{ |
|
g_ClientFactory = Sys_GetFactory( g_ClientDLLModule ); |
|
if ( g_ClientFactory ) |
|
{ |
|
g_ClientDLL = (IBaseClientDLL *)g_ClientFactory( CLIENT_DLL_INTERFACE_VERSION, NULL ); |
|
// this is to ensure the old format of the string table is used for clients version 13 and older. |
|
// when the client version gets revved, there will need to be an else that sets this bool to true |
|
g_bClientGameDLLGreaterThanV13 = false; |
|
if ( !g_ClientDLL ) |
|
{ |
|
Sys_Error( "Could not get client.dll interface from library client" ); |
|
} |
|
|
|
if( g_pSourceVR ) |
|
{ |
|
g_pClientVR = (IClientVirtualReality *)g_ClientFactory( CLIENTVIRTUALREALITY_INTERFACE_VERSION, NULL ); |
|
if( !g_pClientVR ) |
|
{ |
|
Msg( "client.dll is not VR-compatible.\n" ); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
Sys_Error( "Could not find factory interface in library client" ); |
|
} |
|
} |
|
else |
|
{ |
|
// tell Steam to do a quick verify of the install. Sys_Error doesn't return, so do this first. |
|
if( Steam3Client().SteamApps() ) |
|
Steam3Client().SteamApps()->MarkContentCorrupt( true ); |
|
|
|
// library failed to load |
|
Sys_Error( "Could not load library client. Try restarting. If that doesn't work, verify the cache." ); |
|
} |
|
|
|
// Load the client render targets interface from the client .dll |
|
// NOTE: Its OK if this returns NULL, as some mods won't provide the interface and will just use the default behavior of the engine |
|
g_pClientRenderTargets = (IClientRenderTargets *)g_ClientFactory( CLIENTRENDERTARGETS_INTERFACE_VERSION, NULL ); |
|
|
|
return true; |
|
} |
|
|
|
void InitExtraClientCmdCanExecuteVars() |
|
{ |
|
// This can go away when we ship a client DLL with the FCVAR_CLIENTCMD_CAN_EXECUTE flag set on these cvars/concommands. |
|
Cmd_AddClientCmdCanExecuteVar( "cancelselect" ); |
|
Cmd_AddClientCmdCanExecuteVar( "menuselect" ); |
|
Cmd_AddClientCmdCanExecuteVar( "playgamesound" ); |
|
Cmd_AddClientCmdCanExecuteVar( "_cl_classmenuopen" ); |
|
Cmd_AddClientCmdCanExecuteVar( "cl_buy_favorite" ); |
|
Cmd_AddClientCmdCanExecuteVar( "voice_modenable" ); |
|
Cmd_AddClientCmdCanExecuteVar( "togglescores" ); |
|
|
|
Cmd_AddClientCmdCanExecuteVar( "spec_next" ); |
|
Cmd_AddClientCmdCanExecuteVar( "spec_prev" ); |
|
Cmd_AddClientCmdCanExecuteVar( "spec_mode" ); |
|
Cmd_AddClientCmdCanExecuteVar( "spec_menu" ); |
|
Cmd_AddClientCmdCanExecuteVar( "spec_autodirector" ); |
|
Cmd_AddClientCmdCanExecuteVar( "overview_zoom" ); |
|
Cmd_AddClientCmdCanExecuteVar( "overview_mode" ); |
|
Cmd_AddClientCmdCanExecuteVar( "overview_health" ); |
|
Cmd_AddClientCmdCanExecuteVar( "overview_names" ); |
|
Cmd_AddClientCmdCanExecuteVar( "overview_tracks" ); |
|
Cmd_AddClientCmdCanExecuteVar( "overview_locked" ); |
|
Cmd_AddClientCmdCanExecuteVar( "overview_alpha" ); |
|
|
|
Cmd_AddClientCmdCanExecuteVar( "playgamesound" ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Inits the client .dll |
|
//----------------------------------------------------------------------------- |
|
void ClientDLL_Init( void ) |
|
{ |
|
extern void CL_SetSteamCrashComment(); |
|
|
|
// Assert ClientDLL_Load successfully created these interfaces, as we need them to init properly |
|
Assert ( g_ClientDLL ); |
|
Assert ( g_ClientFactory ); |
|
|
|
// this will get updated after we load a map, but this gets video info if we sys_error() prior to loading a map |
|
CL_SetSteamCrashComment(); |
|
|
|
if ( g_ClientDLL ) |
|
{ |
|
COM_TimestampedLog( "g_ClientDLL->Init" ); |
|
|
|
if ( !g_ClientDLL->Init(g_AppSystemFactory, g_AppSystemFactory, &g_ClientGlobalVariables ) ) |
|
{ |
|
Sys_Error("Client.dll Init() in library client failed."); |
|
} |
|
|
|
if ( g_ClientFactory ) |
|
{ |
|
COM_TimestampedLog( "g_pClientSidePrediction->Init" ); |
|
|
|
// Load the prediction interface from the client .dll |
|
g_pClientSidePrediction = (IPrediction *)g_ClientFactory( VCLIENT_PREDICTION_INTERFACE_VERSION, NULL ); |
|
if ( !g_pClientSidePrediction ) |
|
{ |
|
Sys_Error( "Could not get IPrediction interface from library client" ); |
|
} |
|
g_pClientSidePrediction->Init(); |
|
|
|
entitylist = ( IClientEntityList *)g_ClientFactory( VCLIENTENTITYLIST_INTERFACE_VERSION, NULL ); |
|
if ( !entitylist ) |
|
{ |
|
Sys_Error( "Could not get client entity list interface from library client" ); |
|
} |
|
|
|
centerprint = ( ICenterPrint * )g_ClientFactory( VCENTERPRINT_INTERFACE_VERSION, NULL ); |
|
if ( !centerprint ) |
|
{ |
|
Sys_Error( "Could not get centerprint interface from library client" ); |
|
} |
|
|
|
clientleafsystem = ( IClientLeafSystemEngine *)g_ClientFactory( CLIENTLEAFSYSTEM_INTERFACE_VERSION, NULL ); |
|
if ( clientleafsystem ) |
|
{ |
|
g_bClientLeafSystemV1 = false; |
|
} |
|
else if ( !clientleafsystem ) |
|
{ |
|
clientleafsystem = ( IClientLeafSystemEngine *)g_ClientFactory( CLIENTLEAFSYSTEM_INTERFACE_VERSION_1, NULL ); |
|
if ( !clientleafsystem ) |
|
{ |
|
Sys_Error( "Could not get client leaf system interface from library client" ); |
|
} |
|
else |
|
{ |
|
g_bClientLeafSystemV1 = true; |
|
} |
|
} |
|
|
|
#if defined( REPLAY_ENABLED ) |
|
if ( Replay_IsSupportedModAndPlatform() ) |
|
{ |
|
// Replay dll should be loaded by this point |
|
if ( !g_pReplay ) |
|
{ |
|
Sys_Error( "Replay.dll was not loaded" ); |
|
} |
|
|
|
// Get pointer to client-side replay interface implementation |
|
g_pClientReplay = (IClientReplay *)g_ClientFactory( CLIENT_REPLAY_INTERFACE_VERSION, NULL ); |
|
if ( !g_pClientReplay ) |
|
{ |
|
Sys_Error( "Could not get the replay interface from library client" ); |
|
} |
|
|
|
// Allow the client dll to setup pointers to replay interfaces |
|
extern CreateInterfaceFn g_fnReplayFactory; |
|
if ( !g_ClientDLL->ReplayInit( g_fnReplayFactory ) ) |
|
{ |
|
Sys_Error( "Client ReplayInit() failed!" ); |
|
} |
|
|
|
// Allow the replay dll to setup pointers to client interfaces |
|
if ( !g_pReplay->CL_Init( g_ClientFactory ) ) |
|
{ |
|
Sys_Error( "Replay system ClientInit() failed" ); |
|
} |
|
|
|
if ( !g_ClientDLL->ReplayPostInit() ) |
|
{ |
|
Sys_Error( "Client ReplayPostInit() failed!" ); |
|
} |
|
|
|
#if !defined( DEDICATED ) |
|
extern CGameServer sv; |
|
if ( !sv.IsDedicated() ) |
|
{ |
|
g_pClientReplayContext = g_pReplay->CL_GetContext(); |
|
g_pReplayManager = g_pClientReplayContext->GetReplayManager(); |
|
g_pReplayMovieManager = g_pClientReplayContext->GetMovieManager(); |
|
g_pReplayMovieRenderer = g_pClientReplayContext->GetMovieRenderer(); |
|
g_pReplayPerformanceManager = g_pClientReplayContext->GetPerformanceManager(); |
|
g_pReplayPerformanceController = g_pClientReplayContext->GetPerformanceController(); |
|
|
|
ReplayLib_Init( com_gamedir, g_pClientReplayContext ); |
|
} |
|
#endif |
|
} |
|
#endif |
|
|
|
toolframework->ClientInit( g_ClientFactory ); |
|
} |
|
|
|
// Don't want TF2 running less than DX 8 |
|
if ( g_pMaterialSystemHardwareConfig && g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) |
|
{ |
|
if ( ( Q_stricmp( COM_GetModDirectory(), "tf" ) == 0 ) || ( Q_stricmp( COM_GetModDirectory(), "ep2" ) == 0 ) || ( Q_stricmp( COM_GetModDirectory(), "portal" ) == 0 ) || ( Q_stricmp( COM_GetModDirectory(), "tf_beta" ) == 0 ) ) |
|
{ |
|
Sys_Error( "Your graphics hardware must support at least pixel shader version 1.1 to run this game!" ); |
|
} |
|
} |
|
} |
|
|
|
COM_TimestampedLog( "ClientDLL_InitRecvTableMgr" ); |
|
|
|
ClientDLL_InitRecvTableMgr(); |
|
|
|
InitExtraClientCmdCanExecuteVars(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Shuts down the client .dll |
|
//----------------------------------------------------------------------------- |
|
void ClientDLL_Shutdown( void ) |
|
{ |
|
#if defined( REPLAY_ENABLED ) |
|
if ( g_pReplay ) |
|
{ |
|
g_pReplay->CL_Shutdown(); |
|
} |
|
#endif |
|
|
|
toolframework->ClientShutdown(); |
|
|
|
ClientDLL_ShutdownRecvTableMgr(); |
|
|
|
vgui::ivgui()->RunFrame(); |
|
|
|
materials->UncacheAllMaterials(); |
|
|
|
vgui::ivgui()->RunFrame(); |
|
|
|
g_pClientSidePrediction->Shutdown(); |
|
|
|
entitylist = NULL; |
|
g_pClientSidePrediction = NULL; |
|
g_ClientFactory = NULL; |
|
centerprint = NULL; |
|
|
|
g_ClientDLL->Shutdown(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Unloads the client .dll |
|
// Input : - |
|
//----------------------------------------------------------------------------- |
|
void ClientDLL_Unload() |
|
{ |
|
FileSystem_UnloadModule( g_ClientDLLModule ); |
|
|
|
g_ClientDLL = NULL; |
|
g_ClientDLLModule = NULL; |
|
g_pClientRenderTargets = NULL; |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called when the game initializes and whenever the vid_mode is changed |
|
// so the HUD can reinitialize itself. |
|
//----------------------------------------------------------------------------- |
|
void ClientDLL_HudVidInit( void ) |
|
{ |
|
g_ClientDLL->HudVidInit(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Allow client .dll to modify input data |
|
//----------------------------------------------------------------------------- |
|
|
|
void ClientDLL_ProcessInput( void ) |
|
{ |
|
if ( !g_ClientDLL ) |
|
return; |
|
|
|
VPROF("ClientDLL_ProcessInput"); |
|
tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ ); |
|
g_ClientDLL->HudProcessInput( cl.IsConnected() ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ClientDLL_FrameStageNotify( ClientFrameStage_t frameStage ) |
|
{ |
|
if ( !g_ClientDLL ) |
|
return; |
|
|
|
tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ ); |
|
|
|
g_ClientDLL->FrameStageNotify( frameStage ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Allow client .dll to think |
|
//----------------------------------------------------------------------------- |
|
void ClientDLL_Update( void ) |
|
{ |
|
if ( sv.IsDedicated() ) |
|
return; |
|
|
|
if ( !g_ClientDLL ) |
|
return; |
|
|
|
g_ClientDLL->HudUpdate( true ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ClientDLL_VoiceStatus( int entindex, bool bTalking ) |
|
{ |
|
if( g_ClientDLL ) |
|
g_ClientDLL->VoiceStatus( entindex, bTalking ); |
|
} |
|
|
|
|
|
#ifdef IS_WINDOWS_PC |
|
#include "winlite.h" |
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEngineClient::FlashWindow() |
|
{ |
|
#ifndef USE_SDL |
|
FLASHWINFO flashwinfo; |
|
flashwinfo.cbSize = sizeof( flashwinfo ); |
|
flashwinfo.hwnd = (HWND)game->GetMainWindow(); |
|
flashwinfo.dwFlags = FLASHW_ALL; |
|
flashwinfo.uCount = 5; |
|
flashwinfo.dwTimeout = 0; |
|
FlashWindowEx( &flashwinfo ); |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CEngineClient::GetInstancesRunningCount( ) |
|
{ |
|
return CheckOtherInstancesRunning( ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
float CEngineClient::GetPausedExpireTime( void ) |
|
{ |
|
return cl.GetPausedExpireTime(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CEngineClient::StartDemoRecording( const char *pszFilename, const char *pszFolder /* = NULL */ ) |
|
{ |
|
bool bUseFolder = ( pszFolder && pszFolder[0] ); |
|
|
|
if ( demorecorder->IsRecording() ) |
|
{ |
|
ConMsg( "Already recording.\n" ); |
|
return false; |
|
} |
|
|
|
if ( demoplayer->IsPlayingBack() ) |
|
{ |
|
ConMsg( "Can't record during demo playback.\n" ); |
|
return false; |
|
} |
|
|
|
// check filename |
|
if ( !COM_IsValidPath( pszFilename ) ) |
|
{ |
|
ConMsg( "record %s: invalid filename.\n", pszFilename ); |
|
return false; |
|
} |
|
|
|
if ( bUseFolder ) |
|
{ |
|
// check folder |
|
if ( !COM_IsValidPath( pszFolder ) ) |
|
{ |
|
ConMsg( "record %s: invalid folder.\n", pszFolder ); |
|
return false; |
|
} |
|
} |
|
|
|
char szFinal[MAX_OSPATH]; |
|
char szTemp[MAX_OSPATH]; |
|
|
|
if ( !g_ClientDLL->CanRecordDemo( szTemp, sizeof( szTemp ) ) ) |
|
{ |
|
ConMsg( "%s\n", szTemp ); // re-use szTemp as the error string if the client prevents us from starting a demo |
|
return false; |
|
} |
|
|
|
if ( bUseFolder ) |
|
{ |
|
V_sprintf_safe( szTemp, "%s%c%s", pszFolder, CORRECT_PATH_SEPARATOR, pszFilename ); |
|
} |
|
else |
|
{ |
|
V_sprintf_safe( szTemp, "%s", pszFilename ); |
|
} |
|
|
|
// remove .dem extension if it exists |
|
Q_StripExtension( szTemp, szFinal, sizeof( szFinal ) ); |
|
|
|
// record it |
|
demorecorder->StartRecording( szFinal, false ); |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEngineClient::StopDemoRecording( void ) |
|
{ |
|
if ( !demorecorder->IsRecording() ) |
|
{ |
|
ConDMsg( "Not recording a demo.\n" ); |
|
return; |
|
} |
|
|
|
demorecorder->StopRecording(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEngineClient::TakeScreenshot( const char *pszFilename, const char *pszFolder /* = NULL */ ) |
|
{ |
|
bool bUseFolder = ( pszFolder && pszFolder[0] ); |
|
|
|
// check filename |
|
if ( !COM_IsValidPath( pszFilename ) ) |
|
{ |
|
ConMsg( "TakeScreenshot invalid filename: %s\n", pszFilename ); |
|
return; |
|
} |
|
|
|
if ( bUseFolder ) |
|
{ |
|
// check folder |
|
if ( !COM_IsValidPath( pszFolder ) ) |
|
{ |
|
ConMsg( "TakeScreenshot invalid folder: %s\n", pszFolder ); |
|
return; |
|
} |
|
} |
|
|
|
bool bReadPixelsFromFrontBuffer = g_pMaterialSystemHardwareConfig->ReadPixelsFromFrontBuffer(); |
|
if ( bReadPixelsFromFrontBuffer ) |
|
{ |
|
Shader_SwapBuffers(); |
|
} |
|
|
|
// Disable threading for the duration of the screenshots, because we need to get pointers to the (complete) |
|
// back buffer right now. |
|
bool bEnabled = materials->AllowThreading( false, g_nMaterialSystemThread ); |
|
|
|
char szFinal[MAX_OSPATH] = {0}; |
|
|
|
if ( bUseFolder ) |
|
{ |
|
V_sprintf_safe( szFinal, "%s%c%s", pszFolder, CORRECT_PATH_SEPARATOR, pszFilename ); |
|
} |
|
else |
|
{ |
|
V_sprintf_safe( szFinal, "%s", pszFilename ); |
|
} |
|
|
|
V_SetExtension( szFinal, ".tga", sizeof( szFinal ) ); |
|
|
|
videomode->TakeSnapshotTGA( szFinal ); |
|
|
|
// Restore threading if it was previously enabled (if it wasn't this will do nothing). |
|
materials->AllowThreading( bEnabled, g_nMaterialSystemThread ); |
|
|
|
if ( !bReadPixelsFromFrontBuffer ) |
|
{ |
|
Shader_SwapBuffers(); |
|
} |
|
}
|
|
|