//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #include <stdio.h> #include "interface.h" #include "filesystem.h" #include "engine/iserverplugin.h" #include "dlls/iplayerinfo.h" #include "eiface.h" #include "igameevents.h" #include "convar.h" #include "Color.h" #include "vstdlib/random.h" #include "engine/IEngineTrace.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" // Interfaces from the engine IVEngineServer *engine = NULL; // helper functions (messaging clients, loading content, making entities, running commands, etc) IFileSystem *filesystem = NULL; // file I/O IGameEventManager *gameeventmanager = NULL; // game events interface IPlayerInfoManager *playerinfomanager = NULL; // game dll interface to interact with players IBotManager *botmanager = NULL; // game dll interface to interact with bots IServerPluginHelpers *helpers = NULL; // special 3rd party plugin helpers from the engine IUniformRandomStream *randomStr = NULL; IEngineTrace *enginetrace = NULL; CGlobalVars *gpGlobals = NULL; // function to initialize any cvars/command in this plugin void InitCVars( CreateInterfaceFn cvarFactory ); void Bot_RunAll( void ); // useful helper func inline bool FStrEq(const char *sz1, const char *sz2) { return(Q_stricmp(sz1, sz2) == 0); } //--------------------------------------------------------------------------------- // Purpose: a sample 3rd party plugin class //--------------------------------------------------------------------------------- class CEmptyServerPlugin: public IServerPluginCallbacks, public IGameEventListener { public: CEmptyServerPlugin(); ~CEmptyServerPlugin(); // IServerPluginCallbacks methods virtual bool Load( CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory ); virtual void Unload( void ); virtual void Pause( void ); virtual void UnPause( void ); virtual const char *GetPluginDescription( void ); virtual void LevelInit( char const *pMapName ); virtual void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ); virtual void GameFrame( bool simulating ); virtual void LevelShutdown( void ); virtual void ClientActive( edict_t *pEntity ); virtual void ClientDisconnect( edict_t *pEntity ); virtual void ClientPutInServer( edict_t *pEntity, char const *playername ); virtual void SetCommandClient( int index ); virtual void ClientSettingsChanged( edict_t *pEdict ); virtual PLUGIN_RESULT ClientConnect( bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen ); virtual PLUGIN_RESULT ClientCommand( edict_t *pEntity ); virtual PLUGIN_RESULT NetworkIDValidated( const char *pszUserName, const char *pszNetworkID ); // IGameEventListener Interface virtual void FireGameEvent( KeyValues * event ); virtual int GetCommandIndex() { return m_iClientCommandIndex; } private: int m_iClientCommandIndex; }; // // The plugin is a static singleton that is exported as an interface // CEmptyServerPlugin g_EmtpyServerPlugin; EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CEmptyServerPlugin, IServerPluginCallbacks, INTERFACEVERSION_ISERVERPLUGINCALLBACKS, g_EmtpyServerPlugin ); //--------------------------------------------------------------------------------- // Purpose: constructor/destructor //--------------------------------------------------------------------------------- CEmptyServerPlugin::CEmptyServerPlugin() { m_iClientCommandIndex = 0; } CEmptyServerPlugin::~CEmptyServerPlugin() { } //--------------------------------------------------------------------------------- // Purpose: called when the plugin is loaded, load the interface we need from the engine //--------------------------------------------------------------------------------- bool CEmptyServerPlugin::Load( CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory ) { playerinfomanager = (IPlayerInfoManager *)gameServerFactory(INTERFACEVERSION_PLAYERINFOMANAGER,NULL); if ( !playerinfomanager ) { Warning( "Unable to load playerinfomanager, ignoring\n" ); // this isn't fatal, we just won't be able to access specific player data } botmanager = (IBotManager *)gameServerFactory(INTERFACEVERSION_PLAYERBOTMANAGER, NULL); if ( !botmanager ) { Warning( "Unable to load botcontroller, ignoring\n" ); // this isn't fatal, we just won't be able to access specific bot functions } // get the interfaces we want to use if( !(engine = (IVEngineServer*)interfaceFactory(INTERFACEVERSION_VENGINESERVER, NULL)) || !(gameeventmanager = (IGameEventManager *)interfaceFactory(INTERFACEVERSION_GAMEEVENTSMANAGER,NULL)) || !(filesystem = (IFileSystem*)interfaceFactory(FILESYSTEM_INTERFACE_VERSION, NULL)) || !(helpers = (IServerPluginHelpers*)interfaceFactory(INTERFACEVERSION_ISERVERPLUGINHELPERS, NULL)) || !(enginetrace = (IEngineTrace *)interfaceFactory(INTERFACEVERSION_ENGINETRACE_SERVER,NULL)) || !(randomStr = (IUniformRandomStream *)interfaceFactory(VENGINE_SERVER_RANDOM_INTERFACE_VERSION, NULL)) ) { return false; // we require all these interface to function } if ( playerinfomanager ) { gpGlobals = playerinfomanager->GetGlobalVars(); } InitCVars( interfaceFactory ); // register any cvars we have defined MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f ); return true; } //--------------------------------------------------------------------------------- // Purpose: called when the plugin is unloaded (turned off) //--------------------------------------------------------------------------------- void CEmptyServerPlugin::Unload( void ) { gameeventmanager->RemoveListener( this ); // make sure we are unloaded from the event system } //--------------------------------------------------------------------------------- // Purpose: called when the plugin is paused (i.e should stop running but isn't unloaded) //--------------------------------------------------------------------------------- void CEmptyServerPlugin::Pause( void ) { } //--------------------------------------------------------------------------------- // Purpose: called when the plugin is unpaused (i.e should start executing again) //--------------------------------------------------------------------------------- void CEmptyServerPlugin::UnPause( void ) { } //--------------------------------------------------------------------------------- // Purpose: the name of this plugin, returned in "plugin_print" command //--------------------------------------------------------------------------------- const char *CEmptyServerPlugin::GetPluginDescription( void ) { return "Emtpy-Plugin, Valve"; } //--------------------------------------------------------------------------------- // Purpose: called on level start //--------------------------------------------------------------------------------- void CEmptyServerPlugin::LevelInit( char const *pMapName ) { Msg( "Level \"%s\" has been loaded\n", pMapName ); gameeventmanager->AddListener( this, true ); } //--------------------------------------------------------------------------------- // Purpose: called on level start, when the server is ready to accept client connections // edictCount is the number of entities in the level, clientMax is the max client count //--------------------------------------------------------------------------------- void CEmptyServerPlugin::ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) { } //--------------------------------------------------------------------------------- // Purpose: called once per server frame, do recurring work here (like checking for timeouts) //--------------------------------------------------------------------------------- void CEmptyServerPlugin::GameFrame( bool simulating ) { if ( simulating ) { Bot_RunAll(); } } //--------------------------------------------------------------------------------- // Purpose: called on level end (as the server is shutting down or going to a new map) //--------------------------------------------------------------------------------- void CEmptyServerPlugin::LevelShutdown( void ) // !!!!this can get called multiple times per map change { gameeventmanager->RemoveListener( this ); } //--------------------------------------------------------------------------------- // Purpose: called when a client spawns into a server (i.e as they begin to play) //--------------------------------------------------------------------------------- void CEmptyServerPlugin::ClientActive( edict_t *pEntity ) { } //--------------------------------------------------------------------------------- // Purpose: called when a client leaves a server (or is timed out) //--------------------------------------------------------------------------------- void CEmptyServerPlugin::ClientDisconnect( edict_t *pEntity ) { } //--------------------------------------------------------------------------------- // Purpose: called on //--------------------------------------------------------------------------------- void CEmptyServerPlugin::ClientPutInServer( edict_t *pEntity, char const *playername ) { KeyValues *kv = new KeyValues( "msg" ); kv->SetString( "title", "Hello" ); kv->SetString( "msg", "Hello there" ); kv->SetColor( "color", Color( 255, 0, 0, 255 )); kv->SetInt( "level", 5); kv->SetInt( "time", 10); helpers->CreateMessage( pEntity, DIALOG_MSG, kv, this ); kv->deleteThis(); } //--------------------------------------------------------------------------------- // Purpose: called on level start //--------------------------------------------------------------------------------- void CEmptyServerPlugin::SetCommandClient( int index ) { m_iClientCommandIndex = index; } //--------------------------------------------------------------------------------- // Purpose: called on level start //--------------------------------------------------------------------------------- void CEmptyServerPlugin::ClientSettingsChanged( edict_t *pEdict ) { if ( playerinfomanager ) { IPlayerInfo *playerinfo = playerinfomanager->GetPlayerInfo( pEdict ); const char * name = engine->GetClientConVarValue( engine->IndexOfEdict(pEdict), "name" ); if ( playerinfo && name && playerinfo->GetName() && Q_stricmp( name, playerinfo->GetName()) ) // playerinfo may be NULL if the MOD doesn't support access to player data // OR if you are accessing the player before they are fully connected { char msg[128]; Q_snprintf( msg, sizeof(msg), "Your name changed to \"%s\" (from \"%s\"\n", name, playerinfo->GetName() ); engine->ClientPrintf( pEdict, msg ); // this is the bad way to check this, the better option it to listen for the "player_changename" event in FireGameEvent() // this is here to give a real example of how to use the playerinfo interface } } } //--------------------------------------------------------------------------------- // Purpose: called when a client joins a server //--------------------------------------------------------------------------------- PLUGIN_RESULT CEmptyServerPlugin::ClientConnect( bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen ) { return PLUGIN_CONTINUE; } //--------------------------------------------------------------------------------- // Purpose: called when a client types in a command (only a subset of commands however, not CON_COMMAND's) //--------------------------------------------------------------------------------- PLUGIN_RESULT CEmptyServerPlugin::ClientCommand( edict_t *pEntity ) { const char *pcmd = engine->Cmd_Argv(0); if ( !pEntity || pEntity->IsFree() ) { return PLUGIN_CONTINUE; } if ( FStrEq( pcmd, "menu" ) ) { KeyValues *kv = new KeyValues( "menu" ); kv->SetString( "title", "You've got options, hit ESC" ); kv->SetInt( "level", 1 ); kv->SetColor( "color", Color( 255, 0, 0, 255 )); kv->SetInt( "time", 20 ); kv->SetString( "msg", "Pick an option\nOr don't." ); for( int i = 1; i < 9; i++ ) { char num[10], msg[10], cmd[10]; Q_snprintf( num, sizeof(num), "%i", i ); Q_snprintf( msg, sizeof(msg), "Option %i", i ); Q_snprintf( cmd, sizeof(cmd), "option%i", i ); KeyValues *item1 = kv->FindKey( num, true ); item1->SetString( "msg", msg ); item1->SetString( "command", cmd ); } helpers->CreateMessage( pEntity, DIALOG_MENU, kv, this ); kv->deleteThis(); return PLUGIN_STOP; // we handled this function } else if ( FStrEq( pcmd, "rich" ) ) { KeyValues *kv = new KeyValues( "menu" ); kv->SetString( "title", "A rich message" ); kv->SetInt( "level", 1 ); kv->SetInt( "time", 20 ); kv->SetString( "msg", "This is a long long long text string.\n\nIt also has line breaks." ); helpers->CreateMessage( pEntity, DIALOG_TEXT, kv, this ); kv->deleteThis(); return PLUGIN_STOP; // we handled this function } else if ( FStrEq( pcmd, "msg" ) ) { KeyValues *kv = new KeyValues( "menu" ); kv->SetString( "title", "Just a simple hello" ); kv->SetInt( "level", 1 ); kv->SetInt( "time", 20 ); helpers->CreateMessage( pEntity, DIALOG_MSG, kv, this ); kv->deleteThis(); return PLUGIN_STOP; // we handled this function } else if ( FStrEq( pcmd, "entry" ) ) { KeyValues *kv = new KeyValues( "entry" ); kv->SetString( "title", "Stuff" ); kv->SetString( "msg", "Enter something" ); kv->SetString( "command", "say" ); // anything they enter into the dialog turns into a say command kv->SetInt( "level", 1 ); kv->SetInt( "time", 20 ); helpers->CreateMessage( pEntity, DIALOG_ENTRY, kv, this ); kv->deleteThis(); return PLUGIN_STOP; // we handled this function } return PLUGIN_CONTINUE; } //--------------------------------------------------------------------------------- // Purpose: called when a client is authenticated //--------------------------------------------------------------------------------- PLUGIN_RESULT CEmptyServerPlugin::NetworkIDValidated( const char *pszUserName, const char *pszNetworkID ) { return PLUGIN_CONTINUE; } //--------------------------------------------------------------------------------- // Purpose: called when an event is fired //--------------------------------------------------------------------------------- void CEmptyServerPlugin::FireGameEvent( KeyValues * event ) { const char * name = event->GetName(); Msg( "CEmptyServerPlugin::FireGameEvent: Got event \"%s\"\n", name ); } //--------------------------------------------------------------------------------- // Purpose: an example of how to implement a new command //--------------------------------------------------------------------------------- CON_COMMAND( empty_version, "prints the version of the empty plugin" ) { Msg( "Version:1.0.0.0\n" ); } CON_COMMAND( empty_log, "logs the version of the empty plugin" ) { engine->LogPrint( "Version:1.0.0.0\n" ); } //--------------------------------------------------------------------------------- // Purpose: an example cvar //--------------------------------------------------------------------------------- static ConVar empty_cvar("plugin_empty", "0", 0, "Example plugin cvar");
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 5821 | Knut Wikstrom |
Added Valve Source code. This is NOT to be commited to other than new code from Valve. |