mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2024-12-10 22:24:12 +01:00
d11b49a202
--HG-- extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40176
560 lines
14 KiB
C++
560 lines
14 KiB
C++
/* ======== SourceMM ========
|
|
* Copyright (C) 2004-2006 Metamod:Source Development Team
|
|
* No warranties of any kind
|
|
*
|
|
* License: zlib/libpng
|
|
*
|
|
* Author(s): David "BAILOPAN" Anderson
|
|
* ============================
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include "CSmmAPI.h"
|
|
#include "concommands.h"
|
|
#include "CPlugin.h"
|
|
#include "sh_string.h"
|
|
#include "sh_list.h"
|
|
|
|
/**
|
|
* @brief Console Command Implementations
|
|
* @file concommands.cpp
|
|
*/
|
|
|
|
CAlwaysRegisterableCommand g_EternalCommand;
|
|
SMConVarAccessor g_SMConVarAccessor;
|
|
|
|
bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
|
|
{
|
|
// Add the FCVAR_GAMEDLL flag
|
|
// => No crash on exit!
|
|
// UPDATE: Do _not_ add the FCVAR_GAMEDLL flag here, as it
|
|
// causes the command to be unusable on listenservers until you load a map
|
|
// We will set the FCVAR_GAMEDLL flag on all commands we have registered once we are being unloaded
|
|
//pCommand->AddFlags(FCVAR_GAMEDLL);
|
|
m_RegisteredCommands.push_back(pCommand);
|
|
|
|
pCommand->SetNext( NULL );
|
|
g_Engine.icvar->RegisterConCommandBase(pCommand);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SMConVarAccessor::Register(ConCommandBase *pCommand)
|
|
{
|
|
//simple, don't mark as part of sourcemm!
|
|
pCommand->SetNext( NULL );
|
|
g_Engine.icvar->RegisterConCommandBase(pCommand);
|
|
|
|
return true;
|
|
}
|
|
|
|
void SMConVarAccessor::MarkCommandsAsGameDLL()
|
|
{
|
|
for (SourceHook::List<ConCommandBase*>::iterator iter = m_RegisteredCommands.begin();
|
|
iter != m_RegisteredCommands.end(); ++iter)
|
|
{
|
|
(*iter)->AddFlags(FCVAR_GAMEDLL);
|
|
}
|
|
}
|
|
|
|
void SMConVarAccessor::Unregister(ConCommandBase *pCommand)
|
|
{
|
|
ICvar *cv = g_Engine.icvar;
|
|
ConCommandBase *ptr = cv->GetCommands();
|
|
|
|
if (ptr == pCommand)
|
|
{
|
|
//first in list
|
|
g_EternalCommand.BringToFront();
|
|
g_EternalCommand.SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
|
|
} else {
|
|
//find us and unregister us
|
|
ConCommandBase *pPrev = NULL;
|
|
while (ptr)
|
|
{
|
|
if (ptr == pCommand)
|
|
break;
|
|
pPrev = ptr;
|
|
ptr = const_cast<ConCommandBase *>(ptr->GetNext());
|
|
}
|
|
if (pPrev && ptr == pCommand)
|
|
{
|
|
pPrev->SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void SMConVarAccessor::UnregisterGameDLLCommands()
|
|
{
|
|
ConCommandBase *begin = g_Engine.icvar->GetCommands();
|
|
ConCommandBase *iter = begin;
|
|
ConCommandBase *prev = NULL;
|
|
while (iter)
|
|
{
|
|
// watch out for the ETERNAL COMMAND!
|
|
if (iter != &g_EternalCommand && iter->IsBitSet(FCVAR_GAMEDLL))
|
|
{
|
|
// Remove it!
|
|
if (iter == begin)
|
|
{
|
|
g_EternalCommand.BringToFront();
|
|
iter = const_cast<ConCommandBase*>(iter->GetNext());
|
|
g_EternalCommand.SetNext(iter);
|
|
prev = &g_EternalCommand;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
iter = const_cast<ConCommandBase*>(iter->GetNext());
|
|
prev->SetNext(iter);
|
|
continue;
|
|
}
|
|
}
|
|
prev = iter;
|
|
iter = const_cast<ConCommandBase*>(iter->GetNext());
|
|
}
|
|
}
|
|
|
|
ConVar metamod_version("metamod_version", SOURCEMM_VERSION, FCVAR_REPLICATED | FCVAR_SPONLY | FCVAR_NOTIFY, "Metamod:Source Version");
|
|
#if defined WIN32 || defined _WIN32
|
|
ConVar mm_pluginsfile("mm_pluginsfile", "addons\\metamod\\metaplugins.ini", FCVAR_SPONLY, "Metamod:Source Plugins File");
|
|
#else
|
|
ConVar mm_pluginsfile("mm_pluginsfile", "addons/metamod/metaplugins.ini", FCVAR_SPONLY, "Metamod:Source Plugins File");
|
|
#endif
|
|
|
|
CON_COMMAND(meta, "Metamod:Source Menu")
|
|
{
|
|
IVEngineServer *e = g_Engine.engine;
|
|
|
|
int args = e->Cmd_Argc();
|
|
|
|
if (args >= 2)
|
|
{
|
|
const char *command = e->Cmd_Argv(1);
|
|
if (strcmp(command, "credits") == 0)
|
|
{
|
|
CONMSG("Metamod:Source was developed by:\n");
|
|
CONMSG(" SourceHook: Pavol \"PM OnoTo\" Marko\n");
|
|
CONMSG(" GameDLL/Plugins: David \"BAILOPAN\" Anderson\n");
|
|
CONMSG(" GameDLL: Scott \"Damaged Soul\" Ehlert\n");
|
|
CONMSG("For more information, see the official website\n");
|
|
CONMSG("http://www.sourcemm.net/\n");
|
|
|
|
return;
|
|
} else if (strcmp(command, "version") == 0) {
|
|
CONMSG("Metamod:Source version %s\n", SOURCEMM_VERSION);
|
|
CONMSG("Compiled on: %s\n", SOURCEMM_DATE);
|
|
CONMSG("Plugin interface version: %d:%d\n", PLAPI_VERSION, PLAPI_MIN_VERSION);
|
|
CONMSG("SourceHook version: %d:%d\n", g_SourceHook.GetIfaceVersion(), g_SourceHook.GetImplVersion());
|
|
CONMSG("http://www.sourcemm.net/\n");
|
|
|
|
return;
|
|
} else if (strcmp(command, "game") == 0) {
|
|
CONMSG("GameDLL Information\n");
|
|
CONMSG(" Mod path: %s\n", g_ModPath.c_str());
|
|
CONMSG(" Dll path: %s\n", g_BinPath.c_str());
|
|
|
|
return;
|
|
} else if (strcmp(command, "refresh") == 0) {
|
|
char full_path[255];
|
|
#if defined WIN32 || defined _WIN32
|
|
snprintf(full_path, sizeof(full_path)-1, "%s\\addons\\metamod\\%s", g_ModPath.c_str(), "metaplugins.ini");
|
|
#else
|
|
snprintf(full_path, sizeof(full_path)-1, "%s/addons/metamod/%s", g_ModPath.c_str(), "metaplugins.ini");
|
|
#endif
|
|
LoadPluginsFromFile(full_path);
|
|
|
|
return;
|
|
} else if (strcmp(command, "list") == 0) {
|
|
SourceMM::CPluginManager::CPlugin *pl;
|
|
PluginIter i;
|
|
const char *status="";
|
|
const char *version=NULL;
|
|
const char *name=NULL;
|
|
const char *author=NULL;
|
|
|
|
CONMSG("-Id- %-16.15s %-8.7s %-12.11s %-8.7s\n", "Name", "Version", "Author", "Status");
|
|
for (i=g_PluginMngr._begin(); i!=g_PluginMngr._end(); i++)
|
|
{
|
|
pl = (*i);
|
|
if (!pl)
|
|
break;
|
|
if (pl->m_Status == Pl_Paused)
|
|
{
|
|
status = "PAUSE";
|
|
} else if (pl->m_Status == Pl_Running) {
|
|
if (pl->m_API && pl->m_API->QueryRunning(NULL, 0))
|
|
status = "RUN";
|
|
else
|
|
status = "STOPPED";
|
|
} else if (pl->m_Status == Pl_Refused) {
|
|
status = "FAIL";
|
|
} else if (pl->m_Status == Pl_Error) {
|
|
status = "ERROR";
|
|
} else if (pl->m_Status == Pl_NotFound) {
|
|
status = "NOFILE";
|
|
}
|
|
|
|
if (pl->m_API)
|
|
{
|
|
version = pl->m_API->GetVersion();
|
|
author = pl->m_API->GetAuthor();
|
|
name = pl->m_API->GetName();
|
|
} else {
|
|
version = "-";
|
|
author = "-";
|
|
name = "-";
|
|
}
|
|
|
|
if (!version)
|
|
version = "-";
|
|
if (!author)
|
|
author = "-";
|
|
if (!name)
|
|
name = pl->m_File.c_str();
|
|
|
|
|
|
CONMSG("[%02d] %-16.15s %-8.7s %-12.11s %-8.7s\n", pl->m_Id, name, version, author, status);
|
|
}
|
|
|
|
//CONMSG("\n");
|
|
|
|
return;
|
|
} else if (strcmp(command, "cmds") == 0) {
|
|
if (args >= 3)
|
|
{
|
|
int id = atoi(e->Cmd_Argv(2));
|
|
SourceMM::CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
|
|
|
|
if (!pl)
|
|
{
|
|
CONMSG("Plugin %d not found.\n", id);
|
|
return;
|
|
}
|
|
|
|
if (!pl->m_API)
|
|
{
|
|
CONMSG("Plugin %d is not loaded.\n", id);
|
|
} else {
|
|
CONMSG("Console commands for %s:\n", pl->m_API->GetName());
|
|
SourceHook::List<ConCommandBase *>::iterator ci;
|
|
size_t count = 0;
|
|
|
|
for (ci=pl->m_Cmds.begin(); ci!=pl->m_Cmds.end(); ci++)
|
|
{
|
|
count++;
|
|
CONMSG(" [%5d] %-s\n", count, (*ci)->GetName());
|
|
}
|
|
}
|
|
} else {
|
|
CONMSG("Usage: meta cmds <id>\n");
|
|
}
|
|
|
|
return;
|
|
} else if (strcmp(command, "cvars") == 0) {
|
|
if (args >= 3)
|
|
{
|
|
int id = atoi(e->Cmd_Argv(2));
|
|
SourceMM::CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
|
|
|
|
if (!pl)
|
|
{
|
|
CONMSG("Plugin %d not found.\n", id);
|
|
return;
|
|
}
|
|
|
|
if (!pl->m_API)
|
|
{
|
|
CONMSG("Plugin %d is not loaded.\n", id);
|
|
} else {
|
|
CONMSG("Registered cvars for %s:\n", pl->m_API->GetName());
|
|
SourceHook::List<ConCommandBase *>::iterator ci;
|
|
size_t count = 0;
|
|
|
|
for (ci=pl->m_Cvars.begin(); ci!=pl->m_Cvars.end(); ci++)
|
|
{
|
|
count++;
|
|
CONMSG(" [%5d] %-s\n", count, (*ci)->GetName());
|
|
}
|
|
}
|
|
} else {
|
|
CONMSG("Usage: meta cvars <id>\n");
|
|
}
|
|
|
|
return;
|
|
} else if (strcmp(command, "info") == 0) {
|
|
if (args >= 3)
|
|
{
|
|
int id = atoi(e->Cmd_Argv(2));
|
|
SourceMM::CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
|
|
if (!pl)
|
|
{
|
|
CONMSG("Plugin %d not found.\n", id);
|
|
return;
|
|
}
|
|
|
|
if (!pl->m_API)
|
|
{
|
|
CONMSG("Plugin %d is not loaded.\n", id);
|
|
} else {
|
|
if (pl->m_Status == Pl_Paused)
|
|
{
|
|
CONMSG("Plugin %d is paused.\n", id);
|
|
} else if (pl->m_Status == Pl_Running) {
|
|
char run_msg[255];
|
|
bool run = false;
|
|
if (pl->m_API && pl->m_API->QueryRunning(run_msg, sizeof(run_msg)-1))
|
|
run = true;
|
|
if (run)
|
|
{
|
|
CONMSG("Plugin %d is running.\n", id);
|
|
} else {
|
|
CONMSG("Plugin %d is stopped: %s\n", id, run_msg);
|
|
}
|
|
}
|
|
CONMSG(" Name: \"%s\" by %s\n", pl->m_API->GetName(), pl->m_API->GetAuthor());
|
|
CONMSG(" Version: %s\n", pl->m_API->GetVersion());
|
|
CONMSG(" Description: %s\n", pl->m_API->GetDescription());
|
|
CONMSG(" License: %s\n", pl->m_API->GetLicense());
|
|
CONMSG(" URL: %s\n", pl->m_API->GetURL());
|
|
CONMSG(" Details: API %03d, Date: %s\n", pl->m_API->GetApiVersion(), pl->m_API->GetDate());
|
|
}
|
|
CONMSG("File: %s\n\n", pl->m_File.c_str());
|
|
|
|
return;
|
|
} else {
|
|
CONMSG("Usage: meta info <id>\n");
|
|
|
|
return;
|
|
}
|
|
} else if (strcmp(command, "pause") == 0) {
|
|
if (args >= 3)
|
|
{
|
|
int id = atoi(e->Cmd_Argv(2));
|
|
|
|
char error[255];
|
|
|
|
if (!g_PluginMngr.Pause(id, error, sizeof(error)-1))
|
|
{
|
|
CONMSG("Pause failed: %s\n", error);
|
|
return;
|
|
}
|
|
|
|
CONMSG("Plugin %d has been paused.\n", id);
|
|
|
|
return;
|
|
} else {
|
|
CONMSG("Usage: meta pause <id>\n");
|
|
|
|
return;
|
|
}
|
|
} else if (strcmp(command, "unpause") == 0) {
|
|
if (args >= 3)
|
|
{
|
|
int id = atoi(e->Cmd_Argv(2));
|
|
char error[255];
|
|
|
|
if (!g_PluginMngr.Unpause(id, error, sizeof(error)-1))
|
|
{
|
|
CONMSG("Unpause failed: %s\n", error);
|
|
return;
|
|
}
|
|
|
|
CONMSG("Plugin %d has been unpaused.\n", id);
|
|
|
|
return;
|
|
} else {
|
|
CONMSG("Usage: meta unpause <id>\n");
|
|
|
|
return;
|
|
}
|
|
} else if (strcmp(command, "load") == 0) {
|
|
if (args >= 3)
|
|
{
|
|
const char *file = e->Cmd_Argv(2);
|
|
char full_path[255];
|
|
|
|
if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0)
|
|
{
|
|
snprintf(full_path, sizeof(full_path)-1, "%s", file);
|
|
} else {
|
|
const char *ext = UTIL_GetExtension(file);
|
|
#if defined WIN32 || defined _WIN32
|
|
ext = ext ? "" : ".dll";
|
|
snprintf(full_path, sizeof(full_path)-1, "%s\\%s%s", g_ModPath.c_str(), file, ext);
|
|
#else
|
|
ext = ext ? "" : "_i486.so";
|
|
snprintf(full_path, sizeof(full_path)-1, "%s/%s%s", g_ModPath.c_str(), file, ext);
|
|
#endif
|
|
}
|
|
|
|
char error[255]={0};
|
|
bool already;
|
|
SourceMM::CPluginManager::CPlugin *pl;
|
|
|
|
PluginId id = g_PluginMngr.Load(full_path, Pl_Console, already, error, sizeof(error)-1);
|
|
pl = g_PluginMngr.FindById(id);
|
|
if (!pl || id < Pl_MinId || (pl->m_Status < Pl_Paused))
|
|
{
|
|
CONMSG("Failed to load plugin %s (%s).\n", file, error);
|
|
return;
|
|
}
|
|
|
|
if (!already)
|
|
{
|
|
CONMSG("Plugin \"%s\" loaded with id %d.\n", pl->m_API->GetName(), pl->m_Id);
|
|
} else {
|
|
CONMSG("Plugin \"%s\" is already loaded as %d.\n", pl->m_API->GetName(), pl->m_Id);
|
|
}
|
|
|
|
return;
|
|
} else {
|
|
CONMSG("Usage: meta load <path>\n");
|
|
|
|
return;
|
|
}
|
|
} else if (strcmp(command, "unload") == 0) {
|
|
if (args >= 3)
|
|
{
|
|
int id = atoi(e->Cmd_Argv(2));
|
|
char error[255]={0};
|
|
|
|
if (!g_PluginMngr.Unload(id, false, error, sizeof(error)-1))
|
|
{
|
|
CONMSG("Unload failed: %s\n", error);
|
|
return;
|
|
}
|
|
|
|
CONMSG("Plugin %d unloaded.\n", id);
|
|
|
|
return;
|
|
} else {
|
|
CONMSG("Usage: meta unload <id>\n");
|
|
|
|
return;
|
|
}
|
|
} else if (strcmp(command, "force_unload") == 0) {
|
|
if (args >= 3)
|
|
{
|
|
int id = atoi(e->Cmd_Argv(2));
|
|
char error[255]={0};
|
|
|
|
if (!g_PluginMngr.Unload(id, false, error, sizeof(error)-1))
|
|
{
|
|
CONMSG("Force unload failed: %s\n", error);
|
|
return;
|
|
}
|
|
|
|
CONMSG("Plugin %d force unloaded.\n", id);
|
|
|
|
return;
|
|
} else {
|
|
CONMSG("Usage: meta force_unload <id>\n");
|
|
|
|
return;
|
|
}
|
|
} else if (strcmp(command, "clear") == 0) {
|
|
if (!g_PluginMngr.UnloadAll())
|
|
{
|
|
CONMSG("One or more plugins resisted removal (cleaned anyway).\n");
|
|
return;
|
|
}
|
|
|
|
CONMSG("All plugins unloaded.\n");
|
|
|
|
return;
|
|
} else if (strcmp(command, "retry") == 0) {
|
|
if (args >= 3)
|
|
{
|
|
int id = atoi(e->Cmd_Argv(2));
|
|
char error[255];
|
|
|
|
if (!g_PluginMngr.Retry(id, error, sizeof(error)-1))
|
|
{
|
|
CONMSG("Error reloading plugin: %s\n", error);
|
|
return;
|
|
}
|
|
|
|
CONMSG("Plugin %d successfully reloaded.\n", id);
|
|
|
|
return;
|
|
} else {
|
|
CONMSG("Usage: meta retry <id>\n");
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
CONMSG("Metamod:Source Menu\n");
|
|
CONMSG("usage: meta <command> [arguments]\n");
|
|
CONMSG(" clear - Unload all plugins forcefully\n");
|
|
CONMSG(" cmds - Show plugin commands\n");
|
|
CONMSG(" cvars - Show plugin cvars\n");
|
|
CONMSG(" credits - About Metamod:Source\n");
|
|
CONMSG(" force_unload - Forcefully unload a plugin\n");
|
|
CONMSG(" game - Information about GameDLL\n");
|
|
CONMSG(" info - Information about a plugin\n");
|
|
CONMSG(" list - List plugins\n");
|
|
CONMSG(" load - Load a plugin\n");
|
|
CONMSG(" pause - Pause a running plugin\n");
|
|
CONMSG(" refresh - Reparse plugins file\n");
|
|
CONMSG(" retry - Attempt to reload a plugin\n");
|
|
CONMSG(" unload - Unload a loaded plugin\n");
|
|
CONMSG(" unpause - Unpause a paused plugin\n");
|
|
CONMSG(" version - Version information\n");
|
|
}
|
|
|
|
CAlwaysRegisterableCommand::CAlwaysRegisterableCommand()
|
|
{
|
|
Create("", NULL, FCVAR_UNREGISTERED|FCVAR_GAMEDLL);
|
|
m_pICvar = NULL;
|
|
}
|
|
|
|
bool CAlwaysRegisterableCommand::IsRegistered( void ) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void CAlwaysRegisterableCommand::BringToFront()
|
|
{
|
|
if (!m_pICvar)
|
|
m_pICvar = g_Engine.icvar;
|
|
|
|
// First, let's try to find us!
|
|
ConCommandBase *pPtr = m_pICvar->GetCommands();
|
|
|
|
if (pPtr == this)
|
|
{
|
|
// We are already at the beginning; Nothing to do
|
|
return;
|
|
}
|
|
|
|
while (pPtr)
|
|
{
|
|
if (pPtr == this && pPtr->IsCommand() && stricmp(GetName(), pPtr->GetName()) == 0)
|
|
break;
|
|
ConCommandBase *pPrev = NULL;
|
|
while (pPtr)
|
|
{
|
|
if (pPtr == this)
|
|
break;
|
|
pPrev = pPtr;
|
|
pPtr = const_cast<ConCommandBase*>(pPtr->GetNext());
|
|
}
|
|
if (pPrev && pPtr == this)
|
|
{
|
|
pPrev->SetNext(m_pNext); // Remove us from the list
|
|
}
|
|
// Now, register us
|
|
SetNext(NULL);
|
|
m_pICvar->RegisterConCommandBase(this);
|
|
}
|
|
}
|
|
|
|
const char *GetPluginsFile()
|
|
{
|
|
return mm_pluginsfile.GetString();
|
|
}
|
|
|