rewrote console command implementation internally

admin commands on the way but still not done
removed weird restriction

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40519
This commit is contained in:
David Anderson 2007-02-17 07:54:20 +00:00
parent 49d96d4322
commit 6b28bec27f
3 changed files with 299 additions and 74 deletions

View File

@ -13,6 +13,7 @@
#include "CConCmdManager.h" #include "CConCmdManager.h"
#include "sm_srvcmds.h" #include "sm_srvcmds.h"
#include "AdminCache.h"
#include "sm_stringutil.h" #include "sm_stringutil.h"
CConCmdManager g_ConCmds; CConCmdManager g_ConCmds;
@ -23,19 +24,22 @@ SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, false, int
struct PlCmdInfo struct PlCmdInfo
{ {
ConCmdInfo *pInfo; ConCmdInfo *pInfo;
CmdHook *pHook;
CmdType type; CmdType type;
}; };
typedef List<PlCmdInfo> CmdList; typedef List<PlCmdInfo> CmdList;
void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info);
CConCmdManager::CConCmdManager() CConCmdManager::CConCmdManager() : m_Strings(1024)
{ {
m_pCmds = sm_trie_create(); m_pCmds = sm_trie_create();
m_pCmdGrps = sm_trie_create();
} }
CConCmdManager::~CConCmdManager() CConCmdManager::~CConCmdManager()
{ {
sm_trie_destroy(m_pCmds); sm_trie_destroy(m_pCmds);
sm_trie_destroy(m_pCmdGrps);
} }
void CConCmdManager::OnSourceModAllInitialized() void CConCmdManager::OnSourceModAllInitialized()
@ -53,9 +57,23 @@ void CConCmdManager::OnSourceModShutdown()
g_PluginSys.RemovePluginsListener(this); g_PluginSys.RemovePluginsListener(this);
} }
void CConCmdManager::OnPluginLoaded(IPlugin *plugin) void CConCmdManager::RemoveConCmds(List<CmdHook *> &cmdlist, IPluginContext *pContext)
{ {
/* Nothing yet... */ List<CmdHook *>::iterator iter = cmdlist.begin();
CmdHook *pHook;
while (iter != cmdlist.end())
{
pHook = (*iter);
if (pHook->pf->GetParentContext() == pContext)
{
delete pHook->pAdmin;
delete pHook;
iter = cmdlist.erase(iter);
} else {
iter++;
}
}
} }
void CConCmdManager::OnPluginDestroyed(IPlugin *plugin) void CConCmdManager::OnPluginDestroyed(IPlugin *plugin)
@ -64,37 +82,42 @@ void CConCmdManager::OnPluginDestroyed(IPlugin *plugin)
List<ConCmdInfo *> removed; List<ConCmdInfo *> removed;
if (plugin->GetProperty("CommandList", (void **)&pList, true)) if (plugin->GetProperty("CommandList", (void **)&pList, true))
{ {
IPluginContext *pContext = plugin->GetBaseContext();
CmdList::iterator iter; CmdList::iterator iter;
/* First pass!
* Only bother if there's an actual command list on this plugin...
*/
for (iter=pList->begin(); for (iter=pList->begin();
iter!=pList->end(); iter!=pList->end();
iter++) iter++)
{ {
PlCmdInfo &cmd = (*iter); PlCmdInfo &cmd = (*iter);
if (cmd.type == Cmd_Server
|| cmd.type == Cmd_Console)
{
ConCmdInfo *pInfo = cmd.pInfo; ConCmdInfo *pInfo = cmd.pInfo;
/* See if this is being removed */
/* Has this chain already been fully cleaned/removed? */
if (removed.find(pInfo) != removed.end()) if (removed.find(pInfo) != removed.end())
{ {
continue; continue;
} }
/* Remove any hooks from us on this command */
RemoveConCmds(pInfo->conhooks, pContext);
RemoveConCmds(pInfo->srvhooks, pContext);
/* See if there are still hooks */ /* See if there are still hooks */
if (pInfo->srvhooks if (pInfo->srvhooks.size())
&& pInfo->srvhooks->GetFunctionCount())
{ {
continue; continue;
} }
if (pInfo->conhooks if (pInfo->conhooks.size())
&& pInfo->conhooks->GetFunctionCount())
{ {
continue; continue;
} }
/* Remove the command */
/* Remove the command, it should be safe now */
RemoveConCmd(pInfo); RemoveConCmd(pInfo);
removed.push_back(pInfo); removed.push_back(pInfo);
} }
}
delete pList; delete pList;
} }
} }
@ -118,15 +141,32 @@ ResultType CConCmdManager::DispatchClientCommand(int client, ResultType type)
if (sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo)) if (sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
{ {
cell_t result = type; cell_t result = type;
if (pInfo->conhooks && pInfo->conhooks->GetFunctionCount()) cell_t tempres = result;
List<CmdHook *>::iterator iter;
CmdHook *pHook;
for (iter=pInfo->conhooks.begin();
iter!=pInfo->conhooks.end();
iter++)
{ {
pInfo->conhooks->PushCell(client); pHook = (*iter);
pInfo->conhooks->PushCell(args); if (pHook->pAdmin
pInfo->conhooks->Execute(&result); && pHook->pAdmin->eflags)
{
/* :TODO: admin calculations */
} }
if (result >= Pl_Stop) pHook->pf->PushCell(client);
pHook->pf->PushCell(args);
if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE)
{ {
return Pl_Stop; if (tempres > result)
{
result = tempres;
}
if (result == Pl_Stop)
{
break;
}
}
} }
type = (ResultType)result; type = (ResultType)result;
} }
@ -153,12 +193,30 @@ void CConCmdManager::InternalDispatch()
cell_t result = Pl_Continue; cell_t result = Pl_Continue;
int args = engine->Cmd_Argc() - 1; int args = engine->Cmd_Argc() - 1;
if (m_CmdClient == 0) List<CmdHook *>::iterator iter;
CmdHook *pHook;
/* Execute server-only commands if viable */
if (m_CmdClient == 0 && pInfo->srvhooks.size())
{ {
if (pInfo->srvhooks && pInfo->srvhooks->GetFunctionCount()) cell_t tempres = result;
for (iter=pInfo->srvhooks.begin();
iter!=pInfo->srvhooks.end();
iter++)
{ {
pInfo->srvhooks->PushCell(args); pHook = (*iter);
pInfo->srvhooks->Execute(&result); pHook->pf->PushCell(args);
if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE)
{
if (tempres > result)
{
result = tempres;
}
if (result == Pl_Stop)
{
break;
}
}
} }
/* Check if there's an early stop */ /* Check if there's an early stop */
@ -172,12 +230,35 @@ void CConCmdManager::InternalDispatch()
} }
} }
/* Execute console command hooks */ /* Execute console commands */
if (pInfo->conhooks && pInfo->conhooks->GetFunctionCount()) if (pInfo->conhooks.size())
{ {
pInfo->conhooks->PushCell(m_CmdClient); cell_t tempres = result;
pInfo->conhooks->PushCell(args); for (iter=pInfo->conhooks.begin();
pInfo->conhooks->Execute(&result); iter!=pInfo->conhooks.end();
iter++)
{
pHook = (*iter);
if (m_CmdClient
&& pHook->pAdmin
&& pHook->pAdmin->eflags)
{
/* :TODO: check admin stuff */
}
pHook->pf->PushCell(m_CmdClient);
pHook->pf->PushCell(args);
if (pHook->pf->Execute(&tempres) != SP_ERROR_NONE)
{
if (tempres > result)
{
result = tempres;
}
if (result == Pl_Stop)
{
break;
}
}
}
} }
if (result >= Pl_Handled) if (result >= Pl_Handled)
@ -190,19 +271,25 @@ void CConCmdManager::InternalDispatch()
} }
} }
ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args)
{
return Pl_Continue;
}
void CConCmdManager::AddConsoleCommand(IPluginFunction *pFunction, void CConCmdManager::AddConsoleCommand(IPluginFunction *pFunction,
const char *name, const char *name,
const char *description, const char *description,
int flags) int flags)
{ {
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
CmdHook *pHook = new CmdHook();
if (!pInfo->conhooks) pHook->pf = pFunction;
if (description && description[0])
{ {
pInfo->conhooks = g_Forwards.CreateForwardEx(NULL, ET_Hook, 2, NULL, Param_Cell, Param_Cell); pHook->helptext.assign(description);
} }
pInfo->conhooks.push_back(pHook);
pInfo->conhooks->AddFunction(pFunction);
/* Add to the plugin */ /* Add to the plugin */
CmdList *pList; CmdList *pList;
@ -215,7 +302,79 @@ void CConCmdManager::AddConsoleCommand(IPluginFunction *pFunction,
PlCmdInfo info; PlCmdInfo info;
info.pInfo = pInfo; info.pInfo = pInfo;
info.type = Cmd_Console; info.type = Cmd_Console;
pList->push_back(info); info.pHook = pHook;
AddToPlCmdList(pList, info);
}
bool CConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
const char *name,
const char *group,
int adminflags,
const char *description,
int flags)
{
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
CmdHook *pHook = new CmdHook();
AdminCmdInfo *pAdmin = new AdminCmdInfo();
pHook->pf = pFunction;
if (description && description[0])
{
pHook->helptext.assign(description);
}
pHook->pAdmin = pAdmin;
void *object;
int grpid;
if (!sm_trie_retrieve(m_pCmdGrps, group, (void **)&object))
{
grpid = m_Strings.AddString(group);
sm_trie_insert(m_pCmdGrps, group, (void *)grpid);
} else {
grpid = (int)object;
}
pAdmin->cmdGrpId = grpid;
pAdmin->flags = flags;
/* First get the command group override, if any */
bool override = g_Admins.GetCommandOverride(group,
Override_CommandGroup,
&(pAdmin->eflags));
/* Next get the command override, if any */
if (g_Admins.GetCommandOverride(name,
Override_Command,
&(pAdmin->eflags)))
{
override = true;
}
/* Assign normal flags if there were no overrides */
if (!override)
{
pAdmin->eflags = pAdmin->flags;
}
/* Finally, add the hook */
pInfo->conhooks.push_back(pHook);
/* Now add to the plugin */
CmdList *pList;
IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
if (!pPlugin->GetProperty("CommandList", (void **)&pList))
{
pList = new CmdList();
pPlugin->SetProperty("CommandList", pList);
}
PlCmdInfo info;
info.pInfo = pInfo;
info.type = Cmd_Admin;
info.pHook = pHook;
AddToPlCmdList(pList, info);
return true;
} }
void CConCmdManager::AddServerCommand(IPluginFunction *pFunction, void CConCmdManager::AddServerCommand(IPluginFunction *pFunction,
@ -225,13 +384,15 @@ void CConCmdManager::AddServerCommand(IPluginFunction *pFunction,
{ {
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
CmdHook *pHook = new CmdHook();
if (!pInfo->srvhooks) pHook->pf = pFunction;
if (description && description[0])
{ {
pInfo->srvhooks = g_Forwards.CreateForwardEx(NULL, ET_Hook, 1, NULL, Param_Cell); pHook->helptext.assign(description);
} }
pInfo->srvhooks->AddFunction(pFunction); pInfo->srvhooks.push_back(pHook);
/* Add to the plugin */ /* Add to the plugin */
CmdList *pList; CmdList *pList;
@ -244,8 +405,37 @@ void CConCmdManager::AddServerCommand(IPluginFunction *pFunction,
PlCmdInfo info; PlCmdInfo info;
info.pInfo = pInfo; info.pInfo = pInfo;
info.type = Cmd_Server; info.type = Cmd_Server;
info.pHook = pHook;
AddToPlCmdList(pList, info);
}
void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info)
{
CmdList::iterator iter = pList->begin();
bool inserted = false;
const char *orig = NULL;
orig = info.pInfo->pCmd->GetName();
/* Insert this into the help list, SORTED alphabetically. */
while (iter != pList->end())
{
PlCmdInfo &obj = (*iter);
const char *cmd = obj.pInfo->pCmd->GetName();
if (strcmp(orig, cmd) < 0)
{
pList->insert(iter, info);
inserted = true;
break;
}
iter++;
}
if (!inserted)
{
pList->push_back(info); pList->push_back(info);
} }
}
void CConCmdManager::AddToCmdList(ConCmdInfo *info) void CConCmdManager::AddToCmdList(ConCmdInfo *info)
{ {
@ -306,11 +496,7 @@ void CConCmdManager::RemoveConCmd(ConCmdInfo *info)
/* Remove from list */ /* Remove from list */
m_CmdList.remove(info); m_CmdList.remove(info);
/* Free forwards */ delete info;
if (info->srvhooks)
{
g_Forwards.ReleaseForward(info->srvhooks);
}
} }
ConCmdInfo *CConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags) ConCmdInfo *CConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags)
@ -400,11 +586,16 @@ void CConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argc
type = "server"; type = "server";
} else if (cmd.type == Cmd_Console) { } else if (cmd.type == Cmd_Console) {
type = "console"; type = "console";
} else if (cmd.type == Cmd_Client) { } else if (cmd.type == Cmd_Admin) {
type = "client"; type = "admin";
} }
name = cmd.pInfo->pCmd->GetName(); name = cmd.pInfo->pCmd->GetName();
if (cmd.pHook->helptext.size())
{
help = cmd.pHook->helptext.c_str();
} else {
help = cmd.pInfo->pCmd->GetHelpText(); help = cmd.pInfo->pCmd->GetHelpText();
}
g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help); g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help);
} }

