Fix bug in previous commit that caused temporary bindings to die early.

Instead of decrementing all their counters every time an event occurs,
only the counters of the bindings being executed will be decremented.

`_LuaTemporariesDied` is a small optimization to prevent unnecessary calls
to `UpdateTemporaryBindings`. It will only be called when a temporary
binding has run out of shots and needs to be cleaned up.
This commit is contained in:
Patman64
2014-12-19 00:46:50 -05:00
parent 7364facff6
commit ed8edf065c
2 changed files with 45 additions and 28 deletions

View File

@@ -20,8 +20,19 @@ extern "C"
class ElunaBind
{
public:
typedef std::pair<int, uint32> FunctionRefCounterPair; // (function reference, remaining calls counter)
typedef std::vector<FunctionRefCounterPair> FunctionRefVector;
struct Binding
{
int functionReference;
bool isTemporary;
uint32 remainingShots;
Binding(int funcRef, uint32 shots) :
functionReference(funcRef),
isTemporary(shots != 0),
remainingShots(shots)
{}
};
typedef std::vector<Binding> FunctionRefVector;
typedef UNORDERED_MAP<int, FunctionRefVector> EventToFunctionsMap;
Eluna& E;
@@ -57,7 +68,7 @@ public:
for (EventToFunctionsMap::iterator itr = Bindings.begin(); itr != Bindings.end(); ++itr)
{
for (FunctionRefVector::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
luaL_unref(E.L, LUA_REGISTRYINDEX, (*it).first);
luaL_unref(E.L, LUA_REGISTRYINDEX, (*it).functionReference);
itr->second.clear();
}
Bindings.clear();
@@ -69,17 +80,10 @@ public:
{
for (FunctionRefVector::iterator it = itr->second.begin(); it != itr->second.end();)
{
uint32 counter = (*it).second;
if (counter > 1)
Binding &b = (*it);
if (b.isTemporary && b.remainingShots == 0)
{
counter--;
(*it).second = counter;
it++;
}
else if (counter == 1)
{
luaL_unref(E.L, LUA_REGISTRYINDEX, (*it).first);
luaL_unref(E.L, LUA_REGISTRYINDEX, b.functionReference);
it = itr->second.erase(it);
}
else
@@ -102,7 +106,7 @@ public:
void Insert(int eventId, int funcRef, uint32 shots) // Inserts a new registered event
{
Bindings[eventId].push_back(std::make_pair(funcRef, shots));
Bindings[eventId].push_back(Binding(funcRef, shots));
}
// Checks if there are events for ID
@@ -136,7 +140,7 @@ public:
for (EventToFunctionsMap::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).first);
luaL_unref(E.L, LUA_REGISTRYINDEX, (*i).functionReference);
it->second.clear();
}
itr->second.clear();
@@ -152,16 +156,10 @@ public:
{
for (FunctionRefVector::iterator i = it->second.begin(); i != it->second.end();)
{
uint32 counter = (*i).second;
if (counter > 1)
Binding &b = (*i);
if (b.isTemporary && b.remainingShots == 0)
{
counter--;
(*i).second = counter;
i++;
}
else if (counter == 1)
{
luaL_unref(E.L, LUA_REGISTRYINDEX, (*i).first);
luaL_unref(E.L, LUA_REGISTRYINDEX, b.functionReference);
i = it->second.erase(i);
}
else
@@ -195,7 +193,7 @@ public:
void Insert(uint32 entryId, int eventId, int funcRef, uint32 shots) // Inserts a new registered event
{
Bindings[entryId][eventId].push_back(std::make_pair(funcRef, shots));
Bindings[entryId][eventId].push_back(Binding(funcRef, shots));
}
// Returns true if the entry has registered binds

View File

@@ -51,8 +51,17 @@ using namespace HookMgr;
const char* _LuaBindType = this->BINDMAP->groupName; \
uint32 _LuaEvent = EVENT; \
int _LuaStackTop = lua_gettop(L); \
bool _LuaTemporariesDied = false; \
for (size_t i = 0; i < this->BINDMAP->Bindings[_LuaEvent].size(); ++i) \
lua_rawgeti(L, LUA_REGISTRYINDEX, (this->BINDMAP->Bindings[_LuaEvent][i].first)); \
{ \
if (this->BINDMAP->Bindings[_LuaEvent][i].isTemporary) \
{ \
this->BINDMAP->Bindings[_LuaEvent][i].remainingShots--; \
if (this->BINDMAP->Bindings[_LuaEvent][i].remainingShots == 0) \
_LuaTemporariesDied = true; \
} \
lua_rawgeti(L, LUA_REGISTRYINDEX, (this->BINDMAP->Bindings[_LuaEvent][i].functionReference)); \
} \
int _LuaFuncTop = lua_gettop(L); \
int _LuaFuncCount = _LuaFuncTop-_LuaStackTop; \
Eluna::Push(L, _LuaEvent);
@@ -86,8 +95,17 @@ using namespace HookMgr;
const char* _LuaBindType = _LuaBind->groupName; \
uint32 _LuaEvent = EVENT; \
int _LuaStackTop = lua_gettop(L); \
bool _LuaTemporariesDied = false; \
for (size_t i = 0; i < this->BINDMAP->Bindings[ENTRY][_LuaEvent].size(); ++i) \
lua_rawgeti(L, LUA_REGISTRYINDEX, (this->BINDMAP->Bindings[ENTRY][_LuaEvent][i].first)); \
{ \
if (this->BINDMAP->Bindings[ENTRY][_LuaEvent][i].isTemporary) \
{ \
this->BINDMAP->Bindings[ENTRY][_LuaEvent][i].remainingShots--; \
if (this->BINDMAP->Bindings[ENTRY][_LuaEvent][i].remainingShots == 0) \
_LuaTemporariesDied = true; \
} \
lua_rawgeti(L, LUA_REGISTRYINDEX, (this->BINDMAP->Bindings[ENTRY][_LuaEvent][i].functionReference)); \
} \
int _LuaFuncTop = lua_gettop(L); \
int _LuaFuncCount = _LuaFuncTop-_LuaStackTop; \
Eluna::Push(L, _LuaEvent);
@@ -123,6 +141,7 @@ using namespace HookMgr;
ELUNA_LOG_ERROR("[Eluna]: Ending event %u for %s, stack top was %i and was supposed to be between %i and %i. Report to devs", _LuaEvent, _LuaBindType, lua_gettop(L), _LuaStackTop, _LuaStackTop + _LuaFuncCount * _LuaReturnValues); \
} \
lua_settop(L, _LuaStackTop); \
if (_LuaTemporariesDied) \
_LuaBind->UpdateTemporaryBindings(); \
if (!this->event_level) \
this->InvalidateObjects(); // Invalidate objects on outermost hook call