diff --git a/amxmodx/CForward.cpp b/amxmodx/CForward.cpp index fd2eda00..aeaf578b 100755 --- a/amxmodx/CForward.cpp +++ b/amxmodx/CForward.cpp @@ -53,14 +53,14 @@ CForward::CForward(const char *name, ForwardExecType et, int numParams, const Fo } } -int CForward::execute(cell *params, ForwardPreparedArray *preparedArrays) +cell CForward::execute(cell *params, ForwardPreparedArray *preparedArrays) { cell realParams[FORWARD_MAX_PARAMS]; cell *physAddrs[FORWARD_MAX_PARAMS]; const int STRINGEX_MAXLENGTH = 128; - int globRetVal = 0; + cell globRetVal = 0; for (CList::iterator iter = m_Funcs.begin(); iter; ++iter) { @@ -159,28 +159,179 @@ int CForward::execute(cell *params, ForwardPreparedArray *preparedArrays) return globRetVal; } +void CSPForward::Set(int func, AMX *amx, int numParams, const ForwardParam *paramTypes) +{ + m_Func = func; + m_Amx = amx; + m_NumParams = numParams; + memcpy((void *)m_ParamTypes, paramTypes, numParams * sizeof(ForwardParam)); + m_HasFunc = true; +} + +void CSPForward::Set(const char *funcName, AMX *amx, int numParams, const ForwardParam *paramTypes) +{ + m_Amx = amx; + m_NumParams = numParams; + memcpy((void *)m_ParamTypes, paramTypes, numParams * sizeof(ForwardParam)); + m_HasFunc = (amx_FindPublic(amx, funcName, &m_Func) == AMX_ERR_NONE); +} + +cell CSPForward::execute(cell *params, ForwardPreparedArray *preparedArrays) +{ + const int STRINGEX_MAXLENGTH = 128; + + cell realParams[FORWARD_MAX_PARAMS]; + cell *physAddrs[FORWARD_MAX_PARAMS]; + + if (!m_HasFunc) + return 0; + + CPluginMngr::CPlugin *pPlugin = g_plugins.findPluginFast(m_Amx); + if (!pPlugin->isExecutable(m_Func)) + return 0; + + // handle strings & arrays + int i; + for (i = 0; i < m_NumParams; ++i) + { + if (m_ParamTypes[i] == FP_STRING || m_ParamTypes[i] == FP_STRINGEX) + { + cell *tmp; + amx_Allot(m_Amx, + (m_ParamTypes[i] == FP_STRING) ? strlen(reinterpret_cast(params[i]))+1 : STRINGEX_MAXLENGTH, + &realParams[i], &tmp); + amx_SetString(tmp, (const char *)(params[i]), 0, 0); + physAddrs[i] = tmp; + } + else if (m_ParamTypes[i] == FP_ARRAY) + { + cell *tmp; + amx_Allot(m_Amx, preparedArrays[params[i]].size, + &realParams[i], &tmp); + physAddrs[i] = tmp; + if (preparedArrays[params[i]].type == Type_Cell) + { + memcpy(tmp, preparedArrays[params[i]].ptr, preparedArrays[params[i]].size * sizeof(cell)); + } + else + { + char *data = (char*)preparedArrays[params[i]].ptr; + for (unsigned int j = 0; j < preparedArrays[params[i]].size; ++j) + *tmp++ = (static_cast(*data++)) & 0xFF; + } + } + else + { + realParams[i] = params[i]; + } + } + + // exec + cell retVal; + amx_Execv(m_Amx, &retVal, m_Func, m_NumParams, realParams); + + // cleanup strings & arrays + for (i = 0; i < m_NumParams; ++i) + { + if (m_ParamTypes[i] == FP_STRING) + { + amx_Release(m_Amx, realParams[i]); + } + else if (m_ParamTypes[i] == FP_STRINGEX) + { + // copy back + amx_GetString(reinterpret_cast(params[i]), physAddrs[i], 0); + amx_Release(m_Amx, realParams[i]); + } + else if (m_ParamTypes[i] == FP_ARRAY) + { + // copy back + cell *tmp = physAddrs[i]; + if (preparedArrays[params[i]].type == Type_Cell) + { + memcpy(preparedArrays[params[i]].ptr, tmp, preparedArrays[params[i]].size * sizeof(cell)); + } + else + { + char *data = (char*)preparedArrays[params[i]].ptr; + for (unsigned int j = 0; j < preparedArrays[params[i]].size; ++j) + *data++ = static_cast(*tmp++ & 0xFF); + } + amx_Release(m_Amx, realParams[i]); + } + } + + return retVal; +} + int CForwardMngr::registerForward(const char *funcName, ForwardExecType et, int numParams, const ForwardParam * paramTypes) { - int retVal = m_Forwards.size(); + int retVal = m_Forwards.size() << 1; m_Forwards.push_back(new CForward(funcName, et, numParams, paramTypes)); return retVal; } +int CForwardMngr::registerSPForward(int func, AMX *amx, int numParams, const ForwardParam *paramTypes) +{ + int retVal = (m_SPForwards.size() << 1) | 1; + CSPForward *pForward; + if (m_FreeSPForwards.size()) + { + pForward = m_SPForwards[m_FreeSPForwards.back()]; + m_FreeSPForwards.pop_back(); + pForward->Set(func, amx, numParams, paramTypes); + } + else + { + pForward = new CSPForward(); + if (!pForward) + return -1; + pForward->Set(func, amx, numParams, paramTypes); + m_SPForwards.push_back(pForward); + } + return retVal; +} + +int CForwardMngr::registerSPForward(const char *funcName, AMX *amx, int numParams, const ForwardParam *paramTypes) +{ + int retVal = (m_SPForwards.size() << 1) | 1; + CSPForward *pForward; + if (m_FreeSPForwards.size()) + { + pForward = m_SPForwards[m_FreeSPForwards.back()]; + m_FreeSPForwards.pop_back(); + pForward->Set(funcName, amx, numParams, paramTypes); + } + else + { + pForward = new CSPForward(); + if (!pForward) + return -1; + pForward->Set(funcName, amx, numParams, paramTypes); + m_SPForwards.push_back(pForward); + } + return retVal; +} + bool CForwardMngr::isIdValid(int id) const { - return (id >= 0) && (static_cast(id) < m_Forwards.size()); + return (id >= 0) && ((id & 1) ? + (static_cast(id >> 1) < m_SPForwards.size()) : + (static_cast(id >> 1) < m_Forwards.size())); } -int CForwardMngr::executeForwards(int id, cell *params) +cell CForwardMngr::executeForwards(int id, cell *params) { - int retVal = m_Forwards[id]->execute(params, m_TmpArrays); + int retVal = (id & 1) ? m_SPForwards[id >> 1]->execute(params, m_TmpArrays) : + m_Forwards[id >> 1]->execute(params, m_TmpArrays); m_TmpArraysNum = 0; return retVal; } int CForwardMngr::getParamsNum(int id) const { - return m_Forwards[id]->getParamsNum(); + return (id & 1) ? m_SPForwards[id >> 1]->getParamsNum() : + m_Forwards[id >> 1]->getParamsNum(); } void CForwardMngr::clear() @@ -189,10 +340,28 @@ void CForwardMngr::clear() { delete (*iter); } + SPForwardVec::iterator spIter; + for (spIter = m_SPForwards.begin(); spIter != m_SPForwards.end(); ++spIter) + { + delete (*spIter); + } + m_Forwards.clear(); + m_SPForwards.clear(); + m_FreeSPForwards.clear(); m_TmpArraysNum = 0; } +bool CForwardMngr::isSPForward(int id) const +{ + return ((id & 1) == 0) ? false : true; +} + +void CForwardMngr::unregisterSPForward(int id) +{ + m_FreeSPForwards.push_back(id); +} + int registerForward(const char *funcName, ForwardExecType et, ...) { int curParam = 0; @@ -214,7 +383,49 @@ int registerForward(const char *funcName, ForwardExecType et, ...) return g_forwards.registerForward(funcName, et, curParam, params); } -int executeForwards(int id, ...) +int registerSPForwardByName(AMX *amx, const char *funcName, ...) +{ + int curParam = 0; + va_list argptr; + va_start(argptr, funcName); + ForwardParam params[FORWARD_MAX_PARAMS]; + ForwardParam tmp; + while (true) + { + if (curParam == FORWARD_MAX_PARAMS) + break; + tmp = (ForwardParam)va_arg(argptr, int); + if (tmp == FP_DONE) + break; + params[curParam] = tmp; + ++curParam; + } + va_end(argptr); + return g_forwards.registerSPForward(funcName, amx, curParam, params); +} + +int registerSPForward(AMX *amx, int func, ...) +{ + int curParam = 0; + va_list argptr; + va_start(argptr, func); + ForwardParam params[FORWARD_MAX_PARAMS]; + ForwardParam tmp; + while (true) + { + if (curParam == FORWARD_MAX_PARAMS) + break; + tmp = (ForwardParam)va_arg(argptr, int); + if (tmp == FP_DONE) + break; + params[curParam] = tmp; + ++curParam; + } + va_end(argptr); + return g_forwards.registerSPForward(func, amx, curParam, params); +} + +cell executeForwards(int id, ...) { if (!g_forwards.isIdValid(id)) return -1; @@ -253,3 +464,8 @@ cell prepareCharArray(char *ptr, unsigned int size) { return g_forwards.prepareArray((void*)ptr, size, Type_Char); } + +void unregisterSPForward(int id) +{ + g_forwards.unregisterSPForward(id); +} \ No newline at end of file diff --git a/amxmodx/CForward.h b/amxmodx/CForward.h index fc78fa3d..38561848 100755 --- a/amxmodx/CForward.h +++ b/amxmodx/CForward.h @@ -29,13 +29,23 @@ * version. */ +/* + CForward.h + forwards + 1) normal forwards: called in all plugins + 2) single plugin (sp) forwards: called in one plugin + + The SP Forwards are handled differently because they are expected to be created / deleted + often, but the "normal" forwards are expected to be initialized at start up. + + Note about forward ids: + for normal forwards: << 1 + for sp forwards: ( << 1) | 1 +*/ + #ifndef FORWARD_H #define FORWARD_H -// ***************************************************** -// class CmdMngr -// ***************************************************** - const int FORWARD_MAX_PARAMS = 16; enum ForwardExecType @@ -57,6 +67,7 @@ enum ForwardParam FP_ARRAY, // array; use the return value of prepareArray. }; +// for prepareArray enum ForwardArrayElemType { Type_Cell = 0, @@ -65,12 +76,12 @@ enum ForwardArrayElemType struct ForwardPreparedArray { - void *ptr; ForwardArrayElemType type; unsigned int size; }; +// Normal forward class CForward { const char *m_FuncName; @@ -88,17 +99,53 @@ public: CForward(const char *name, ForwardExecType et, int numParams, const ForwardParam * paramTypes); CForward() { } // leaves everything unitialized - int execute(cell *params, ForwardPreparedArray *preparedArrays); + cell execute(cell *params, ForwardPreparedArray *preparedArrays); int getParamsNum() const { return m_NumParams; } + int getFuncsNum() const + { + return m_Funcs.size(); + } +}; + +// Single plugin forward +class CSPForward +{ + const char *m_FuncName; + int m_NumParams; + ForwardParam m_ParamTypes[FORWARD_MAX_PARAMS]; + AMX *m_Amx; + int m_Func; + bool m_HasFunc; +public: + CSPForward() { m_HasFunc = false; } + void Set(const char *funcName, AMX *amx, int numParams, const ForwardParam * paramTypes); + void Set(int func, AMX *amx, int numParams, const ForwardParam * paramTypes); + + cell execute(cell *params, ForwardPreparedArray *preparedArrays); + int getParamsNum() const + { + return m_NumParams; + } + int getFuncsNum() const + { + return (m_HasFunc) ? 1 : 0; + } }; class CForwardMngr { typedef CVector ForwardVec; + typedef CVector SPForwardVec; + typedef CVector FreeSPVec; // Free SP Forwards + ForwardVec m_Forwards; + + SPForwardVec m_SPForwards; + FreeSPVec m_FreeSPForwards; // so we don't have to free memory + ForwardPreparedArray m_TmpArrays[FORWARD_MAX_PARAMS]; // used by prepareArray int m_TmpArraysNum; public: @@ -109,18 +156,31 @@ public: { } // Interface + // Register normal forward int registerForward(const char *funcName, ForwardExecType et, int numParams, const ForwardParam *paramTypes); - int executeForwards(int id, cell *params); + // Register single plugin forward + int registerSPForward(const char *funcName, AMX *amx, int numParams, const ForwardParam * paramTypes); + int registerSPForward(int func, AMX *amx, int numParams, const ForwardParam * paramTypes); + // Unregister single plugin forward + void unregisterSPForward(int id); + // execute forward + cell executeForwards(int id, cell *params); void clear(); // delete all forwards - bool isIdValid(int id) const; - int getParamsNum(int id) const; - cell prepareArray(void *ptr, unsigned int size, ForwardArrayElemType type); + bool isIdValid(int id) const; // check whether forward id is valid + bool isSPForward(int id) const; // check whether forward is single plugin + int getParamsNum(int id) const; // get num of params of a forward + int getFuncsNum(int id) const; // get num of found functions of a forward + cell prepareArray(void *ptr, unsigned int size, ForwardArrayElemType type); // prepare array }; -// register forward +// (un)register forward int registerForward(const char *funcName, ForwardExecType et, ...); +int registerSPForwardByName(AMX *amx, const char *funcName, ...); +int registerSPForward(AMX *amx, int func, ...); +void unregisterSPForward(int id); + // execute forwards -int executeForwards(int id, ...); +cell executeForwards(int id, ...); // prepare array cell prepareCellArray(cell *ptr, unsigned int size); cell prepareCharArray(char *ptr, unsigned int size);