//====== Copyright c 1996-2008, Valve Corporation, All rights reserved. =======// // // Purpose: Exposing command console for scripting // // #include #include #include "valve_ipc_win32.h" #include "tier0/dbg.h" #include "tier0/platform.h" #include "mathlib/mathlib.h" #include "tier1/convar.h" #include "UtlStringMap.h" #include "con_nprint.h" #include "cdll_int.h" #include "globalvars_base.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" extern IVEngineClient *engineClient; extern CGlobalVarsBase *gpGlobals; ////////////////////////////////////////////////////////////////////////// // // Definition of CValveIpcServerUtl // class CValveIpcServerUtl : public CValveIpcServer { public: explicit CValveIpcServerUtl( char const *szServerName ) : CValveIpcServer( szServerName ) {} virtual BOOL ExecuteCommand( char *bufCommand, DWORD numCommandBytes, char *bufResult, DWORD &numResultBytes ) { CUtlBuffer cmd( bufCommand, numCommandBytes, CUtlBuffer::READ_ONLY ); CUtlBuffer res( bufResult, VALVE_IPC_CS_BUFFER, int( 0 ) ); if ( !ExecuteCommand( cmd, res ) ) return FALSE; numResultBytes = res.TellPut(); return TRUE; } virtual BOOL ExecuteCommand( CUtlBuffer &cmd, CUtlBuffer &res ) = 0; }; ////////////////////////////////////////////////////////////////////////// // // Class encapsulating a single ipc console // class CIpcConsoleImpl : public CValveIpcServerUtl { public: explicit CIpcConsoleImpl( char const *szName ); virtual BOOL ExecuteCommand( CUtlBuffer &cmd, CUtlBuffer &res ); }; CIpcConsoleImpl::CIpcConsoleImpl( char const *szName ) : CValveIpcServerUtl( szName ) { } BOOL CIpcConsoleImpl::ExecuteCommand( CUtlBuffer &cmd, CUtlBuffer &res ) { extern ConVar sv_cheats; if ( !sv_cheats.GetBool() ) { res.PutString( "ERROR: Engine IPC communication requires sv_cheats 1!\n" ); res.PutInt( 0 ); return TRUE; } // NOTE: ExecuteCommand is called on a separate thread! engineClient->ClientCmd( ( char const * ) cmd.Base() ); res.PutInt( 0 ); return TRUE; } ////////////////////////////////////////////////////////////////////////// // // Class encapsulating management of ipc consoles // class CIpcConsoleMgr { public: bool Enable( char const *szConsoleName ); bool Disable( char const *szConsoleName ); void DisableAll(); void Show( char const *szConsoleName ); void ShowAll(); protected: CIpcConsoleImpl *FindConsole( char const *szConsoleName ); CIpcConsoleImpl *CreateConsole( char const *szConsoleName ); bool RemoveConsole( CIpcConsoleImpl *pConsole ); protected: CUtlStringMap< CIpcConsoleImpl * > m_mapConsoles; }; static CIpcConsoleMgr &IpcConsoleGetMgr() { static CIpcConsoleMgr s_mgr; return s_mgr; } static char const *IpcConsoleGetDefaultName() { return "ENGINE_IPC_SERVER"; } bool CIpcConsoleMgr::Enable( char const *szConsoleName ) { CIpcConsoleImpl *pConsole = FindConsole( szConsoleName ); if ( !pConsole ) pConsole = CreateConsole( szConsoleName ); if ( pConsole->EnsureRegisteredAndRunning() ) { Msg( "IPC: enabled console \"%s\"\n", szConsoleName ); return true; } RemoveConsole( pConsole ); Error( "IPC: Failed to enable console \"%s\"\n", szConsoleName ); return false; } bool CIpcConsoleMgr::Disable( const char *szConsoleName ) { CIpcConsoleImpl *pConsole = FindConsole( szConsoleName ); if ( !pConsole ) { Msg( "IPC: disabling unknown console \"%s\"\n", szConsoleName ); return false; } pConsole->EnsureStoppedAndUnregistered(); RemoveConsole( pConsole ); Msg( "IPC: disabled console \"%s\"\n", szConsoleName ); return true; } void CIpcConsoleMgr::DisableAll() { int numActiveConsoles = 0; for ( int idx = 0; idx < m_mapConsoles.GetNumStrings(); ++ idx ) { char const *szConsoleName = m_mapConsoles.String( idx ); CIpcConsoleImpl *&pConsole = m_mapConsoles[ szConsoleName ]; if ( !pConsole ) continue; pConsole->EnsureStoppedAndUnregistered(); delete pConsole; pConsole = NULL; Msg( "IPC: disabled console \"%s\"\n", szConsoleName ); ++ numActiveConsoles; } Msg( "IPC: disabled %d console(s).\n", numActiveConsoles ); } void CIpcConsoleMgr::Show( const char *szConsoleName ) { CIpcConsoleImpl *pConsole = FindConsole( szConsoleName ); if ( pConsole ) { Msg( "IPC: Active console \"%s\"\n", szConsoleName ); } else { Msg( "IPC: Unknown console \"%s\"\n", szConsoleName ); } } void CIpcConsoleMgr::ShowAll() { int numActiveConsoles = 0; for ( int idx = 0; idx < m_mapConsoles.GetNumStrings(); ++ idx ) { char const *szConsoleName = m_mapConsoles.String( idx ); CIpcConsoleImpl *pConsole = m_mapConsoles[ szConsoleName ]; if ( !pConsole ) continue; Msg( "IPC: Active console \"%s\"\n", szConsoleName ); ++ numActiveConsoles; } Msg( "IPC: %d active console(s).\n", numActiveConsoles ); } CIpcConsoleImpl * CIpcConsoleMgr::FindConsole( char const *szConsoleName ) { if ( m_mapConsoles.Find( szConsoleName ) == m_mapConsoles.InvalidIndex() ) return NULL; CIpcConsoleImpl *&pConsole = m_mapConsoles[ szConsoleName ]; return pConsole; } CIpcConsoleImpl * CIpcConsoleMgr::CreateConsole( char const *szConsoleName ) { CIpcConsoleImpl *&pConsole = m_mapConsoles[ szConsoleName ]; pConsole = new CIpcConsoleImpl( szConsoleName ); return pConsole; } bool CIpcConsoleMgr::RemoveConsole( CIpcConsoleImpl *pConsoleRemove ) { if ( !pConsoleRemove ) return false; for ( int idx = 0; idx < m_mapConsoles.GetNumStrings(); ++ idx ) { char const *szConsoleName = m_mapConsoles.String( idx ); CIpcConsoleImpl *&pConsole = m_mapConsoles[ szConsoleName ]; if ( pConsole != pConsoleRemove ) continue; delete pConsole; pConsole = NULL; return true; } return false; } ////////////////////////////////////////////////////////////////////////// // // Console commands to enable, disable and show ipc console names // CON_COMMAND_F( ipc_console_enable, "Enable IPC console", FCVAR_CHEAT | FCVAR_CLIENTCMD_CAN_EXECUTE | FCVAR_DONTRECORD ) { char const *szConsoleName = IpcConsoleGetDefaultName(); if ( args.ArgC() <= 1 ) { IpcConsoleGetMgr().Enable( szConsoleName ); return; } else for ( int k = 1; k < args.ArgC(); ++ k ) { szConsoleName = args.Arg( k ); if ( IpcConsoleGetMgr().Enable( szConsoleName ) ) return; } } CON_COMMAND_F( ipc_console_disable, "Disable IPC console(s)", FCVAR_CLIENTCMD_CAN_EXECUTE | FCVAR_DONTRECORD ) { char const *szConsoleName = IpcConsoleGetDefaultName(); if ( args.ArgC() <= 1 ) { IpcConsoleGetMgr().Disable( szConsoleName ); return; } else for ( int k = 1; k < args.ArgC(); ++ k ) { szConsoleName = args.Arg( k ); IpcConsoleGetMgr().Disable( szConsoleName ); } } CON_COMMAND_F( ipc_console_disable_all, "Disable all IPC consoles", FCVAR_CLIENTCMD_CAN_EXECUTE | FCVAR_DONTRECORD ) { IpcConsoleGetMgr().DisableAll(); } CON_COMMAND_F( ipc_console_show, "Show status of IPC consoles", FCVAR_CLIENTCMD_CAN_EXECUTE | FCVAR_DONTRECORD ) { if ( args.ArgC() <= 1 ) { IpcConsoleGetMgr().ShowAll(); return; } else for ( int k = 1; k < args.ArgC(); ++ k ) { char const *szConsoleName = args.Arg( k ); IpcConsoleGetMgr().Show( szConsoleName ); } }