diff --git a/core/logic/smn_core.cpp b/core/logic/smn_core.cpp index adf0a0fb..490a6a00 100644 --- a/core/logic/smn_core.cpp +++ b/core/logic/smn_core.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "common_logic.h" #include "Logger.h" @@ -56,6 +57,7 @@ #include #include #include +#include using namespace SourceMod; using namespace SourcePawn; @@ -114,6 +116,71 @@ public: } } g_CoreNativeHelpers; +/** + * @brief Nearly identical to the standard core plugin iterator + * with one key difference. Next doesn't increment the counter + * the first time it is ran. This is a hack for the methodmap.. + */ +class CMMPluginIterator + : public IPluginIterator, + public IPluginsListener +{ +public: + CMMPluginIterator(const CVector *list) + : m_hasStarted(false) + { + for(auto iter = list->begin(); iter != list->end(); ++iter) { + m_list.push_back(*iter); + } + scripts->FreePluginList(list); + + m_current = m_list.begin(); + + scripts->AddPluginsListener(this); + } + + virtual ~CMMPluginIterator() + { + scripts->RemovePluginsListener(this); + } + virtual bool MorePlugins() override + { + return (m_current != m_list.end()); + } + virtual IPlugin *GetPlugin() override + { + return *m_current; + } + virtual void NextPlugin() override + { + if(!m_hasStarted) + { + m_hasStarted = true; + return; + } + + m_current++; + } + virtual void Release() override + { + delete this; + } + +public: + virtual void OnPluginDestroyed(IPlugin *plugin) override + { + if (*m_current == plugin) + m_current = m_list.erase(m_current); + else + m_list.remove(static_cast(plugin)); + } + +private: + std::list m_list; + std::list::iterator m_current; + bool m_hasStarted; +}; + void LogAction(Handle_t hndl, int type, int client, int target, const char *message) { if (g_OnLogAction->GetFunctionCount()) @@ -146,7 +213,7 @@ void LogAction(Handle_t hndl, int type, int client, int target, const char *mess g_Logger.LogMessage("[%s] %s", logtag, message); } - static cell_t ThrowError(IPluginContext *pContext, const cell_t *params) +static cell_t ThrowError(IPluginContext *pContext, const cell_t *params) { char buffer[512]; @@ -264,6 +331,60 @@ static cell_t ReadPlugin(IPluginContext *pContext, const cell_t *params) return pPlugin->GetMyHandle(); } +static cell_t PluginIterator_Create(IPluginContext *pContext, const cell_t *params) +{ + IPluginIterator *iter = new CMMPluginIterator(scripts->ListPlugins()); + + Handle_t hndl = handlesys->CreateHandle(g_PlIter, iter, pContext->GetIdentity(), g_pCoreIdent, NULL); + + if (hndl == BAD_HANDLE) + { + iter->Release(); + } + + return hndl; +} + +static cell_t PluginIterator_Next(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleSecurity sec{pContext->GetIdentity(), g_pCoreIdent}; + HandleError err{}; + IPluginIterator *pIter = nullptr; + + if ((err=handlesys->ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None) + { + return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); + } + + if(!pIter->MorePlugins()) + return 0; + + pIter->NextPlugin(); + return 1; +} + +static cell_t PluginIterator_Plugin_get(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleSecurity sec{pContext->GetIdentity(), g_pCoreIdent}; + HandleError err{}; + IPluginIterator *pIter = nullptr; + + if ((err=handlesys->ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None) + { + return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); + } + + IPlugin *pPlugin = pIter->GetPlugin(); + if (!pPlugin) + { + return BAD_HANDLE; + } + + return pPlugin->GetMyHandle(); +} + IPlugin *GetPluginFromHandle(IPluginContext *pContext, Handle_t hndl) { if (hndl == BAD_HANDLE) @@ -969,7 +1090,7 @@ REGISTER_NATIVES(coreNatives) {"FormatTime", FormatTime}, {"GetPluginIterator", GetPluginIterator}, {"MorePlugins", MorePlugins}, - {"ReadPlugin", ReadPlugin}, + {"ReadPlugin", ReadPlugin}, {"GetPluginStatus", GetPluginStatus}, {"GetPluginFilename", GetPluginFilename}, {"IsPluginDebugging", IsPluginDebugging}, @@ -1000,5 +1121,9 @@ REGISTER_NATIVES(coreNatives) {"FrameIterator.LineNumber.get", FrameIterator_LineNumber}, {"FrameIterator.GetFunctionName", FrameIterator_GetFunctionName}, {"FrameIterator.GetFilePath", FrameIterator_GetFilePath}, + + {"PluginIterator.PluginIterator", PluginIterator_Create}, + {"PluginIterator.Next", PluginIterator_Next}, + {"PluginIterator.Plugin.get", PluginIterator_Plugin_get}, {NULL, NULL}, }; diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 610ff48c..1a704bd9 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -243,6 +243,28 @@ forward void OnAllPluginsLoaded(); */ native Handle GetMyHandle(); +methodmap PluginIterator < Handle +{ + // Returns an iterator that can be used to search through plugins. + // + // @return A new Handle to a PluginIterator. + public native PluginIterator(); + + // Advances the iterator. Returns whether there are more plugins available in the iterator. + // + // @return True on more plugins, false otherwise. + // @error Invalid Handle. + public native bool Next(); + + // Returns the current plugin in the iterator. + // + // @return Current plugin the iterator is at + // @error Invalid Handle. + property Handle Plugin { + public native get(); + } +} + /** * Returns an iterator that can be used to search through plugins. *