1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2024-12-01 13:24:25 +01:00
HLMetaModOfficial/core/metamod_console.cpp
Scott Ehlert 1f1d6e57f9 Rewrote user message caching code to always use IServerGameDLL::GetUserMessageInfo (bug 4117, r=dvander).
Games where the above function can crash are handled by detouring tier0's Error() function and jumping back to our own code. So in theory this should work on all games now.
2009-12-10 00:59:50 -06:00

771 lines
18 KiB
C++

/**
* vim: set ts=4 sw=4 tw=99 noet :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2009 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <stdio.h>
#include "metamod_oslink.h"
#include <ctype.h>
#include "metamod.h"
#include "metamod_util.h"
#include "metamod_console.h"
#include "metamod_plugins.h"
using namespace SourceMM;
using namespace SourceHook;
/**
* @brief Console Command Implementations
* @file concommands.cpp
*/
#define CONMSG g_Metamod.ConPrintf
#define CLIENT_CONMSG g_Metamod.ClientConPrintf
bool Command_Meta(IMetamodSourceCommandInfo *info)
{
unsigned int args = info->GetArgCount();
if (mm_IsVspBridged() && !mm_IsVspLoadComplete())
{
CONMSG("You must change the map to activate Metamod:Source.\n");
return true;
}
if (args >= 1)
{
const char *command = info->GetArg(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 \"DS\" Ehlert\n");
CONMSG("For more information, see the official website\n");
CONMSG("http://www.metamodsource.net/\n");
return true;
}
else if (strcmp(command, "version") == 0)
{
CONMSG("Metamod:Source version %s\n", MMS_FULL_VERSION);
CONMSG("Build ID: %s\n", MMS_BUILD_UNIQUEID);
if (g_Metamod.IsLoadedAsGameDLL())
{
CONMSG("Loaded As: GameDLL (gameinfo.txt)\n");
}
else
{
CONMSG("Loaded As: Valve Server Plugin\n");
}
CONMSG("Compiled on: %s\n", SOURCEMM_DATE);
CONMSG("Plugin interface version: %d:%d\n", METAMOD_PLAPI_VERSION, PLAPI_MIN_VERSION);
CONMSG("SourceHook version: %d:%d\n", g_SHPtr->GetIfaceVersion(), g_SHPtr->GetImplVersion());
CONMSG("http://www.metamodsource.net/\n");
return true;
}
else if (strcmp(command, "game") == 0)
{
CONMSG("GameDLL Information\n");
CONMSG(" Description: %s\n", provider->GetGameDescription());
CONMSG(" Mod Path: %s\n", g_Metamod.GetBaseDir());
CONMSG(" DLL Path: %s\n", g_Metamod.GetGameBinaryPath());
CONMSG(" Interface: ServerGameDLL%03d\n", g_Metamod.GetGameDLLVersion());
#if 0
int engine = g_Metamod.GetSourceEngineBuild();
if (engine == SOURCE_ENGINE_ORIGINAL)
{
CONMSG(" Engine: Original (pre-Episode 1)\n");
}
else if (engine == SOURCE_ENGINE_EPISODEONE)
{
CONMSG(" Engine: Episode 1 (2004)\n");
}
else if (engine == SOURCE_ENGINE_ORANGEBOX)
{
CONMSG(" Engine: Episode 2 (Orange Box, 2007)\n");
}
#endif
#if SOURCE_ENGINE == SE_LEFT4DEAD2
CONMSG(" Engine: Left 4 Dead 2 (2009)\n");
#elif SOURCE_ENGINE == SE_LEFT4DEAD
CONMSG(" Engine: Left 4 Dead (2008)\n");
#elif SOURCE_ENGINE == SE_ORANGEBOX
CONMSG(" Engine: Episode 2 (Orange Box, 2007)\n");
#elif SOURCE_ENGINE == SE_ORANGEBOXVALVE
CONMSG(" Engine: Episode 2 (Valve Orange Box, 2009)\n");
#elif SOURCE_ENGINE == SE_DARKMESSIAH
CONMSG(" Engine: Dark Messiah (2006)\n");
#else
#error "SOURCE_ENGINE not defined to a known value"
#endif
// Display user messages
const char *msgname;
int msgsize;
int messages = g_Metamod.GetUserMessageCount();
if (messages > 0)
{
CONMSG(" User Messages: %-32.31s %-5s %-5s\n", "Name", "Index", "Size");
for (int i = 0; i < messages; i++)
{
msgname = g_Metamod.GetUserMessage(i, &msgsize);
CONMSG(" %-32.31s %-5d %-5d\n", msgname, i, msgsize);
}
CONMSG(" %d user message%s in total\n", messages, (messages > 1) ? "s" : "");
}
else
{
CONMSG(" User Messages: None\n");
}
return true;
}
else if (strcmp(command, "refresh") == 0)
{
char filepath[PATH_SIZE], vdfpath[PATH_SIZE];
g_Metamod.PathFormat(filepath,
sizeof(filepath),
"%s/%s",
g_Metamod.GetBaseDir(),
g_Metamod.GetPluginsFile());
g_Metamod.PathFormat(vdfpath,
sizeof(vdfpath),
"%s/%s",
g_Metamod.GetBaseDir(),
g_Metamod.GetVDFDir());
mm_LoadPlugins(filepath, vdfpath);
return true;
}
else if (strcmp(command, "list") == 0)
{
CPluginManager::CPlugin *pl;
ISmmPlugin *plapi;
const char *plname;
PluginIter i;
char buffer[256];
int len;
int plnum = g_PluginMngr.GetPluginCount();
if (!plnum)
{
CONMSG("No plugins loaded.\n");
return true;
} else {
CONMSG("Listing %d plugin%s:\n", plnum, (plnum > 1) ? "s" : "");
}
for (i = g_PluginMngr._begin(); i != g_PluginMngr._end(); i++)
{
pl = (*i);
if (!pl)
{
break;
}
len = 0;
if (pl->m_Status != Pl_Running)
{
len += UTIL_Format(buffer, sizeof(buffer), " [%02d] <%s>", pl->m_Id, g_PluginMngr.GetStatusText(pl));
} else {
len += UTIL_Format(buffer, sizeof(buffer), " [%02d]", pl->m_Id);
}
if ((plapi = pl->m_API))
{
plname = IS_STR_FILLED(plapi->GetName()) ? plapi->GetName() : pl->m_File.c_str();
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " %s", plname);
if (IS_STR_FILLED(plapi->GetVersion()))
{
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", plapi->GetVersion());
}
if (IS_STR_FILLED(plapi->GetAuthor()))
{
UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", plapi->GetAuthor());
}
}
CONMSG("%s\n", buffer);
}
return true;
}
else if (strcmp(command, "cmds") == 0)
{
if (args >= 2)
{
int id = atoi(info->GetArg(2));
CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
if (!pl)
{
CONMSG("Plugin %d not found.\n", id);
return true;
}
if (!pl->m_API)
{
CONMSG("Plugin %d is not loaded.\n", id);
}
else
{
CONMSG("Console commands for %s:\n", pl->m_API->GetName());
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 true;
}
else if (strcmp(command, "cvars") == 0)
{
if (args >= 2)
{
int id = atoi(info->GetArg(2));
CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
if (!pl)
{
CONMSG("Plugin %d not found.\n", id);
return true;
}
if (!pl->m_API)
{
CONMSG("Plugin %d is not loaded.\n", id);
}
else
{
CONMSG("Registered cvars for %s:\n", pl->m_API->GetName());
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 true;
}
else if (strcmp(command, "info") == 0)
{
if (args >= 2)
{
int id = atoi(info->GetArg(2));
CPluginManager::CPlugin *pl = g_PluginMngr.FindById(id);
if (!pl)
{
CONMSG("Plugin %d not found.\n", id);
return true;
}
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 true;
}
else
{
CONMSG("Usage: meta info <id>\n");
return true;
}
}
else if (strcmp(command, "pause") == 0)
{
if (args >= 2)
{
int id = atoi(info->GetArg(2));
char error[255];
if (!g_PluginMngr.Pause(id, error, sizeof(error)))
{
CONMSG("Pause failed: %s\n", error);
return true;
}
CONMSG("Plugin %d has been paused.\n", id);
return true;
}
else
{
CONMSG("Usage: meta pause <id>\n");
return true;
}
}
else if (strcmp(command, "unpause") == 0)
{
if (args >= 2)
{
int id = atoi(info->GetArg(2));
char error[255];
if (!g_PluginMngr.Unpause(id, error, sizeof(error)))
{
CONMSG("Unpause failed: %s\n", error);
return true;
}
CONMSG("Plugin %d has been unpaused.\n", id);
return true;
}
else
{
CONMSG("Usage: meta unpause <id>\n");
return true;
}
}
else if (strcmp(command, "load") == 0)
{
if (args >= 2)
{
const char *file = info->GetArg(2);
char full_path[255];
const char *alias = g_PluginMngr.LookupAlias(file);
if (alias)
{
file = alias;
}
if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0)
{
g_Metamod.PathFormat(full_path, sizeof(full_path), "%s", file);
}
else
{
const char *ext = UTIL_GetExtension(file);
#if defined WIN32 || defined _WIN32
ext = ext ? "" : ".dll";
#else
ext = ext ? "" : "_i486.so";
#endif
g_Metamod.PathFormat(full_path,
sizeof(full_path),
"%s/%s%s",
g_Metamod.GetBaseDir(),
file,
ext);
}
char error[255]={0};
bool already;
CPluginManager::CPlugin *pl;
PluginId id = g_PluginMngr.Load(full_path, Pl_Console, already, error, sizeof(error));
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 true;
}
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 true;
}
else
{
CONMSG("Usage: meta load <path>\n");
return true;
}
}
else if ( (strcmp(command, "alias") == 0) ||
(strcmp(command, "aliases") == 0) )
{
if (args >= 3)
{
const char *alias = info->GetArg(2);
const char *value = info->GetArg(3);
g_PluginMngr.SetAlias(alias, value);
if (value == NULL || value[0] == '\0')
{
CONMSG("Deleted alias: %s.\n", alias);
} else {
CONMSG("Set alias \"%s\" to: %s\n", alias, value);
}
}
else if (args >= 2)
{
const char *alias = info->GetArg(2);
const char *value = g_PluginMngr.LookupAlias(alias);
if (value)
{
CONMSG("Alias \"%s\" is set to: %s\n", alias, value);
} else {
CONMSG("Alias \"%s\" was not found.\n", alias);
}
}
else
{
List<CNameAlias *>::iterator iter, end;
CNameAlias *p;
iter = g_PluginMngr._alias_begin();
end = g_PluginMngr._alias_end();
size_t total = 0;
if (iter != end)
{
CONMSG("%-10.9s %s\n", "Alias", "File");
CONMSG(" --- \n");
for (; iter!=end; iter++)
{
p = (*iter);
CONMSG("%-10.9s %s\n", p->alias.c_str(), p->value.c_str());
total++;
}
CONMSG(" --- \n");
CONMSG("%d aliases total.\n", total);
}
else
{
CONMSG("No aliases found.\n");
}
}
return true;
}
else if (strcmp(command, "unload") == 0)
{
if (args >= 2)
{
const char *file = info->GetArg(2);
int id = atoi(file);
char error[255]={0};
if (id == 0 && isalpha(file[0]))
{
char full_path[255];
const char *alias = g_PluginMngr.LookupAlias(file);
if (alias)
{
file = alias;
}
/* first check if it's a known filename */
if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0)
{
g_Metamod.PathFormat(full_path, sizeof(full_path), "%s", file);
}
else
{
const char *ext = UTIL_GetExtension(file);
#if defined WIN32 || defined _WIN32
ext = ext ? "" : ".dll";
#else
ext = ext ? "" : "_i486.so";
#endif
g_Metamod.PathFormat(full_path,
sizeof(full_path),
"%s/%s%s",
g_Metamod.GetBaseDir(),
file,
ext);
}
List<CPluginManager::CPlugin *>::iterator iter, end;
CPluginManager::CPlugin *pl;
iter = g_PluginMngr._begin();
end = g_PluginMngr._end();
for (; iter!=end; iter++)
{
pl = (*iter);
if (strcmp(pl->m_File.c_str(), full_path) == 0)
{
id = pl->m_Id;
break;
}
}
if (id == 0)
{
CONMSG("Plugin \"%s\" not found.\n", full_path);
return true;
}
}
if (!g_PluginMngr.Unload(id, false, error, sizeof(error)))
{
CONMSG("Unload failed: %s\n", error);
return true;
}
CONMSG("Plugin %d unloaded.\n", id);
}
else
{
CONMSG("Usage: meta unload <id>\n");
}
return true;
}
else if (strcmp(command, "force_unload") == 0)
{
if (args >= 2)
{
int id = atoi(info->GetArg(2));
char error[255]={0};
if (!g_PluginMngr.Unload(id, false, error, sizeof(error)))
{
CONMSG("Force unload failed: %s\n", error);
return true;
}
CONMSG("Plugin %d force unloaded.\n", id);
return true;
}
else
{
CONMSG("Usage: meta force_unload <id>\n");
return true;
}
}
else if (strcmp(command, "clear") == 0)
{
if (!g_PluginMngr.UnloadAll())
{
CONMSG("One or more plugins resisted removal (cleaned anyway).\n");
return true;
}
CONMSG("All plugins unloaded.\n");
return true;
}
else if (strcmp(command, "retry") == 0)
{
if (args >= 2)
{
int id = atoi(info->GetArg(2));
char error[255];
if (!g_PluginMngr.Retry(id, error, sizeof(error)))
{
CONMSG("Error reloading plugin: %s\n", error);
return true;
}
CONMSG("Plugin %d successfully reloaded.\n", id);
return true;
}
else
{
CONMSG("Usage: meta retry <id>\n");
return true;
}
}
}
CONMSG("Metamod:Source Menu\n");
CONMSG("usage: meta <command> [arguments]\n");
CONMSG(" alias - List or set an alias\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 plugin files\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");
return true;
}
bool Command_ClientMeta(edict_t *client, IMetamodSourceCommandInfo *info)
{
const char *cmd = info->GetArg(0);
if (strcmp(cmd, "meta") == 0)
{
unsigned int args = info->GetArgCount();
if (args == 1)
{
const char *subcmd = info->GetArg(1);
if (strcmp(subcmd, "credits") == 0)
{
CLIENT_CONMSG(client, "Metamod:Source was developed by:\n");
CLIENT_CONMSG(client, " SourceHook: Pavol \"PM OnoTo\" Marko\n");
CLIENT_CONMSG(client, " GameDLL/Plugins: David \"BAILOPAN\" Anderson\n");
CLIENT_CONMSG(client, " GameDLL: Scott \"DS\" Ehlert\n");
CLIENT_CONMSG(client, "For more information, see the official website\n");
CLIENT_CONMSG(client, "http://www.metamodsource.net/\n");
return true;
}
else if(strcmp(subcmd, "version") == 0)
{
CLIENT_CONMSG(client, "Metamod:Source version %s\n", MMS_FULL_VERSION);
CLIENT_CONMSG(client, "Compiled on: %s\n", SOURCEMM_DATE);
CLIENT_CONMSG(client, "Plugin interface version: %d:%d\n", METAMOD_PLAPI_VERSION, PLAPI_MIN_VERSION);
CLIENT_CONMSG(client, "SourceHook version: %d:%d\n", g_SHPtr->GetIfaceVersion(), g_SHPtr->GetImplVersion());
CLIENT_CONMSG(client, "http://www.metamodsource.net/\n");
return true;
}
else if(strcmp(subcmd, "list") == 0)
{
CPluginManager::CPlugin *pl;
ISmmPlugin *plapi;
const char *plname;
PluginIter i;
char buffer[256];
int len = 0;
int plnum = 0;
for (i = g_PluginMngr._begin(); i != g_PluginMngr._end(); i++, len=0)
{
pl = (*i);
if (pl && pl->m_Status == Pl_Running)
{
plapi = pl->m_API;
if (!plapi || !plapi->QueryRunning(NULL, 0))
{
continue;
}
plnum++;
len += UTIL_Format(buffer, sizeof(buffer), " [%02d]", plnum);
plname = IS_STR_FILLED(plapi->GetName()) ? plapi->GetName() : pl->m_File.c_str();
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " %s", plname);
if (IS_STR_FILLED(plapi->GetVersion()))
{
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", plapi->GetVersion());
}
if (IS_STR_FILLED(plapi->GetAuthor()))
{
UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", plapi->GetAuthor());
}
CLIENT_CONMSG(client, "%s\n", buffer);
}
}
if (!plnum)
{
CLIENT_CONMSG(client, "No active plugins loaded.\n");
}
return true;
}
}
CLIENT_CONMSG(client, "Metamod:Source Menu\n");
CLIENT_CONMSG(client, "usage: meta <command>\n");
CLIENT_CONMSG(client, " credits - About Metamod:Source\n");
CLIENT_CONMSG(client, " list - List plugins\n");
CLIENT_CONMSG(client, " version - Version information\n");
return true;
}
return false;
}