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 "sm_srvcmds.h"
#include "AdminCache.h"
#include "sm_stringutil.h"
CConCmdManager g_ConCmds;
@ -23,19 +24,22 @@ SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, false, int
struct PlCmdInfo
{
ConCmdInfo *pInfo;
CmdHook *pHook;
CmdType type;
};
typedef List<PlCmdInfo> CmdList;
void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info);
CConCmdManager::CConCmdManager()
CConCmdManager::CConCmdManager() : m_Strings(1024)
{
m_pCmds = sm_trie_create();
m_pCmdGrps = sm_trie_create();
}
CConCmdManager::~CConCmdManager()
{
sm_trie_destroy(m_pCmds);
sm_trie_destroy(m_pCmdGrps);
}
void CConCmdManager::OnSourceModAllInitialized()
@ -53,9 +57,23 @@ void CConCmdManager::OnSourceModShutdown()
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)
@ -64,37 +82,42 @@ void CConCmdManager::OnPluginDestroyed(IPlugin *plugin)
List<ConCmdInfo *> removed;
if (plugin->GetProperty("CommandList", (void **)&pList, true))
{
IPluginContext *pContext = plugin->GetBaseContext();
CmdList::iterator iter;
/* First pass!
* Only bother if there's an actual command list on this plugin...
*/
for (iter=pList->begin();
iter!=pList->end();
iter++)
{
PlCmdInfo &cmd = (*iter);
if (cmd.type == Cmd_Server
|| cmd.type == Cmd_Console)
{
ConCmdInfo *pInfo = cmd.pInfo;
/* See if this is being removed */
/* Has this chain already been fully cleaned/removed? */
if (removed.find(pInfo) != removed.end())
{
continue;
}
/* Remove any hooks from us on this command */
RemoveConCmds(pInfo->conhooks, pContext);
RemoveConCmds(pInfo->srvhooks, pContext);
/* See if there are still hooks */
if (pInfo->srvhooks
&& pInfo->srvhooks->GetFunctionCount())
if (pInfo->srvhooks.size())
{
continue;
}
if (pInfo->conhooks
&& pInfo->conhooks->GetFunctionCount())
if (pInfo->conhooks.size())
{
continue;
}
/* Remove the command */
/* Remove the command, it should be safe now */
RemoveConCmd(pInfo);
removed.push_back(pInfo);
}
}
delete pList;
}
}
@ -118,15 +141,32 @@ ResultType CConCmdManager::DispatchClientCommand(int client, ResultType type)
if (sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
{
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);
pInfo->conhooks->PushCell(args);
pInfo->conhooks->Execute(&result);
pHook = (*iter);
if (pHook->pAdmin
&& 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;
}
@ -153,12 +193,30 @@ void CConCmdManager::InternalDispatch()
cell_t result = Pl_Continue;
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);
pInfo->srvhooks->Execute(&result);
pHook = (*iter);
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 */
@ -172,12 +230,35 @@ void CConCmdManager::InternalDispatch()
}
}
/* Execute console command hooks */
if (pInfo->conhooks && pInfo->conhooks->GetFunctionCount())
/* Execute console commands */
if (pInfo->conhooks.size())
{
pInfo->conhooks->PushCell(m_CmdClient);
pInfo->conhooks->PushCell(args);
pInfo->conhooks->Execute(&result);
cell_t tempres = result;
for (iter=pInfo->conhooks.begin();
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)
@ -190,19 +271,25 @@ void CConCmdManager::InternalDispatch()
}
}
ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args)
{
return Pl_Continue;
}
void CConCmdManager::AddConsoleCommand(IPluginFunction *pFunction,
const char *name,
const char *description,
int 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->AddFunction(pFunction);
pInfo->conhooks.push_back(pHook);
/* Add to the plugin */
CmdList *pList;
@ -215,7 +302,79 @@ void CConCmdManager::AddConsoleCommand(IPluginFunction *pFunction,
PlCmdInfo info;
info.pInfo = pInfo;
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,
@ -225,13 +384,15 @@ void CConCmdManager::AddServerCommand(IPluginFunction *pFunction,
{
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 */
CmdList *pList;
@ -244,7 +405,36 @@ void CConCmdManager::AddServerCommand(IPluginFunction *pFunction,
PlCmdInfo info;
info.pInfo = pInfo;
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);
}
}
void CConCmdManager::AddToCmdList(ConCmdInfo *info)
@ -306,11 +496,7 @@ void CConCmdManager::RemoveConCmd(ConCmdInfo *info)
/* Remove from list */
m_CmdList.remove(info);
/* Free forwards */
if (info->srvhooks)
{
g_Forwards.ReleaseForward(info->srvhooks);
}
delete info;
}
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";
} else if (cmd.type == Cmd_Console) {
type = "console";
} else if (cmd.type == Cmd_Client) {
type = "client";
} else if (cmd.type == Cmd_Admin) {
type = "admin";
}
name = cmd.pInfo->pCmd->GetName();
if (cmd.pHook->helptext.size())
{
help = cmd.pHook->helptext.c_str();
} else {
help = cmd.pInfo->pCmd->GetHelpText();
}
g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help);
}

View File

@ -19,8 +19,11 @@
#include "sourcemm_api.h"
#include "ForwardSys.h"
#include "sm_trie.h"
#include "sm_memtable.h"
#include <sh_list.h>
#include <sh_string.h>
#include <IRootConsoleMenu.h>
#include <IAdminSystem.h>
using namespace SourceHook;
@ -28,7 +31,32 @@ enum CmdType
{
Cmd_Server,
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
@ -37,13 +65,11 @@ struct ConCmdInfo
{
sourceMod = false;
pCmd = NULL;
srvhooks = NULL;
conhooks = NULL;
}
bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */
ConCommand *pCmd; /**< Pointer to the command itself */
IChangeableForward *srvhooks; /**< Hooks on this name as a server command */
IChangeableForward *conhooks; /**< Hooks on this name as a console command */
List<CmdHook *> srvhooks; /**< Hooks as a server command */
List<CmdHook *> conhooks; /**< Hooks as a console command */
};
class CConCmdManager :
@ -59,24 +85,33 @@ public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModShutdown();
public: //IPluginsListener
void OnPluginLoaded(IPlugin *plugin);
void OnPluginDestroyed(IPlugin *plugin);
public: //IRootConsoleCommand
void OnRootConsoleCommand(const char *command, unsigned int argcount);
public:
void AddServerCommand(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);
private:
void InternalDispatch();
ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args);
ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags);
void SetCommandClient(int client);
void AddToCmdList(ConCmdInfo *info);
void RemoveConCmd(ConCmdInfo *info);
void RemoveConCmds(List<CmdHook *> &cmdlist, IPluginContext *pContext);
private:
Trie *m_pCmds;
List<ConCmdInfo *> m_CmdList;
int m_CmdClient;
Trie *m_pCmds; /* command lookup */
Trie *m_pCmdGrps; /* command group lookup */
List<ConCmdInfo *> m_CmdList; /* command list, currently unused */
int m_CmdClient; /* current client */
BaseStringTable m_Strings; /* string table */
};
extern CConCmdManager g_ConCmds;

View File

@ -115,7 +115,7 @@ native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:descripti
#if 0
/**
* 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 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 flags Optional console flags.
* @noreturn
* @error If this command has already been registered as an admin command.
*/
native RegAdminCmd(const String:cmd[],
ConCmd:callback,