View File

@ -19,8 +19,11 @@
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include "ForwardSys.h" #include "ForwardSys.h"
#include "sm_trie.h" #include "sm_trie.h"
#include "sm_memtable.h"
#include <sh_list.h> #include <sh_list.h>
#include <sh_string.h>
#include <IRootConsoleMenu.h> #include <IRootConsoleMenu.h>
#include <IAdminSystem.h>
using namespace SourceHook; using namespace SourceHook;
@ -28,7 +31,32 @@ enum CmdType
{ {
Cmd_Server, Cmd_Server,
Cmd_Console, Cmd_Console,
Cmd_Client Cmd_Admin,
};
struct AdminCmdInfo
{
AdminCmdInfo()
{
cmdGrpId = -1;
flags = 0;
eflags = 0;
}
int cmdGrpId; /* index into cmdgroup string table */
FlagBits flags; /* default flags */
FlagBits eflags; /* effective flags */
};
struct CmdHook
{
CmdHook()
{
pf = NULL;
pAdmin = NULL;
}
IPluginFunction *pf; /* function hook */
String helptext; /* help text */
AdminCmdInfo *pAdmin; /* admin requirements, if any */
}; };
struct ConCmdInfo struct ConCmdInfo
@ -37,13 +65,11 @@ struct ConCmdInfo
{ {
sourceMod = false; sourceMod = false;
pCmd = NULL; pCmd = NULL;
srvhooks = NULL;
conhooks = NULL;
} }
bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */ bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */
ConCommand *pCmd; /**< Pointer to the command itself */ ConCommand *pCmd; /**< Pointer to the command itself */
IChangeableForward *srvhooks; /**< Hooks on this name as a server command */ List<CmdHook *> srvhooks; /**< Hooks as a server command */
IChangeableForward *conhooks; /**< Hooks on this name as a console command */ List<CmdHook *> conhooks; /**< Hooks as a console command */
}; };
class CConCmdManager : class CConCmdManager :
@ -59,24 +85,33 @@ public: //SMGlobalClass
void OnSourceModAllInitialized(); void OnSourceModAllInitialized();
void OnSourceModShutdown(); void OnSourceModShutdown();
public: //IPluginsListener public: //IPluginsListener
void OnPluginLoaded(IPlugin *plugin);
void OnPluginDestroyed(IPlugin *plugin); void OnPluginDestroyed(IPlugin *plugin);
public: //IRootConsoleCommand public: //IRootConsoleCommand
void OnRootConsoleCommand(const char *command, unsigned int argcount); void OnRootConsoleCommand(const char *command, unsigned int argcount);
public: public:
void AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags); void AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags);
void AddConsoleCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags); void AddConsoleCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags);
bool AddAdminCommand(IPluginFunction *pFunction,
const char *name,
const char *group,
int adminflags,
const char *description,
int flags);
ResultType DispatchClientCommand(int client, ResultType type); ResultType DispatchClientCommand(int client, ResultType type);
private: private:
void InternalDispatch(); void InternalDispatch();
ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args);
ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags); ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags);
void SetCommandClient(int client); void SetCommandClient(int client);
void AddToCmdList(ConCmdInfo *info); void AddToCmdList(ConCmdInfo *info);
void RemoveConCmd(ConCmdInfo *info); void RemoveConCmd(ConCmdInfo *info);
void RemoveConCmds(List<CmdHook *> &cmdlist, IPluginContext *pContext);
private: private:
Trie *m_pCmds; Trie *m_pCmds; /* command lookup */
List<ConCmdInfo *> m_CmdList; Trie *m_pCmdGrps; /* command group lookup */
int m_CmdClient; List<ConCmdInfo *> m_CmdList; /* command list, currently unused */
int m_CmdClient; /* current client */
BaseStringTable m_Strings; /* string table */
}; };
extern CConCmdManager g_ConCmds; extern CConCmdManager g_ConCmds;

View File

@ -115,7 +115,7 @@ native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:descripti
#if 0 #if 0
/** /**
* Creates a console command as an administrative command. If the command does not exist, * Creates a console command as an administrative command. If the command does not exist,
* it is created. This command cannot be used to create duplicate admin commands. * it is created.
* *
* @param cmd String containing command to register. * @param cmd String containing command to register.
* @param callback A function to use as a callback for when the command is invoked. * @param callback A function to use as a callback for when the command is invoked.
@ -125,7 +125,6 @@ native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:descripti
* @param description Optional description to use for help. * @param description Optional description to use for help.
* @param flags Optional console flags. * @param flags Optional console flags.
* @noreturn * @noreturn
* @error If this command has already been registered as an admin command.
*/ */
native RegAdminCmd(const String:cmd[], native RegAdminCmd(const String:cmd[],
ConCmd:callback, ConCmd:callback,