Add base CommandIterator implementation (#819)

* Add base CommandIterator implementation

* Add check for invalid pos & finalize pr
This commit is contained in:
Michael Flaherty 2018-07-10 14:39:31 -07:00 committed by Nicholas Hastings
parent aaac0b9eb2
commit 28f1ea82b6
4 changed files with 208 additions and 13 deletions

View File

@ -342,9 +342,10 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
const char *group, const char *group,
int adminflags, int adminflags,
const char *description, const char *description,
int flags) int flags,
IPlugin *pPlugin)
{ {
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags, pPlugin);
if (!pInfo) if (!pInfo)
return false; return false;
@ -388,10 +389,11 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
bool ConCmdManager::AddServerCommand(IPluginFunction *pFunction, bool ConCmdManager::AddServerCommand(IPluginFunction *pFunction,
const char *name, const char *name,
const char *description, const char *description,
int flags) int flags,
IPlugin *pPlugin)
{ {
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags, pPlugin);
if (!pInfo) if (!pInfo)
return false; return false;
@ -555,7 +557,7 @@ bool ConCmdManager::LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags)
return true; return true;
} }
ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags) ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags, IPlugin *pPlugin)
{ {
ConCmdInfo *pInfo; ConCmdInfo *pInfo;
if (!m_Cmds.retrieve(name, &pInfo)) if (!m_Cmds.retrieve(name, &pInfo))
@ -580,6 +582,7 @@ ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *descri
char *new_name = sm_strdup(name); char *new_name = sm_strdup(name);
char *new_help = sm_strdup(description); char *new_help = sm_strdup(description);
pCmd = new ConCommand(new_name, CommandCallback, new_help, flags); pCmd = new ConCommand(new_name, CommandCallback, new_help, flags);
pInfo->pPlugin = pPlugin;
pInfo->sourceMod = true; pInfo->sourceMod = true;
} }
else else

View File

@ -99,8 +99,9 @@ struct ConCmdInfo
{ {
ConCmdInfo() ConCmdInfo()
{ {
pPlugin = nullptr;
sourceMod = false; sourceMod = false;
pCmd = NULL; pCmd = nullptr;
eflags = 0; eflags = 0;
} }
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 */
@ -108,6 +109,7 @@ struct ConCmdInfo
CmdHookList hooks; /**< Hook list */ CmdHookList hooks; /**< Hook list */
FlagBits eflags; /**< Effective admin flags */ FlagBits eflags; /**< Effective admin flags */
ke::RefPtr<CommandHook> sh_hook; /**< SourceHook hook, if any. */ ke::RefPtr<CommandHook> sh_hook; /**< SourceHook hook, if any. */
IPlugin *pPlugin; /**< Owning plugin handle. */
}; };
typedef List<ConCmdInfo *> ConCmdList; typedef List<ConCmdInfo *> ConCmdList;
@ -132,13 +134,14 @@ public: //IRootConsoleCommand
public: //IConCommandTracker public: //IConCommandTracker
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name) override; void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name) override;
public: public:
bool AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags); bool AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags, IPlugin *pPlugin);
bool AddAdminCommand(IPluginFunction *pFunction, bool AddAdminCommand(IPluginFunction *pFunction,
const char *name, const char *name,
const char *group, const char *group,
int adminflags, int adminflags,
const char *description, const char *description,
int flags); int flags,
IPlugin *pPlugin);
ResultType DispatchClientCommand(int client, const char *cmd, int args, ResultType type); ResultType DispatchClientCommand(int client, const char *cmd, int args, ResultType type);
void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits, bool remove); void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits, bool remove);
bool LookForSourceModCommand(const char *cmd); bool LookForSourceModCommand(const char *cmd);
@ -146,7 +149,7 @@ public:
private: private:
bool InternalDispatch(int client, const ICommandArgs *args); bool InternalDispatch(int client, const ICommandArgs *args);
ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args); 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, IPlugin *pPlugin);
void AddToCmdList(ConCmdInfo *info); void AddToCmdList(ConCmdInfo *info);
void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool untrack); void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool untrack);
bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin); bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);

View File

