diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index e11df52b..a3c266c0 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -342,9 +342,10 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction, const char *group, int adminflags, const char *description, - int flags) + int flags, + IPlugin *pPlugin) { - ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); + ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags, pPlugin); if (!pInfo) return false; @@ -388,10 +389,11 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction, bool ConCmdManager::AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, - int flags) + int flags, + IPlugin *pPlugin) { - ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags); + ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags, pPlugin); if (!pInfo) return false; @@ -555,7 +557,7 @@ bool ConCmdManager::LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags) 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; 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_help = sm_strdup(description); pCmd = new ConCommand(new_name, CommandCallback, new_help, flags); + pInfo->pPlugin = pPlugin; pInfo->sourceMod = true; } else diff --git a/core/ConCmdManager.h b/core/ConCmdManager.h index 2c9865d6..64d84e13 100644 --- a/core/ConCmdManager.h +++ b/core/ConCmdManager.h @@ -99,8 +99,9 @@ struct ConCmdInfo { ConCmdInfo() { + pPlugin = nullptr; sourceMod = false; - pCmd = NULL; + pCmd = nullptr; eflags = 0; } bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */ @@ -108,6 +109,7 @@ struct ConCmdInfo CmdHookList hooks; /**< Hook list */ FlagBits eflags; /**< Effective admin flags */ ke::RefPtr sh_hook; /**< SourceHook hook, if any. */ + IPlugin *pPlugin; /**< Owning plugin handle. */ }; typedef List ConCmdList; @@ -132,13 +134,14 @@ public: //IRootConsoleCommand public: //IConCommandTracker void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name) override; 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, const char *name, const char *group, int adminflags, const char *description, - int flags); + int flags, + IPlugin *pPlugin); ResultType DispatchClientCommand(int client, const char *cmd, int args, ResultType type); void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits, bool remove); bool LookForSourceModCommand(const char *cmd); @@ -146,7 +149,7 @@ public: private: bool InternalDispatch(int client, const ICommandArgs *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 RemoveConCmd(ConCmdInfo *info, const char *cmd, bool untrack); bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin); diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 799e1359..1621977a 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -712,7 +712,8 @@ static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params) 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); } @@ -742,7 +743,7 @@ static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params) IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext()); 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); } @@ -769,9 +770,9 @@ static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params) pContext->LocalToString(params[5], (char **)&group); pFunction = pContext->GetFunctionById(params[2]); + IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext()); if (group[0] == '\0') { - IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext()); 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]); } - 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); } @@ -1307,6 +1308,141 @@ static cell_t FakeClientCommandKeyValues(IPluginContext *pContext, const cell_t #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 &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 &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 &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 &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 &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) { {"CreateConVar", sm_CreateConVar}, @@ -1372,5 +1508,12 @@ REGISTER_NATIVES(consoleNatives) {"ConVar.AddChangeHook", sm_HookConVarChange}, {"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} }; diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 79c13159..07ca0597 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -433,6 +433,52 @@ native int GetCmdArg(int argnum, 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(). *