Finished porting the "plugins" command to the new menu system

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40314
This commit is contained in:
David Anderson 2007-01-17 18:22:00 +00:00
parent 35d0c555fa
commit 3597a8b1fe
5 changed files with 321 additions and 53 deletions

View File

@ -71,6 +71,17 @@ namespace SourceMod
* @return String containing all arguments. * @return String containing all arguments.
*/ */
virtual const char *GetArguments() =0; virtual const char *GetArguments() =0;
/**
* @brief Draws a generic command/description pair.
* NOTE: The pair is currently four spaces indented and 16-N spaces of separation,
* N being the length of the command name. This is subject to change in case we
* account for Valve's font choices.
*
* @param option String containing the command option.
* @param description String containing the command description.
*/
virtual void DrawGenericOption(const char *cmd, const char *text) =0;
}; };
}; };

View File

@ -41,28 +41,6 @@ bool RootConsoleMenu::RegisterConCommandBase(ConCommandBase *pCommand)
return true; return true;
} }
inline const char *StatusToStr(PluginStatus st)
{
switch (st)
{
case Plugin_Running:
return "Running";
case Plugin_Paused:
return "Paused";
case Plugin_Error:
return "Error";
case Plugin_Uncompiled:
return "Uncompiled";
case Plugin_BadLoad:
return "Bad Load";
case Plugin_Failed:
return "Failed";
default:
assert(false);
return "-";
}
}
void RootConsoleMenu::ConsolePrint(const char *fmt, ...) void RootConsoleMenu::ConsolePrint(const char *fmt, ...)
{ {
char buffer[512]; char buffer[512];
@ -155,6 +133,24 @@ bool RootConsoleMenu::RemoveRootConsoleCommand(const char *cmd, IRootConsoleComm
return true; return true;
} }
void RootConsoleMenu::DrawGenericOption(const char *cmd, const char *text)
{
char buffer[255];
size_t len, cmdlen = strlen(cmd);
len = snprintf(buffer, sizeof(buffer), " %s", cmd);
if (cmdlen < 16)
{
size_t num = 16 - cmdlen;
for (size_t i = 0; i < num; i++)
{
buffer[len++] = ' ';
}
len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", text);
ConsolePrint("%s", buffer);
}
}
void RootConsoleMenu::GotRootCmd() void RootConsoleMenu::GotRootCmd()
{ {
unsigned int argnum = GetArgumentCount(); unsigned int argnum = GetArgumentCount();
@ -175,22 +171,10 @@ void RootConsoleMenu::GotRootCmd()
List<ConsoleEntry *>::iterator iter; List<ConsoleEntry *>::iterator iter;
ConsoleEntry *pEntry; ConsoleEntry *pEntry;
char buffer[255];
size_t len;
for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++) for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
{ {
pEntry = (*iter); pEntry = (*iter);
len = snprintf(buffer, sizeof(buffer), " %s", pEntry->command.c_str()); DrawGenericOption(pEntry->command.c_str(), pEntry->description.c_str());
if (pEntry->command.size() < 16)
{
size_t num = 16 - pEntry->command.size();
for (size_t i = 0; i < num; i++)
{
buffer[len++] = ' ';
}
}
len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", pEntry->description.c_str());
ConsolePrint("%s", buffer);
} }
} }
@ -231,7 +215,6 @@ void RootConsoleMenu::OnRootConsoleCommand(const char *cmd, unsigned int argcoun
} }
} }
#define IS_STR_FILLED(var) (var[0] != '\0')
CON_COMMAND(sm, "SourceMod Menu") CON_COMMAND(sm, "SourceMod Menu")
{ {
g_RootMenu.GotRootCmd(); g_RootMenu.GotRootCmd();

View File

@ -42,6 +42,7 @@ public: //IRootConsole
const char *GetArgument(unsigned int argno); const char *GetArgument(unsigned int argno);
unsigned int GetArgumentCount(); unsigned int GetArgumentCount();
const char *GetArguments(); const char *GetArguments();
void DrawGenericOption(const char *cmd, const char *text);
public: public:
void GotRootCmd(); void GotRootCmd();
private: private:

View File

@ -8,6 +8,8 @@
#include "CTextParsers.h" #include "CTextParsers.h"
#include "CLogger.h" #include "CLogger.h"
#include "ExtensionSys.h" #include "ExtensionSys.h"
#include "sm_srvcmds.h"
#include "sm_stringutil.h"
CPluginManager g_PluginSys; CPluginManager g_PluginSys;
HandleType_t g_PluginType = 0; HandleType_t g_PluginType = 0;
@ -477,39 +479,68 @@ IdentityToken_t *CPlugin::GetIdentity() const
return m_ident; return m_ident;
} }
bool CPlugin::ToggleDebugMode(bool debug) bool CPlugin::ToggleDebugMode(bool debug, char *error, size_t maxlength)
{ {
int err; int err;
if (!IsRunnable()) if (!IsRunnable())
{ {
if (error)
{
snprintf(error, maxlength, "Plugin is not runnable.");
}
return false; return false;
} }
if ((debug && IsDebugging()) || (!debug && !IsDebugging())) if (debug && IsDebugging())
{ {
if (error)
{
snprintf(error, maxlength, "Plugin is already in debug mode.");
}
return false;
} else if (!debug && !IsDebugging()) {
if (error)
{
snprintf(error, maxlength, "Plugins is already in production mode.");
}
return false; return false;
} }
ICompilation *co = g_pVM->StartCompilation(m_ctx.ctx->plugin); ICompilation *co = g_pVM->StartCompilation(m_ctx.ctx->plugin);
if (!g_pVM->SetCompilationOption(co, "debug", (debug) ? "1" : "0")) if (!g_pVM->SetCompilationOption(co, "debug", (debug) ? "1" : "0"))
{ {
if (error)
{
snprintf(error, maxlength, "Failed to change plugin mode (JIT failure).");
}
return false; return false;
} }
sp_context_t *new_ctx = g_pVM->CompileToContext(co, &err); sp_context_t *new_ctx = g_pVM->CompileToContext(co, &err);
memcpy(new_ctx->memory, m_ctx.ctx->memory, m_ctx.ctx->mem_size); if (new_ctx)
new_ctx->hp = m_ctx.ctx->hp; {
new_ctx->sp = m_ctx.ctx->sp; memcpy(new_ctx->memory, m_ctx.ctx->memory, m_ctx.ctx->mem_size);
new_ctx->frm = m_ctx.ctx->frm; new_ctx->hp = m_ctx.ctx->hp;
new_ctx->dbreak = m_ctx.ctx->dbreak; new_ctx->sp = m_ctx.ctx->sp;
new_ctx->context = m_ctx.ctx->context; new_ctx->frm = m_ctx.ctx->frm;
memcpy(new_ctx->user, m_ctx.ctx->user, sizeof(m_ctx.ctx->user)); new_ctx->dbreak = m_ctx.ctx->dbreak;
new_ctx->context = m_ctx.ctx->context;
memcpy(new_ctx->user, m_ctx.ctx->user, sizeof(m_ctx.ctx->user));
g_pVM->FreeContext(m_ctx.ctx); g_pVM->FreeContext(m_ctx.ctx);
m_ctx.ctx = new_ctx; m_ctx.ctx = new_ctx;
m_ctx.base->SetContext(new_ctx); m_ctx.base->SetContext(new_ctx);
UpdateInfo(); UpdateInfo();
} else {
if (error)
{
snprintf(error, maxlength, "Failed to recompile plugin (JIT error %d).", err);
}
return false;
}
return true; return true;
} }
@ -1252,10 +1283,14 @@ void CPluginManager::OnSourceModAllInitialized()
g_PluginType = g_HandleSys.CreateType("Plugin", this, 0, NULL, &sec, m_MyIdent, NULL); g_PluginType = g_HandleSys.CreateType("Plugin", this, 0, NULL, &sec, m_MyIdent, NULL);
g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN"); g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN");
g_RootMenu.AddRootConsoleCommand("plugins", "Manage Plugins", this);
} }
void CPluginManager::OnSourceModShutdown() void CPluginManager::OnSourceModShutdown()
{ {
g_RootMenu.RemoveRootConsoleCommand("plugins", this);
List<CPlugin *>::iterator iter; List<CPlugin *>::iterator iter;
while ( (iter = m_plugins.begin()) != m_plugins.end() ) while ( (iter = m_plugins.begin()) != m_plugins.end() )
{ {
@ -1318,3 +1353,232 @@ CPlugin *CPluginManager::GetPluginByOrder(int num)
return pl; return pl;
} }
const char *CPluginManager::GetStatusText(PluginStatus st)
{
switch (st)
{
case Plugin_Running:
return "Running";
case Plugin_Paused:
return "Paused";
case Plugin_Error:
return "Error";
case Plugin_Uncompiled:
return "Uncompiled";
case Plugin_BadLoad:
return "Bad Load";
case Plugin_Failed:
return "Failed";
default:
assert(false);
return "-";
}
}
#define IS_STR_FILLED(var) (var[0] != '\0')
void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argcount)
{
if (argcount >= 3)
{
const char *cmd = g_RootMenu.GetArgument(2);
if (strcmp(cmd, "list") == 0)
{
char buffer[256];
unsigned int id = 1;
int plnum = GetPluginCount();
if (!plnum)
{
g_RootMenu.ConsolePrint("[SM] No plugins loaded");
return;
} else {
g_RootMenu.ConsolePrint("[SM] Displaying %d plugin%s:", GetPluginCount(), (plnum > 1) ? "s" : "");
}
IPluginIterator *iter = GetPluginIterator();
for (; iter->MorePlugins(); iter->NextPlugin(), id++)
{
IPlugin *pl = iter->GetPlugin();
assert(pl->GetStatus() != Plugin_Created);
int len = 0;
const sm_plugininfo_t *info = pl->GetPublicInfo();
len += UTIL_Format(buffer, sizeof(buffer), " %02d <%s>", id, GetStatusText(pl->GetStatus()));
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
if (IS_STR_FILLED(info->version))
{
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", info->version);
}
if (IS_STR_FILLED(info->author))
{
UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", info->author);
}
g_RootMenu.ConsolePrint("%s", buffer);
}
iter->Release();
return;
} else if (strcmp(cmd, "load") == 0) {
if (argcount < 4)
{
g_RootMenu.ConsolePrint("Usage: sm plugins load <file>");
return;
}
char error[128];
const char *filename = g_RootMenu.GetArgument(3);
IPlugin *pl = LoadPlugin(filename, false, PluginType_MapUpdated, error, sizeof(error));
if (pl)
{
g_RootMenu.ConsolePrint("[SM] Loaded plugin %s successfully.", filename);
} else {
g_RootMenu.ConsolePrint("[SM] Plugin %s failed to load: %s.", filename, error);
}
return;
} else if (strcmp(cmd, "unload") == 0) {
if (argcount < 4)
{
g_RootMenu.ConsolePrint("Usage: sm plugins unload <#>");
return;
}
int id = 1;
int num = atoi(g_RootMenu.GetArgument(3));
if (num < 1 || num > (int)GetPluginCount())
{
g_RootMenu.ConsolePrint("Plugin index %d not found.", num);
return;
}
IPluginIterator *iter = GetPluginIterator();
for (; iter->MorePlugins() && id<num; iter->NextPlugin(), id++)
;
IPlugin *pl = iter->GetPlugin();
char name[PLATFORM_MAX_PATH+1];
const sm_plugininfo_t *info = pl->GetPublicInfo();
strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
if (UnloadPlugin(pl))
{
g_RootMenu.ConsolePrint("Plugin %s unloaded successfully.", name);
} else {
g_RootMenu.ConsolePrint("Failed to unload plugin %s.", name);
}
iter->Release();
return;
} else if (strcmp(cmd, "info") == 0) {
if (argcount < 4)
{
g_RootMenu.ConsolePrint("Usage: sm plugins info <#>");
return;
}
int id = 1;
int num = atoi(g_RootMenu.GetArgument(3));
if (num < 1 || num > (int)GetPluginCount())
{
g_RootMenu.ConsolePrint("Plugin index not found.");
return;
}
IPluginIterator *iter = GetPluginIterator();
for (; iter->MorePlugins() && id<num; iter->NextPlugin(), id++) {}
IPlugin *pl = iter->GetPlugin();
const sm_plugininfo_t *info = pl->GetPublicInfo();
g_RootMenu.ConsolePrint(" Filename: %s", pl->GetFilename());
if (IS_STR_FILLED(info->name))
{
g_RootMenu.ConsolePrint(" Title: %s", info->name);
}
if (IS_STR_FILLED(info->author))
{
g_RootMenu.ConsolePrint(" Author: %s", info->author);
}
if (IS_STR_FILLED(info->version))
{
g_RootMenu.ConsolePrint(" Version: %s", info->version);
}
if (IS_STR_FILLED(info->description))
{
g_RootMenu.ConsolePrint(" Description: %s", info->description);
}
if (IS_STR_FILLED(info->url))
{
g_RootMenu.ConsolePrint(" URL: %s", info->url);
}
if (pl->GetStatus() >= Plugin_Error)
{
g_RootMenu.ConsolePrint(" Debugging: %s", pl->IsDebugging() ? "yes" : "no");
}
iter->Release();
return;
} else if (strcmp(cmd, "debug") == 0) {
if (argcount < 5)
{
g_RootMenu.ConsolePrint("Usage: sm plugins debug <#> [on|off]");
return;
}
int num = atoi(g_RootMenu.GetArgument(3));
if (num < 1 || num > (int)GetPluginCount())
{
g_RootMenu.ConsolePrint("Plugin index not found.");
return;
}
int res;
const char *mode = g_RootMenu.GetArgument(4);
if ((res=strcmp("on", mode)) && strcmp("off", mode))
{
g_RootMenu.ConsolePrint("The only possible options are \"on\" and \"off.\"");
return;
}
bool debug;
if (!res)
{
debug = true;
} else {
debug = false;
}
CPlugin *pl = GetPluginByOrder(num);
if (debug && pl->IsDebugging())
{
g_RootMenu.ConsolePrint("[SM] This plugin is already in debug mode.");
return;
} else if (!debug && !pl->IsDebugging()) {
g_RootMenu.ConsolePrint("[SM] Debug mode is already disabled in this plugin.");
return;
}
char error[256];
if (pl->ToggleDebugMode(debug, error, sizeof(error)))
{
g_RootMenu.ConsolePrint("Successfully toggled debug mode on plugin %s.", pl->GetFilename());
return;
} else {
g_RootMenu.ConsolePrint("[SM] Could not toggle debug mode on plugin %s.", pl->GetFilename());
g_RootMenu.ConsolePrint("[SM] Plugin returned error: %s", error);
return;
}
}
}
/* Draw the main menu */
g_RootMenu.ConsolePrint("SourceMod Plugins Menu:");
g_RootMenu.DrawGenericOption("list", "Show loaded plugins");
g_RootMenu.DrawGenericOption("load", "Load a plugin");
g_RootMenu.DrawGenericOption("unload", "Unload a plugin");
g_RootMenu.DrawGenericOption("info", "Information about a plugin");
g_RootMenu.DrawGenericOption("debug", "Toggle debug mode on a plugin");
}

View File

@ -12,6 +12,7 @@
#include "PluginInfoDatabase.h" #include "PluginInfoDatabase.h"
#include "sm_trie.h" #include "sm_trie.h"
#include "sourcemod.h" #include "sourcemod.h"
#include <IRootConsoleMenu.h>
using namespace SourceHook; using namespace SourceHook;
@ -150,7 +151,7 @@ public:
/** /**
* Toggles debug mode in the plugin * Toggles debug mode in the plugin
*/ */
bool ToggleDebugMode(bool debug); bool ToggleDebugMode(bool debug, char *error, size_t maxlength);
/** /**
* Returns true if a plugin is usable. * Returns true if a plugin is usable.
@ -186,7 +187,8 @@ private:
class CPluginManager : class CPluginManager :
public IPluginManager, public IPluginManager,
public SMGlobalClass, public SMGlobalClass,
public IHandleTypeDispatch public IHandleTypeDispatch,
public IRootConsoleCommand
{ {
friend class CPlugin; friend class CPlugin;
public: public:
@ -227,6 +229,8 @@ public: //SMGlobalClass
void OnSourceModShutdown(); void OnSourceModShutdown();
public: //IHandleTypeDispatch public: //IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void *object); void OnHandleDestroy(HandleType_t type, void *object);
public: //IRootConsoleCommand
void OnRootConsoleCommand(const char *command, unsigned int argcount);
public: public:
/** /**
* Loads all plugins not yet loaded * Loads all plugins not yet loaded
@ -265,9 +269,14 @@ public:
IPlugin *PluginFromHandle(Handle_t handle, HandleError *err); IPlugin *PluginFromHandle(Handle_t handle, HandleError *err);
/** /**
* Finds a plugin based on its index. (starts on index 1) * Finds a plugin based on its index. (starts on index 1)
*/ */
CPlugin *GetPluginByOrder(int num); CPlugin *GetPluginByOrder(int num);
/**
* Gets status text for a status code
*/
const char *GetStatusText(PluginStatus status);
private: private:
bool _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t err_max); bool _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t err_max);