//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: Implmentation of IEngineTool callback interface // Tool .dlls can call back through this interface to talk to the engine // //============================================================================= #include "ienginetoolinternal.h" #include "EngineSoundInternal.h" #include "vengineserver_impl.h" #include "cdll_engine_int.h" #include "toolframework/ienginetool.h" #include "client.h" #include "server.h" #include "con_nprint.h" #include "toolframework/itoolframework.h" #include "sound.h" #include "screen.h" #include "render.h" #include "gl_matsysiface.h" #include "cl_main.h" #include "sys_dll.h" #include "ivideomode.h" #include "voice.h" #include "filesystem_engine.h" #include "enginetrace.h" #include "Overlay.h" #include "r_efx.h" #include "r_local.h" #include "lightcache.h" #include "ispatialpartitioninternal.h" #include "networkstringtableserver.h" #include "networkstringtable.h" #include "igame.h" #include "gl_rmain.h" #ifndef DEDICATED #include "vgui_baseui_interface.h" #endif // NOTE: This has to be the last file included! #include "tier0/memdbgon.h" // External variables and APIs needed extern CSysModule *g_GameDLL; extern ConVar host_timescale; extern CGlobalVars g_ServerGlobalVariables; void SV_ForceSend(); CreateInterfaceFn ClientDLL_GetFactory( void ); extern CNetworkStringTableContainer *networkStringTableContainerServer; IOverlayMgr *OverlayMgr(); void SV_ForceSend(); extern ConVar host_framerate; void CL_StartMovie( const char *filename, int flags, int nWidth, int nHeight, float flFrameRate, int jpeg_quality ); void CL_EndMovie(); bool CL_IsRecordingMovie(); void VGui_SetGameDLLPanelsVisible( bool show ); float AudioSource_GetSoundDuration( char const *pName ); //----------------------------------------------------------------------------- // Purpose: Singleton implementation of external tools callback interface //----------------------------------------------------------------------------- class CEngineTool : public IEngineToolInternal { public: CEngineTool(); // Methods of IEngineToolFramework // Take over input virtual void ShowCursor( bool show ); virtual bool IsCursorVisible() const; // Helpers for implementing a tool switching UI virtual int GetToolCount() const; virtual const char *GetToolName( int index ) const; virtual void SwitchToTool( int index ); virtual bool IsTopmostTool( const IToolSystem *sys ) const; virtual const IToolSystem *GetToolSystem( int index ) const; virtual IToolSystem *GetTopmostTool(); // If module not already loaded, loads it and optionally switches to first tool in module. Returns false if load failed or tool already loaded virtual bool LoadToolModule( char const *pToolModule, bool bSwitchToFirst ); public: // Retrieve factories from server.dll and client.dll to get at specific interfaces defined within virtual void GetServerFactory( CreateInterfaceFn& factory ); virtual void GetClientFactory( CreateInterfaceFn& factory ); // Issue a console command virtual void Command( const char *cmd ); // Flush console command buffer right away virtual void Execute(); // If in a level, get name of current level virtual const char *GetCurrentMap(); virtual void ChangeToMap( const char *mapname ); virtual bool IsMapValid( const char *mapname ); // Method for causing engine to call client to render scene with no view model or overlays virtual void RenderView( CViewSetup &view, int nFlags, int nWhatToRender ); // Returns true if the player is fully connected and active in game (i.e, not still loading) virtual bool IsInGame(); // Returns true if the player is connected, but not necessarily active in game (could still be loading) virtual bool IsConnected(); virtual int GetMaxClients(); // Tools might want to ensure single player, e.g. virtual bool IsGamePaused(); virtual void SetGamePaused( bool paused ); virtual float GetTimescale(); // host_timescale ConVar multiplied by the game timescale virtual void SetTimescale( float scale ); // Real time is unscaled, but is updated once per frame virtual float GetRealTime(); virtual float GetRealFrameTime(); // unscaled virtual float Time(); // Get high precision timer (for profiling?) // Host time is scaled virtual float HostFrameTime(); // host_frametime virtual float HostTime(); // host_time virtual int HostTick(); // host_tickcount virtual int HostFrameCount(); // total famecount virtual float ServerTime(); // gpGlobals->curtime on server virtual float ServerFrameTime(); // gpGlobals->frametime on server virtual int ServerTick(); // gpGlobals->tickcount on server virtual float ServerTickInterval(); // tick interval on server virtual float ClientTime(); // gpGlobals->curtime on client virtual float ClientFrameTime(); // gpGlobals->frametime on client virtual int ClientTick(); // gpGlobals->tickcount on client virtual void SetClientFrameTime( float frametime ); // gpGlobals->frametime on client // Currently the engine doesn't like to do networking when it's paused, but if a tool changes entity state, it can be useful to force // a network update to get that state over to the client virtual void ForceUpdateDuringPause(); // Maybe through modelcache??? virtual model_t *GetModel( HTOOLHANDLE hEntity ); // Get the .mdl file used by entity (if it's a cbaseanimating) virtual studiohdr_t *GetStudioModel( HTOOLHANDLE hEntity ); // SINGLE PLAYER/LISTEN SERVER ONLY (just matching the client .dll api for this) // Prints the formatted string to the notification area of the screen ( down the right hand edge // numbered lines starting at position 0 virtual void Con_NPrintf( int pos, const char *fmt, ... ); // SINGLE PLAYER/LISTEN SERVER ONLY(just matching the client .dll api for this) // Similar to Con_NPrintf, but allows specifying custom text color and duration information virtual void Con_NXPrintf( const struct con_nprint_s *info, const char *fmt, ... ); // Get the current game directory (hl2, tf2, hl1, cstrike, etc.) virtual void GetGameDir( char *szGetGameDir, int maxlength ); // Do we need separate rects for the 3d "viewport" vs. the tools surface??? and can we control viewports from virtual void GetScreenSize( int& width, int &height ); virtual int StartSound( int iUserData, bool staticsound, int iEntIndex, int iChannel, const char *pSample, float flVolume, soundlevel_t iSoundlevel, const Vector& origin, const Vector& direction, int iFlags = 0, int iPitch = PITCH_NORM, bool bUpdatePositions = true, float delay = 0.0f, int speakerentity = -1 ); virtual void StopSoundByGuid( int guid ); virtual void SetVolumeByGuid( int guid, float flVolume ); virtual bool IsSoundStillPlaying( int guid ); virtual bool GetSoundChannelVolume( const char* sound, float &flVolumeLeft, float &flVolumeRight ) { return false; } virtual float GetSoundDuration( int guid ); virtual void ReloadSound( const char *pSample ); virtual void StopAllSounds( ); virtual void SetAudioState( const AudioState_t &audioState ); virtual void SetMainView( const Vector &vecOrigin, const QAngle &angles ); virtual bool GetPlayerView( CViewSetup &playerView, int x, int y, int w, int h ); virtual void CreatePickingRay( const CViewSetup &viewSetup, int x, int y, Vector& org, Vector& forward ); virtual bool IsLoopingSound( int guid ); virtual void InstallQuitHandler( void *pvUserData, FnQuitHandler func ); virtual void TakeTGAScreenShot( const char *filename, int width, int height ); // Even if game is paused, force networking to update to get new server state down to client virtual void ForceSend(); virtual bool IsRecordingMovie(); // NOTE: Params can contain file name, frame rate, output avi, output raw, and duration virtual void StartMovieRecording( KeyValues *pMovieParams ); virtual void EndMovieRecording(); virtual void CancelMovieRecording(); virtual AVIHandle_t GetRecordingAVIHandle(); virtual void StartRecordingVoiceToFile( const char *filename, const char *pPathID = 0 ); virtual void StopRecordingVoiceToFile(); virtual bool IsVoiceRecording(); virtual void TraceRay( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, CBaseTrace *pTrace ); virtual void TraceRayServer( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, CBaseTrace *pTrace ); bool CanQuit(); void UpdateScreenshot(); bool ShouldSuppressDeInit() const; virtual bool IsConsoleVisible(); virtual int GetPointContents( const Vector &vecPosition ); virtual int GetActiveDLights( dlight_t *pList[MAX_DLIGHTS] ); virtual int GetLightingConditions( const Vector &vecPosition, Vector *pColors, int nMaxLocalLights, LightDesc_t *pLocalLights ); // precache methods virtual bool PrecacheSound( const char *pName, bool bPreload = false ); virtual bool PrecacheModel( const char *pName, bool bPreload = false ); virtual float GetMono16Samples( const char *pszName, CUtlVector< short >& sampleList ); virtual void GetWorldToScreenMatrixForView( const CViewSetup &view, VMatrix *pVMatrix ); virtual SpatialPartitionHandle_t CreatePartitionHandle( IHandleEntity *pEntity, SpatialPartitionListMask_t listMask, const Vector& mins, const Vector& maxs ); virtual void DestroyPartitionHandle( SpatialPartitionHandle_t hPartition ); virtual void InstallPartitionQueryCallback( IPartitionQueryCallback *pQuery ); virtual void RemovePartitionQueryCallback( IPartitionQueryCallback *pQuery ); virtual void ElementMoved( SpatialPartitionHandle_t handle, const Vector& mins, const Vector& maxs ); virtual float GetSoundDuration( const char *pszName ); virtual void ValidateSoundCache( char const *pchSoundName ); virtual void PrefetchSound( char const *pchSoundName ); virtual void* GetEngineHwnd(); virtual void OnModeChanged( bool bGameMode ); public: // Methods of IEngineToolInternal virtual void SetIsInGame( bool bIsInGame ); virtual float GetSoundElapsedTime( int guid ); virtual bool GetPreventSound( void ); private: bool m_bIsInGame; struct QuitHandler_t { void *userdata; FnQuitHandler func; }; CUtlVector< QuitHandler_t > m_QuitHandlers; char m_szScreenshotFile[ MAX_OSPATH ]; int m_nScreenshotWidth; int m_nScreenshotHeight; bool m_bRecordingMovie; bool m_bSuppressDeInit; char m_szVoiceoverFile[ MAX_OSPATH ]; }; //----------------------------------------------------------------------------- // Singleton //----------------------------------------------------------------------------- static CEngineTool g_EngineTool; IEngineToolInternal *g_pEngineToolInternal = &g_EngineTool; void EngineTool_InstallQuitHandler( void *pvUserData, FnQuitHandler func ) { g_EngineTool.InstallQuitHandler( pvUserData, func ); } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool EngineTool_CheckQuitHandlers() { return g_EngineTool.CanQuit(); } void EngineTool_UpdateScreenshot() { g_EngineTool.UpdateScreenshot(); } //----------------------------------------------------------------------------- // Constructor //----------------------------------------------------------------------------- CEngineTool::CEngineTool() { m_bIsInGame = false; m_szScreenshotFile[ 0 ] = 0; m_nScreenshotWidth = 180; m_nScreenshotHeight = 100; m_bRecordingMovie = false; m_bSuppressDeInit = false; m_szVoiceoverFile[ 0 ] = 0; } //----------------------------------------------------------------------------- // Singleton //----------------------------------------------------------------------------- void CEngineTool::ShowCursor( bool show ) { Assert( 0 ); } bool CEngineTool::IsCursorVisible() const { Assert( 0 ); return true; } int CEngineTool::GetPointContents( const Vector &vecPosition ) { return g_pEngineTraceClient->GetPointContents( vecPosition, NULL ); } int CEngineTool::GetActiveDLights( dlight_t *pList[MAX_DLIGHTS] ) { return g_pEfx->CL_GetActiveDLights( pList ); } bool WorldLightToMaterialLight( dworldlight_t* pWorldLight, LightDesc_t& light ); int CEngineTool::GetLightingConditions( const Vector &vecLightingOrigin, Vector *pColors, int nMaxLocalLights, LightDesc_t *pLocalLights ) { LightcacheGetDynamic_Stats stats; LightingState_t state; LightcacheGetDynamic( vecLightingOrigin, state, stats, NULL ); Assert( state.numlights >= 0 && state.numlights < MAXLOCALLIGHTS ); memcpy( pColors, state.r_boxcolor, sizeof(state.r_boxcolor) ); int nLightCount = 0; for ( int i = 0; i < state.numlights; ++i ) { LightDesc_t *pLightDesc = &pLocalLights[nLightCount]; if (!WorldLightToMaterialLight( state.locallight[i], *pLightDesc )) continue; // Apply lightstyle float bias = LightStyleValue( state.locallight[i]->style ); // Deal with overbrighting + bias pLightDesc->m_Color[0] *= bias; pLightDesc->m_Color[1] *= bias; pLightDesc->m_Color[2] *= bias; if ( ++nLightCount >= nMaxLocalLights ) break; } return nLightCount; } void CEngineTool::GetServerFactory( CreateInterfaceFn& factory ) { factory = Sys_GetFactory( g_GameDLL ); } void CEngineTool::GetClientFactory( CreateInterfaceFn& factory ) { factory = ClientDLL_GetFactory(); } void CEngineTool::Command( const char *cmd ) { Cbuf_AddText( Cbuf_GetCurrentPlayer(), cmd ); } void CEngineTool::Execute() { Cbuf_Execute(); } const char *CEngineTool::GetCurrentMap() { if ( sv.IsDedicated() ) return "Dedicated Server"; if ( !GetBaseLocalClient().IsConnected() ) { if ( sv.IsLoading() ) return sv.GetMapName(); return ""; } return GetBaseLocalClient().m_szLevelName; } void CEngineTool::ChangeToMap( const char *mapname ) { if ( modelloader->Map_IsValid( mapname ) ) { Cbuf_AddText( Cbuf_GetCurrentPlayer(), va( "map \"%s\"\n", mapname ) ); } } bool CEngineTool::IsMapValid( const char *mapname ) { return modelloader->Map_IsValid( mapname ); } // Allows tools to kick off rendering by having the engine call the client void CEngineTool::RenderView( CViewSetup &view, int nFlags, int whatToRender ) { // Call client ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 ); g_ClientDLL->RenderView( view, nFlags, whatToRender ); } void CEngineTool::SetIsInGame( bool bIsInGame ) { m_bIsInGame = bIsInGame; } bool CEngineTool::IsInGame() { return m_bIsInGame && GetBaseLocalClient().IsConnected(); } bool CEngineTool::IsConnected() { return GetBaseLocalClient().IsConnected(); } int CEngineTool::GetMaxClients() { return GetBaseLocalClient().m_nMaxClients; } bool CEngineTool::IsGamePaused() { return GetBaseLocalClient().IsPaused(); } bool CEngineTool::IsConsoleVisible() { #ifdef DEDICATED return false; #else return EngineVGui()->IsConsoleVisible(); #endif } void CEngineTool::SetGamePaused( bool paused ) { sv.SetPaused( paused ); } float CEngineTool::GetTimescale() { return host_timescale.GetFloat() * sv.GetTimescale(); } void CEngineTool::SetTimescale( float scale ) { host_timescale.SetValue( scale ); } float CEngineTool::Time() { return Plat_FloatTime(); } // Real time is unscaled, but is updated once per frame float CEngineTool::GetRealTime() { return realtime; } float CEngineTool::GetRealFrameTime() { return host_frametime_unscaled; } float CEngineTool::HostFrameTime() { return host_frametime; } float CEngineTool::HostTime() { return host_time; } int CEngineTool::HostTick() { return host_tickcount; } int CEngineTool::HostFrameCount() { return host_framecount; } float CEngineTool::ServerTime() { return g_ServerGlobalVariables.curtime; } float CEngineTool::ServerFrameTime() { return g_ServerGlobalVariables.frametime; } int CEngineTool::ServerTick() { return g_ServerGlobalVariables.tickcount; } float CEngineTool::ServerTickInterval() { return g_ServerGlobalVariables.interval_per_tick; } float CEngineTool::ClientTime() { return g_ClientGlobalVariables.curtime; } float CEngineTool::ClientFrameTime() { return g_ClientGlobalVariables.frametime; } int CEngineTool::ClientTick() { return g_ClientGlobalVariables.tickcount; } void CEngineTool::SetClientFrameTime( float frametime ) { g_ClientGlobalVariables.frametime = frametime; } void CEngineTool::ForceUpdateDuringPause() { SV_ForceSend(); } model_t *CEngineTool::GetModel( HTOOLHANDLE hEntity ) { Assert( 0 ); return NULL; } studiohdr_t *CEngineTool::GetStudioModel( HTOOLHANDLE hEntity ) { Assert( 0 ); return NULL; } void CEngineTool::Con_NPrintf( int pos, const char *fmt, ... ) { char buf[ 1024 ]; va_list argptr; va_start( argptr, fmt ); _vsnprintf( buf, sizeof( buf ) - 1, fmt, argptr ); va_end( argptr ); return ::Con_NPrintf( pos, "%s", buf ); } void CEngineTool::Con_NXPrintf( const struct con_nprint_s *info, const char *fmt, ... ) { char buf[ 1024 ]; va_list argptr; va_start( argptr, fmt ); _vsnprintf( buf, sizeof( buf ) - 1, fmt, argptr ); va_end( argptr ); ::Con_NXPrintf( info, "%s", buf ); } void CEngineTool::GetGameDir( char *szGetGameDir, int maxlength ) { Q_strncpy( szGetGameDir, com_gamedir, maxlength ); } void CEngineTool::GetScreenSize( int& width, int &height ) { CMatRenderContextPtr pRenderContext( materials ); pRenderContext->GetWindowSize( width, height ); } //----------------------------------------------------------------------------- // Purpose: Helpers for implementing a tool switching UI // Input : - // Output : int //----------------------------------------------------------------------------- int CEngineTool::GetToolCount() const { return toolframework->GetToolCount(); } //----------------------------------------------------------------------------- // Purpose: // Input : index - // Output : char //----------------------------------------------------------------------------- const char *CEngineTool::GetToolName( int index ) const { return toolframework->GetToolName( index ); } //----------------------------------------------------------------------------- // Purpose: // Input : index - //----------------------------------------------------------------------------- void CEngineTool::SwitchToTool( int index ) { toolframework->SwitchToTool( index ); } bool CEngineTool::IsTopmostTool( const IToolSystem *sys ) const { return toolframework->IsTopmostTool( sys ); } IToolSystem *CEngineTool::GetTopmostTool() { return toolframework->GetTopmostTool(); } const IToolSystem *CEngineTool::GetToolSystem( int index ) const { return toolframework->GetToolSystem( index ); } // If module not already loaded, loads it and optionally switches to first tool in module. Returns false if load failed or tool already loaded bool CEngineTool::LoadToolModule( char const *pToolModule, bool bSwitchToFirst ) { return toolframework->LoadToolModule( pToolModule, bSwitchToFirst ); } void CEngineTool::ValidateSoundCache( char const *pchSoundName ) { S_ValidateSoundCache( pchSoundName ); } void CEngineTool::PrefetchSound( char const *pchSoundName ) { S_PrefetchSound( pchSoundName, false ); } int CEngineTool::StartSound( int iUserData, bool staticsound, int iEntIndex, int iChannel, const char *pSample, float flVolume, soundlevel_t iSoundlevel, const Vector& origin, const Vector& direction, int iFlags /*= 0*/, int iPitch /*= PITCH_NORM*/, bool bUpdatePositions /*= true*/, float delay /*= 0.0f*/, int speakerentity /*= -1*/ ) { StartSoundParams_t params; params.userdata = iUserData; params.staticsound = staticsound; params.soundsource = iEntIndex; params.entchannel = iChannel; params.pSfx = S_PrecacheSound( pSample ); params.origin = origin; params.direction = direction; params.bUpdatePositions = bUpdatePositions; params.fvol = flVolume; params.soundlevel = iSoundlevel; params.flags = iFlags; params.pitch = iPitch; params.fromserver = false; params.delay = delay; params.speakerentity = speakerentity; params.bToolSound = true; int guid = S_StartSound( params ); return guid; } void CEngineTool::StopSoundByGuid( int guid ) { S_StopSoundByGuid( guid ); } void CEngineTool::SetVolumeByGuid( int guid, float flVolume ) { S_SetVolumeByGuid( guid, flVolume ); } bool CEngineTool::IsSoundStillPlaying( int guid ) { return S_IsSoundStillPlaying( guid ); } float CEngineTool::GetSoundDuration( int guid ) { return S_SoundDurationByGuid( guid ); } float CEngineTool::GetSoundElapsedTime( int guid ) { return S_GetElapsedTimeByGuid( guid ); } void* CEngineTool::GetEngineHwnd() { return game->GetMainWindow(); } float CEngineTool::GetSoundDuration( const char *pszName ) { return AudioSource_GetSoundDuration( pszName ); } void CEngineTool::ReloadSound( const char *pSample ) { S_ReloadSound( pSample ); } void CEngineTool::StopAllSounds( ) { S_StopAllSounds( true ); } bool CEngineTool::GetPreventSound( ) { return S_GetPreventSound( ); } // Returns if the sound is looping bool CEngineTool::IsLoopingSound( int guid ) { return S_IsLoopingSoundByGuid( guid ); } void CEngineTool::TraceRay( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, CBaseTrace *pTrace ) { trace_t tempTrace; g_pEngineTraceClient->TraceRay( ray, fMask, pTraceFilter, &tempTrace ); memcpy( pTrace, &tempTrace, sizeof ( CBaseTrace ) ); } void CEngineTool::TraceRayServer( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, CBaseTrace *pTrace ) { trace_t tempTrace; g_pEngineTraceServer->TraceRay( ray, fMask, pTraceFilter, &tempTrace ); memcpy( pTrace, &tempTrace, sizeof ( CBaseTrace ) ); } void CEngineTool::SetAudioState( const AudioState_t &audioState ) { Host_SetAudioState( audioState ); } // Sets the location of the main view void CEngineTool::SetMainView( const Vector &vecOrigin, const QAngle &angles ) { g_EngineRenderer->SetMainView( vecOrigin, angles ); } static float ScaleFOVByWidthRatio( float fovDegrees, float ratio ) { float halfAngleRadians = fovDegrees * ( 0.5f * M_PI / 180.0f ); float t = tan( halfAngleRadians ); t *= ratio; float retDegrees = ( 180.0f / M_PI ) * atan( t ); return retDegrees * 2.0f; } // Gets the player view bool CEngineTool::GetPlayerView( CViewSetup &viewSetup, int x, int y, int w, int h ) { if ( g_ClientDLL ) { if ( !g_ClientDLL->GetPlayerView( viewSetup ) ) return false; // Initialize view setup given the desired rectangle viewSetup.x = x; viewSetup.y = y; viewSetup.width = w; viewSetup.height = h; viewSetup.m_flAspectRatio = (viewSetup.height != 0) ? (float)viewSetup.width / (float)viewSetup.height : 4.0f / 3.0f; viewSetup.m_bRenderToSubrectOfLargerScreen = true; viewSetup.fov = ScaleFOVByWidthRatio( viewSetup.fov, viewSetup.m_flAspectRatio / ( 4.0f / 3.0f ) ); viewSetup.fovViewmodel = ScaleFOVByWidthRatio( viewSetup.fovViewmodel, viewSetup.m_flAspectRatio / ( 4.0f / 3.0f ) ); return true; } return false; } //----------------------------------------------------------------------------- // From a location on the screen, figure out the vector into the world //----------------------------------------------------------------------------- void CEngineTool::CreatePickingRay( const CViewSetup &viewSetup, int x, int y, Vector& org, Vector& forward ) { // Remap x and y into -1 to 1 normalized space float xf, yf; xf = ( 2.0f * (float)x / (float)viewSetup.width ) - 1.0f; yf = ( 2.0f * (float)y / (float)viewSetup.height ) - 1.0f; // Flip y axis yf = -yf; VMatrix worldToScreen; GetWorldToScreenMatrixForView( viewSetup, &worldToScreen ); VMatrix screenToWorld; MatrixInverseGeneral( worldToScreen, screenToWorld ); // Create two points at the normalized mouse x, y pos and at the near and far z planes (0 and 1 depth) Vector v1, v2; v1.Init( xf, yf, 0.0f ); v2.Init( xf, yf, 1.0f ); Vector o2; // Transform the two points by the screen to world matrix screenToWorld.V3Mul( v1, org ); // ray start origin screenToWorld.V3Mul( v2, o2 ); // ray end origin VectorSubtract( o2, org, forward ); forward.NormalizeInPlace(); } //----------------------------------------------------------------------------- // Purpose: Returns true if all handlers say we can quit the engine //----------------------------------------------------------------------------- bool CEngineTool::CanQuit() { int c = m_QuitHandlers.Count(); for ( int i = 0; i < c; ++i ) { QuitHandler_t& qh = m_QuitHandlers[ i ]; FnQuitHandler func = qh.func; if ( func ) { if ( !func( qh.userdata ) ) { return false; } } } return true; } void CEngineTool::InstallQuitHandler( void *pvUserData, FnQuitHandler func ) { QuitHandler_t qh; qh.userdata = pvUserData; qh.func = func; m_QuitHandlers.AddToTail( qh ); } // precache methods bool CEngineTool::PrecacheSound( const char *pName, bool bPreload ) { if ( pName && TestSoundChar( pName, CHAR_SENTENCE ) ) return true; bool bState = networkStringTableContainerServer->Lock( false ); int flags = bPreload ? RES_PRELOAD : 0; int i = sv.PrecacheSound( pName, flags ); networkStringTableContainerServer->Lock( bState ); return i >= 0; } bool CEngineTool::PrecacheModel( const char *pName, bool bPreload ) { int flags = bPreload ? RES_PRELOAD : 0; bool bState = networkStringTableContainerServer->Lock( false ); int i = sv.PrecacheModel( pName, flags ); networkStringTableContainerServer->Lock( bState ); return i >= 0; } void CEngineTool::TakeTGAScreenShot( const char *filename, int width, int height ) { Q_strncpy( m_szScreenshotFile, filename, sizeof( m_szScreenshotFile ) ); m_nScreenshotWidth = width; m_nScreenshotHeight = height; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CEngineTool::UpdateScreenshot() { if ( g_LostVideoMemory ) return; if ( m_szScreenshotFile[0] ) { g_ClientDLL->WriteSaveGameScreenshotOfSize( m_szScreenshotFile, m_nScreenshotWidth, m_nScreenshotHeight ); m_szScreenshotFile[0] = 0; } } // Even if game is paused, force networking to update to get new server state down to client void CEngineTool::ForceSend() { SV_ForceSend(); } bool CEngineTool::IsRecordingMovie() { if ( m_bRecordingMovie ) { Assert( CL_IsRecordingMovie() ); return true; } return false; } // NOTE: Params can contain file name, frame rate, output avi, output raw, and duration void CEngineTool::StartMovieRecording( KeyValues *pMovieParams ) { if ( CL_IsRecordingMovie() ) { Warning( "Can't record movie, already recording!!!\n" ); return; } if ( m_bRecordingMovie ) return; int jpeg_quality = DEFAULT_JPEG_QUALITY; int flags = 0; if ( pMovieParams->GetInt( "outputavi", 0 ) ) { if ( pMovieParams->GetInt( "avisoundonly", 0 ) ) { flags |= MovieInfo_t::FMOVIE_AVISOUND; } else { flags |= MovieInfo_t::FMOVIE_AVI | MovieInfo_t::FMOVIE_AVISOUND; } } if ( pMovieParams->GetInt( "outputtga", 0 ) ) { flags |= MovieInfo_t::FMOVIE_TGA; } if ( pMovieParams->GetInt( "outputjpg", 0 ) ) { flags |= MovieInfo_t::FMOVIE_JPG; jpeg_quality = pMovieParams->GetInt( "jpeg_quality" ); } if ( pMovieParams->GetInt( "outputwav", 0 ) ) { flags |= MovieInfo_t::FMOVIE_WAV; } const char *pFileName = pMovieParams->GetString( "filename", NULL ); if ( !pFileName ) { Warning( "Output filename not specified!\n" ); return; } int nWidth = pMovieParams->GetInt( "width", videomode->GetModeWidth() ); int nHeight = pMovieParams->GetInt( "height", videomode->GetModeHeight() ); float flFrameRate = pMovieParams->GetFloat( "framerate", 30.0f ); m_bRecordingMovie = true; CL_StartMovie( pFileName, flags, nWidth, nHeight, flFrameRate, jpeg_quality ); } void CEngineTool::EndMovieRecording() { if ( !m_bRecordingMovie ) return; CL_EndMovie(); m_bRecordingMovie = false; } void CEngineTool::CancelMovieRecording() { EndMovieRecording(); } AVIHandle_t CEngineTool::GetRecordingAVIHandle() { if ( !CL_IsRecordingMovie() ) return AVIHANDLE_INVALID; return g_hCurrentAVI; } bool CEngineTool::ShouldSuppressDeInit() const { return m_bSuppressDeInit; } void CEngineTool::StartRecordingVoiceToFile( const char *filename, const char *pPathID /*= 0*/ ) { FileHandle_t fh = g_pFileSystem->Open( filename, "wb", pPathID ); if ( fh != FILESYSTEM_INVALID_HANDLE ) { byte foo = 'b'; g_pFileSystem->Write( &foo, 1, fh ); g_pFileSystem->Close( fh ); } g_pFileSystem->RelativePathToFullPath( filename, pPathID, m_szVoiceoverFile, sizeof( m_szVoiceoverFile ) ); g_pFileSystem->RemoveFile( filename, pPathID ); #if !defined( NO_VOICE ) if ( IsVoiceRecording() ) { Voice_RecordStop(); } m_bSuppressDeInit = true; Voice_ForceInit(); Voice_RecordStart( m_szVoiceoverFile, NULL, NULL); #endif } void CEngineTool::StopRecordingVoiceToFile() { #if !defined( NO_VOICE ) Voice_RecordStop(); m_bSuppressDeInit = false; #endif } float CEngineTool::GetMono16Samples( const char *pszName, CUtlVector< short >& sampleList ) { return S_GetMono16Samples( pszName, sampleList ); } void CEngineTool::GetWorldToScreenMatrixForView( const CViewSetup &view, VMatrix *pVMatrix ) { VMatrix worldToView, viewToProjection; view.ComputeViewMatrices( &worldToView, &viewToProjection, pVMatrix ); } SpatialPartitionHandle_t CEngineTool::CreatePartitionHandle( IHandleEntity *pEntity, SpatialPartitionListMask_t listMask, const Vector& mins, const Vector& maxs ) { return SpatialPartition()->CreateHandle( pEntity, listMask, mins, maxs ); } void CEngineTool::DestroyPartitionHandle( SpatialPartitionHandle_t hPartition ) { SpatialPartition()->DestroyHandle( hPartition ); } void CEngineTool::InstallPartitionQueryCallback( IPartitionQueryCallback *pQuery ) { SpatialPartition()->InstallQueryCallback( pQuery ); } void CEngineTool::RemovePartitionQueryCallback( IPartitionQueryCallback *pQuery ) { SpatialPartition()->RemoveQueryCallback( pQuery ); } void CEngineTool::ElementMoved( SpatialPartitionHandle_t handle, const Vector& mins, const Vector& maxs ) { SpatialPartition()->ElementMoved( handle, mins, maxs ); } bool CEngineTool::IsVoiceRecording() { #if !defined( NO_VOICE ) return Voice_IsRecording(); #else return false; #endif } void CEngineTool::OnModeChanged( bool bGameMode ) { EngineVGui()->OnToolModeChanged( bGameMode ); } bool EngineTool_SuppressDeInit() { return g_EngineTool.ShouldSuppressDeInit(); } void EngineTool_OverrideSampleRate( int& rate ) { if ( EngineTool_SuppressDeInit() ) { rate = 11025; } } // Expose complex interface EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineTool, IEngineTool, VENGINETOOL_INTERFACE_VERSION, g_EngineTool ); // Expose simple interface EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineTool, IEngineToolFramework, VENGINETOOLFRAMEWORK_INTERFACE_VERSION, g_EngineTool );