From 3ff4c5f26ee7d96449d37d8448cd2b3d311667ed Mon Sep 17 00:00:00 2001 From: Patman64 Date: Mon, 15 Dec 2014 02:16:37 -0500 Subject: [PATCH] Allow multiple callbacks for the same entry/event combo. The callbacks will be called in reverse-order of registration. --- ElunaBinding.h | 44 +++++++++++++++++--------------------------- HookMgr.cpp | 25 +++++++++++++++++++------ 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/ElunaBinding.h b/ElunaBinding.h index bb5b271..c0eafdb 100644 --- a/ElunaBinding.h +++ b/ElunaBinding.h @@ -93,7 +93,8 @@ template class EntryBind : public ElunaBind { public: - typedef std::map ElunaBindingMap; + typedef std::vector FunctionRefVector; + typedef std::map ElunaBindingMap; typedef UNORDERED_MAP ElunaEntryMap; EntryBind(const char* bindGroupName, Eluna& _E) : ElunaBind(bindGroupName, _E) @@ -105,8 +106,12 @@ public: { for (ElunaEntryMap::iterator itr = Bindings.begin(); itr != Bindings.end(); ++itr) { - for (ElunaBindingMap::const_iterator it = itr->second.begin(); it != itr->second.end(); ++it) - luaL_unref(E.L, LUA_REGISTRYINDEX, it->second); + for (ElunaBindingMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it) + { + for (FunctionRefVector::iterator i = it->second.begin(); i != it->second.end(); ++i) + luaL_unref(E.L, LUA_REGISTRYINDEX, (*i)); + it->second.clear(); + } itr->second.clear(); } Bindings.clear(); @@ -114,27 +119,7 @@ public: void Insert(uint32 entryId, int eventId, int funcRef) // Inserts a new registered event { - if (Bindings[entryId][eventId]) - { - luaL_unref(E.L, LUA_REGISTRYINDEX, funcRef); // free the unused ref - luaL_error(E.L, "A function is already registered for entry (%d) event (%d)", entryId, eventId); - } - else - Bindings[entryId][eventId] = funcRef; - } - - // Gets the function ref of an entry for an event - int GetBind(uint32 entryId, T eventId) const - { - if (Bindings.empty()) - return 0; - ElunaEntryMap::const_iterator itr = Bindings.find(entryId); - if (itr == Bindings.end() || itr->second.empty()) - return 0; - ElunaBindingMap::const_iterator itr2 = itr->second.find(eventId); - if (itr2 == itr->second.end()) - return 0; - return itr2->second; + Bindings[entryId][eventId].push_back(funcRef); } // Gets the binding std::map containing all registered events with the function refs for the entry @@ -150,14 +135,19 @@ public: } // Returns true if the entry has registered binds - bool HasBinds(uint32 entryId) const + bool HasEvents(uint32 entryId, int eventId) const { if (Bindings.empty()) return false; - return Bindings.find(entryId) != Bindings.end(); + + ElunaEntryMap::const_iterator itr = Bindings.find(entryId); + if (itr == Bindings.end()) + return false; + + return itr->second.find(eventId) != itr->second.end(); } - ElunaEntryMap Bindings; // Binding store Bindings[entryId][eventId] = funcRef; + ElunaEntryMap Bindings; // Binding store Bindings[entryId][eventId] = {funcRef}; }; #endif diff --git a/HookMgr.cpp b/HookMgr.cpp index d8bfb53..6ec4e01 100644 --- a/HookMgr.cpp +++ b/HookMgr.cpp @@ -29,7 +29,7 @@ using namespace HookMgr; /* * Call model for EventBind: - * + * * // Begin the call if should * EVENT_BEGIN(bindmap, eventid, return returnvalue); * // push arguments @@ -78,22 +78,35 @@ using namespace HookMgr; // RET is a return statement #define ENTRY_BEGIN(BINDMAP, ENTRY, EVENT, RET) \ - int _Luabind = this->BINDMAP->GetBind(ENTRY, EVENT); \ - if (!_Luabind) \ + if (!BINDMAP->HasEvents(ENTRY, EVENT)) \ RET; \ lua_State* L = this->L; \ const char* _LuaBindType = this->BINDMAP->groupName; \ uint32 _LuaEvent = EVENT; \ int _LuaStackTop = lua_gettop(L); \ - lua_rawgeti(L, LUA_REGISTRYINDEX, _Luabind); \ + for (size_t i = 0; i < this->BINDMAP->Bindings[ENTRY][_LuaEvent].size(); ++i) \ + lua_rawgeti(L, LUA_REGISTRYINDEX, (this->BINDMAP->Bindings[ENTRY][_LuaEvent][i])); \ int _LuaFuncTop = lua_gettop(L); \ int _LuaFuncCount = _LuaFuncTop-_LuaStackTop; \ Eluna::Push(L, _LuaEvent); #define ENTRY_EXECUTE(RETVALS) \ int _LuaReturnValues = RETVALS; \ - int _LuaParams = lua_gettop(L) - _LuaStackTop - 1; \ - Eluna::ExecuteCall(_LuaParams, _LuaReturnValues); + int _LuaParams = lua_gettop(L) - _LuaFuncTop; \ + if (_LuaParams < 2) \ + { \ + ELUNA_LOG_ERROR("[Eluna]: Executing event %u for %s, params was %i. Report to devs", _LuaEvent, _LuaBindType, _LuaParams); \ + } \ + for (int j = _LuaFuncTop-_LuaStackTop; j > 0; --j) \ + { \ + for (int i = 0; i <= _LuaParams; ++i) \ + lua_pushvalue(L, _LuaFuncTop+i); \ + Eluna::ExecuteCall(_LuaParams, _LuaReturnValues); \ + lua_remove(L, _LuaFuncTop--); \ + } \ + for (int i = _LuaParams; i > 0; --i) \ + if (!lua_isnone(L, i)) \ + lua_remove(L, i); #define FOR_RETS(IT) \ for (int IT = _LuaStackTop + 1; IT <= lua_gettop(L); ++IT)