@ -712,7 +712,8 @@ static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
} }
if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4])) IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4], pPlugin))
{ {
return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name); return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
} }
@ -742,7 +743,7 @@ static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext()); IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
const char *group = pPlugin->GetFilename(); const char *group = pPlugin->GetFilename();
if (!g_ConCmds.AddAdminCommand(pFunction, name, group, 0, help, params[4])) if (!g_ConCmds.AddAdminCommand(pFunction, name, group, 0, help, params[4], pPlugin))
{ {
return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name); return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
} }
@ -769,9 +770,9 @@ static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
pContext->LocalToString(params[5], (char **)&group); pContext->LocalToString(params[5], (char **)&group);
pFunction = pContext->GetFunctionById(params[2]); pFunction = pContext->GetFunctionById(params[2]);
IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
if (group[0] == '\0') if (group[0] == '\0')
{ {
IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
group = pPlugin->GetFilename(); group = pPlugin->GetFilename();
} }
@ -780,7 +781,7 @@ static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
} }
if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags)) if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags, pPlugin))
{ {
return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name); return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
} }
@ -1307,6 +1308,141 @@ static cell_t FakeClientCommandKeyValues(IPluginContext *pContext, const cell_t
#endif #endif
} }
static cell_t sm_CommandIterator(IPluginContext *pContext, const cell_t *params)
{
GlobCmdIter *iter = new GlobCmdIter;
iter->started = false;
Handle_t hndl = handlesys->CreateHandle(hCmdIterType, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
if (hndl == BAD_HANDLE)
{
delete iter;
}
return hndl;
}
static cell_t sm_CommandIteratorNext(IPluginContext *pContext, const cell_t *params)
{
GlobCmdIter *iter;
HandleError err;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
if ((err = handlesys->ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid CommandIterator Handle %x", params[1]);
}
const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
if (!iter->started)
{
iter->iter = cmds.begin();
iter->started = true;
}
else
{
iter->iter++;
}
// iterate further, skip non-sourcemod cmds
while (iter->iter != cmds.end() && !(*(iter->iter))->sourceMod)
{
iter->iter++;
}
return iter->iter != cmds.end();
}
static cell_t sm_CommandIteratorFlags(IPluginContext *pContext, const cell_t *params)
{
GlobCmdIter *iter;
HandleError err;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
if ((err = handlesys->ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid CommandIterator Handle %x", params[1]);
}
const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
if (!iter->started || iter->iter == cmds.end())
{
return pContext->ThrowNativeError("Invalid CommandIterator position");
}
ConCmdInfo *pInfo = (*(iter->iter));
return pInfo->eflags;
}
static cell_t sm_CommandIteratorGetDesc(IPluginContext *pContext, const cell_t *params)
{
GlobCmdIter *iter;
HandleError err;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
if ((err = handlesys->ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid CommandIterator Handle %x", params[1]);
}
const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
if (!iter->started || iter->iter == cmds.end())
{
return pContext->ThrowNativeError("Invalid CommandIterator position");
}
ConCmdInfo *pInfo = (*(iter->iter));
pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetHelpText(), NULL);
return 1;
}
static cell_t sm_CommandIteratorGetName(IPluginContext *pContext, const cell_t *params)
{
GlobCmdIter *iter;
HandleError err;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
if ((err = handlesys->ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid CommandIterator Handle %x", params[1]);
}
const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
if (!iter->started || iter->iter == cmds.end())
{
return pContext->ThrowNativeError("Invalid CommandIterator position");
}
ConCmdInfo *pInfo = (*(iter->iter));
pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetName(), NULL);
return 1;
}
static cell_t sm_CommandIteratorPlugin(IPluginContext *pContext, const cell_t *params)
{
GlobCmdIter *iter;
HandleError err;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
if ((err = handlesys->ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid CommandIterator Handle %x", params[1]);
}
const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
if (!iter->started || iter->iter == cmds.end())
{
return pContext->ThrowNativeError("Invalid CommandIterator position");
}
ConCmdInfo *pInfo = (*(iter->iter));
return pInfo->pPlugin->GetMyHandle();
}
REGISTER_NATIVES(consoleNatives) REGISTER_NATIVES(consoleNatives)
{ {
{"CreateConVar", sm_CreateConVar}, {"CreateConVar", sm_CreateConVar},
@ -1372,5 +1508,12 @@ REGISTER_NATIVES(consoleNatives)
{"ConVar.AddChangeHook", sm_HookConVarChange}, {"ConVar.AddChangeHook", sm_HookConVarChange},
{"ConVar.RemoveChangeHook", sm_UnhookConVarChange}, {"ConVar.RemoveChangeHook", sm_UnhookConVarChange},
{"CommandIterator.CommandIterator", sm_CommandIterator},
{"CommandIterator.Next", sm_CommandIteratorNext},
{"CommandIterator.GetDescription", sm_CommandIteratorGetDesc},
{"CommandIterator.GetName", sm_CommandIteratorGetName},
{"CommandIterator.Flags.get", sm_CommandIteratorFlags},
{"CommandIterator.Plugin.get", sm_CommandIteratorPlugin},
{NULL, NULL} {NULL, NULL}
}; };

View File

@ -433,6 +433,52 @@ native int GetCmdArg(int argnum, char[] buffer, int maxlength);
*/ */
native int GetCmdArgString(char[] buffer, int maxlength); native int GetCmdArgString(char[] buffer, int maxlength);
methodmap CommandIterator < Handle {
// Creates a new CommandIterator. Must be freed with delete or
// CloseHandle().
//
// The CommandIterator can be used to iterate commands created by
// SourceMod plugins and allows inspection of properties associated
// with the command.
//
// @return New CommandIterator Handle.
public native CommandIterator();
// Determines if there is a next command. If one is found, the
// iterator is advanced to it.
//
// @return true if found and iterator is advanced.
public native bool Next();
// Retrieves the command's description.
//
// @param buffer Buffer to copy to.
// @param maxlen Maximum size of the buffer.
// @error Invalid iterator position.
public native void GetDescription(char[] buffer, int maxlen);
// Retrieves the command's name.
//
// @param buffer Buffer to copy to.
// @param maxlen Maximum size of the buffer.
// @error Invalid iterator position.
public native void GetName(char[] buffer, int maxlen);
// Retrieves the plugin handle of the command's creator
//
// @error Invalid iterator position.
property Handle Plugin {
public native get();
}
// Retrieves the command's default flags
//
// @error Invalid iterator position.
property int Flags {
public native get();
}
}
/** /**
* Gets a command iterator. Must be freed with CloseHandle(). * Gets a command iterator. Must be freed with CloseHandle().
* *