Eluna made hook stores use templates to verify right bind store used to prevent human errors. Also fixed an error this system brought up :)

This commit is contained in:
Rochet2
2014-06-04 19:55:25 +03:00
committed by Foereaper
parent d7a07239e9
commit 77ff26ac8e
4 changed files with 373 additions and 357 deletions

View File

@@ -8,6 +8,8 @@
#include "LuaEngine.h"
#include "Includes.h"
using namespace HookMgr;
/*
Call model for EventBind:
@@ -30,25 +32,26 @@ ENDCALL();
lua_State* L = sEluna->L; \
uint32 _LuaEvent = EVENT; \
int _LuaStackTop = lua_gettop(L); \
EventBind* _LuaBindMap = sEluna->BINDMAP; \
for (int i = 0; i < sEluna->BINDMAP->Bindings[EVENT].size(); ++i) \
lua_rawgeti(L, LUA_REGISTRYINDEX, (sEluna->BINDMAP->Bindings[EVENT][i])); \
int _LuaFuncTop = lua_gettop(L); \
Eluna::Push(L, _LuaEvent);
// use LUA_MULTRET for multiple return values
// return values will be at top of stack if any
#define EVENT_EXECUTE(RETVALS) \
int _LuaReturnValues = RETVALS; \
int _LuaParams = lua_gettop(L) - _LuaStackTop; \
int _LuaParams = lua_gettop(L) - _LuaFuncTop; \
if (_LuaParams < 1) \
{ \
ELUNA_LOG_ERROR("[Eluna]: Executing event %u, params was %i. Report to devs", _LuaEvent, _LuaParams); \
} \
for (EventBind::ElunaBindingMap::const_iterator it = _LuaBindMap->Bindings[_LuaEvent].begin(); it != _LuaBindMap->Bindings[_LuaEvent].end(); ++it) \
for (int j = _LuaFuncTop-_LuaStackTop; j > 0; --j) \
{ \
lua_rawgeti(L, LUA_REGISTRYINDEX, (*it)); \
int stacktop = lua_gettop(L); \
for (int i = stacktop - _LuaParams; i < stacktop; ++i) \
lua_pushvalue(L, i); \
for (int i = 0; i <= _LuaParams; ++i) \
lua_pushvalue(L, _LuaFuncTop+i); \
Eluna::ExecuteCall(L, _LuaParams, _LuaReturnValues); \
lua_remove(L, _LuaFuncTop--); \
} \
for (int i = _LuaParams; i > 0; --i) \
if (!lua_isnone(L, i)) \
@@ -173,7 +176,7 @@ void Eluna::OnPacketSendAny(Player* player, WorldPacket& packet, bool& result)
}
void Eluna::OnPacketSendOne(Player* player, WorldPacket& packet, bool& result)
{
ENTRY_BEGIN(PacketEventBindings, OpcodesList(packet.GetOpcode()), SERVER_EVENT_ON_PACKET_SEND, return);
ENTRY_BEGIN(PacketEventBindings, OpcodesList(packet.GetOpcode()), PACKET_EVENT_ON_PACKET_SEND, return);
Push(L, new WorldPacket(packet));
Push(L, player);
ENTRY_EXECUTE(2);
@@ -224,7 +227,7 @@ void Eluna::OnPacketReceiveAny(Player* player, WorldPacket& packet, bool& result
}
void Eluna::OnPacketReceiveOne(Player* player, WorldPacket& packet, bool& result)
{
ENTRY_BEGIN(PacketEventBindings, OpcodesList(packet.GetOpcode()), SERVER_EVENT_ON_PACKET_RECEIVE, return);
ENTRY_BEGIN(PacketEventBindings, OpcodesList(packet.GetOpcode()), PACKET_EVENT_ON_PACKET_RECEIVE, return);
Push(L, new WorldPacket(packet));
Push(L, player);
ENTRY_EXECUTE(2);
@@ -473,7 +476,7 @@ bool Eluna::OnCommand(Player* player, const char* text)
}
}
bool result = true;
EVENT_BEGIN(ServerEventBindings, PLAYER_EVENT_ON_COMMAND, return result);
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_COMMAND, return result);
Push(L, player);
Push(L, fullcmd);
EVENT_EXECUTE(1);

View File

@@ -7,6 +7,8 @@
#ifndef LUAHOOKS_H
#define LUAHOOKS_H
namespace HookMgr
{
enum RegisterTypes
{
REGTYPE_PACKET,
@@ -26,9 +28,14 @@ enum RegisterTypes
};
// RegisterPacketEvent(Opcode, event, function)
// SERVER_EVENT_ON_PACKET_RECEIVE = 5, // (event, packet, player) - Player only if accessible. Can return false or a new packet
// SERVER_EVENT_ON_PACKET_RECEIVE_UNKNOWN = 6, // Not Implemented
// SERVER_EVENT_ON_PACKET_SEND = 7, // (event, packet, player) - Player only if accessible. Can return false or a new packet
enum PacketEvents
{
PACKET_EVENT_ON_PACKET_RECEIVE = 5, // (event, packet, player) - Player only if accessible. Can return false or a new packet
PACKET_EVENT_ON_PACKET_RECEIVE_UNKNOWN = 6, // Not Implemented
PACKET_EVENT_ON_PACKET_SEND = 7, // (event, packet, player) - Player only if accessible. Can return false or a new packet
PACKET_EVENT_COUNT
};
// RegisterServerEvent(EventId, function)
enum ServerEvents
@@ -134,7 +141,7 @@ enum PlayerEvents
};
// RegisterGuildEvent(eventId, function)
enum GuildEventTypes
enum GuildEvents
{
// Guild
GUILD_EVENT_ON_ADD_MEMBER = 1, // (event, guild, player, rank)
@@ -258,4 +265,5 @@ enum GossipEvents
GOSSIP_EVENT_ON_SELECT = 2, // (event, player, object, sender, intid, code, menu_id) - Object is the Creature/GameObject/Item/Player, menu_id is only for player gossip
GOSSIP_EVENT_COUNT
};
};
#endif

View File

@@ -40,6 +40,7 @@ void Eluna::Initialize()
void Eluna::Uninitialize()
{
delete GEluna;
scripts.clear();
}
void Eluna::ReloadEluna()
@@ -53,20 +54,20 @@ L(luaL_newstate()),
m_EventMgr(new EventMgr(*this)),
ServerEventBindings(new EventBind(*this)),
PlayerEventBindings(new EventBind(*this)),
GuildEventBindings(new EventBind(*this)),
GroupEventBindings(new EventBind(*this)),
VehicleEventBindings(new EventBind(*this)),
ServerEventBindings(new EventBind<HookMgr::ServerEvents>(*this)),
PlayerEventBindings(new EventBind<HookMgr::PlayerEvents>(*this)),
GuildEventBindings(new EventBind<HookMgr::GuildEvents>(*this)),
GroupEventBindings(new EventBind<HookMgr::GroupEvents>(*this)),
VehicleEventBindings(new EventBind<HookMgr::VehicleEvents>(*this)),
PacketEventBindings(new EntryBind(*this)),
CreatureEventBindings(new EntryBind(*this)),
CreatureGossipBindings(new EntryBind(*this)),
GameObjectEventBindings(new EntryBind(*this)),
GameObjectGossipBindings(new EntryBind(*this)),
ItemEventBindings(new EntryBind(*this)),
ItemGossipBindings(new EntryBind(*this)),
playerGossipBindings(new EntryBind(*this))
PacketEventBindings(new EntryBind<HookMgr::PacketEvents>(*this)),
CreatureEventBindings(new EntryBind<HookMgr::CreatureEvents>(*this)),
CreatureGossipBindings(new EntryBind<HookMgr::GossipEvents>(*this)),
GameObjectEventBindings(new EntryBind<HookMgr::GameObjectEvents>(*this)),
GameObjectGossipBindings(new EntryBind<HookMgr::GossipEvents>(*this)),
ItemEventBindings(new EntryBind<HookMgr::ItemEvents>(*this)),
ItemGossipBindings(new EntryBind<HookMgr::GossipEvents>(*this)),
playerGossipBindings(new EntryBind<HookMgr::GossipEvents>(*this))
{
// open base lua
luaL_openlibs(L);
@@ -525,56 +526,63 @@ void Eluna::Register(uint8 regtype, uint32 id, uint32 evt, int functionRef)
{
switch (regtype)
{
case REGTYPE_PACKET:
if (evt < NUM_MSG_TYPES)
{
PacketEventBindings->Insert(id, evt, functionRef);
return;
}
break;
case REGTYPE_SERVER:
if (evt < SERVER_EVENT_COUNT)
case HookMgr::REGTYPE_SERVER:
if (evt < HookMgr::SERVER_EVENT_COUNT)
{
ServerEventBindings->Insert(evt, functionRef);
return;
}
break;
case REGTYPE_PLAYER:
if (evt < PLAYER_EVENT_COUNT)
case HookMgr::REGTYPE_PLAYER:
if (evt < HookMgr::PLAYER_EVENT_COUNT)
{
PlayerEventBindings->Insert(evt, functionRef);
return;
}
break;
case REGTYPE_GUILD:
if (evt < GUILD_EVENT_COUNT)
case HookMgr::REGTYPE_GUILD:
if (evt < HookMgr::GUILD_EVENT_COUNT)
{
GuildEventBindings->Insert(evt, functionRef);
return;
}
break;
case REGTYPE_GROUP:
if (evt < GROUP_EVENT_COUNT)
case HookMgr::REGTYPE_GROUP:
if (evt < HookMgr::GROUP_EVENT_COUNT)
{
GroupEventBindings->Insert(evt, functionRef);
return;
}
break;
case REGTYPE_VEHICLE:
if (evt < VEHICLE_EVENT_COUNT)
case HookMgr::REGTYPE_VEHICLE:
if (evt < HookMgr::VEHICLE_EVENT_COUNT)
{
VehicleEventBindings->Insert(evt, functionRef);
return;
}
break;
case REGTYPE_CREATURE:
if (evt < CREATURE_EVENT_COUNT)
case HookMgr::REGTYPE_PACKET:
if (evt < HookMgr::PACKET_EVENT_COUNT)
{
if (id >= NUM_MSG_TYPES)
{
luaL_unref(L, LUA_REGISTRYINDEX, functionRef);
luaL_error(L, "Couldn't find a creature with (ID: %d)!", id);
return;
}
PacketEventBindings->Insert(id, evt, functionRef);
return;
}
break;
case HookMgr::REGTYPE_CREATURE:
if (evt < HookMgr::CREATURE_EVENT_COUNT)
{
if (!eObjectMgr->GetCreatureTemplate(id))
{
@@ -588,8 +596,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint32 evt, int functionRef)
}
break;
case REGTYPE_CREATURE_GOSSIP:
if (evt < GOSSIP_EVENT_COUNT)
case HookMgr::REGTYPE_CREATURE_GOSSIP:
if (evt < HookMgr::GOSSIP_EVENT_COUNT)
{
if (!eObjectMgr->GetCreatureTemplate(id))
{
@@ -603,8 +611,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint32 evt, int functionRef)
}
break;
case REGTYPE_GAMEOBJECT:
if (evt < GAMEOBJECT_EVENT_COUNT)
case HookMgr::REGTYPE_GAMEOBJECT:
if (evt < HookMgr::GAMEOBJECT_EVENT_COUNT)
{
if (!eObjectMgr->GetGameObjectTemplate(id))
{
@@ -618,8 +626,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint32 evt, int functionRef)
}
break;
case REGTYPE_GAMEOBJECT_GOSSIP:
if (evt < GOSSIP_EVENT_COUNT)
case HookMgr::REGTYPE_GAMEOBJECT_GOSSIP:
if (evt < HookMgr::GOSSIP_EVENT_COUNT)
{
if (!eObjectMgr->GetGameObjectTemplate(id))
{
@@ -633,8 +641,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint32 evt, int functionRef)
}
break;
case REGTYPE_ITEM:
if (evt < ITEM_EVENT_COUNT)
case HookMgr::REGTYPE_ITEM:
if (evt < HookMgr::ITEM_EVENT_COUNT)
{
if (!eObjectMgr->GetItemTemplate(id))
{
@@ -648,8 +656,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint32 evt, int functionRef)
}
break;
case REGTYPE_ITEM_GOSSIP:
if (evt < GOSSIP_EVENT_COUNT)
case HookMgr::REGTYPE_ITEM_GOSSIP:
if (evt < HookMgr::GOSSIP_EVENT_COUNT)
{
if (!eObjectMgr->GetItemTemplate(id))
{
@@ -663,8 +671,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint32 evt, int functionRef)
}
break;
case REGTYPE_PLAYER_GOSSIP:
if (evt < GOSSIP_EVENT_COUNT)
case HookMgr::REGTYPE_PLAYER_GOSSIP:
if (evt < HookMgr::GOSSIP_EVENT_COUNT)
{
playerGossipBindings->Insert(id, evt, functionRef);
return;
@@ -675,53 +683,6 @@ void Eluna::Register(uint8 regtype, uint32 id, uint32 evt, int functionRef)
luaL_error(L, "Unknown event type (regtype %d, id %d, event %d)", regtype, id, evt);
}
void EventBind::Clear()
{
for (ElunaEntryMap::iterator itr = Bindings.begin(); itr != Bindings.end(); ++itr)
{
for (ElunaBindingMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
luaL_unref(E.L, LUA_REGISTRYINDEX, (*it));
itr->second.clear();
}
Bindings.clear();
}
void EventBind::Insert(int eventId, int funcRef)
{
Bindings[eventId].push_back(funcRef);
}
bool EventBind::HasEvents(int eventId) const
{
if (Bindings.empty())
return false;
if (Bindings.find(eventId) == Bindings.end())
return false;
return true;
}
void EntryBind::Clear()
{
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);
itr->second.clear();
}
Bindings.clear();
}
void EntryBind::Insert(uint32 entryId, int eventId, int funcRef)
{
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;
}
EventMgr::LuaEvent::LuaEvent(Eluna& _E, EventProcessor* _events, int _funcRef, uint32 _delay, uint32 _calls, Object* _obj):
E(_E), events(_events), funcRef(_funcRef), delay(_delay), calls(_calls), obj(_obj)
{

View File

@@ -20,6 +20,7 @@ extern "C"
#include <ace/Singleton.h>
#include <ace/Atomic_Op.h>
// enums & singletons
#include "HookMgr.h"
#ifdef MANGOS
#include "AccountMgr.h"
#include "Config/Config.h"
@@ -334,10 +335,12 @@ struct EventMgr
}
};
template<typename T>
struct EventBind
{
typedef std::vector<int> ElunaBindingMap;
typedef std::map<int, ElunaBindingMap> ElunaEntryMap;
typedef std::map<T, ElunaBindingMap> ElunaEntryMap;
Eluna& E;
EventBind(Eluna& _E): E(_E)
@@ -349,11 +352,25 @@ struct EventBind
Clear();
}
void Clear(); // unregisters all registered functions and clears all registered events from the bind std::maps (reset)
void Insert(int eventId, int funcRef); // Inserts a new registered event
// unregisters all registered functions and clears all registered events from the bind std::maps (reset)
void Clear()
{
for (ElunaEntryMap::iterator itr = Bindings.begin(); itr != Bindings.end(); ++itr)
{
for (ElunaBindingMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
luaL_unref(E.L, LUA_REGISTRYINDEX, (*it));
itr->second.clear();
}
Bindings.clear();
}
void Insert(int eventId, int funcRef) // Inserts a new registered event
{
Bindings[eventId].push_back(funcRef);
}
// Gets the binding std::map containing all registered events with the function refs for the entry
ElunaBindingMap* GetBindMap(int eventId)
ElunaBindingMap* GetBindMap(T eventId)
{
if (Bindings.empty())
return NULL;
@@ -365,15 +382,24 @@ struct EventBind
}
// Checks if there are events for ID
bool HasEvents(int eventId) const;
bool HasEvents(T eventId) const
{
if (Bindings.empty())
return false;
if (Bindings.find(eventId) == Bindings.end())
return false;
return true;
}
ElunaEntryMap Bindings; // Binding store Bindings[eventId] = {funcRef};
};
template<typename T>
struct EntryBind
{
typedef std::map<int, int> ElunaBindingMap;
typedef std::map<T, int> ElunaBindingMap;
typedef UNORDERED_MAP<uint32, ElunaBindingMap> ElunaEntryMap;
Eluna& E;
EntryBind(Eluna& _E): E(_E)
@@ -385,11 +411,30 @@ struct EntryBind
Clear();
}
void Clear(); // unregisters all registered functions and clears all registered events from the bind std::maps (reset)
void Insert(uint32 entryId, int eventId, int funcRef); // Inserts a new registered event
void Clear() // unregisters all registered functions and clears all registered events from the bind std::maps (reset)
{
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);
itr->second.clear();
}
Bindings.clear();
}
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, int eventId) const
int GetBind(uint32 entryId, T eventId) const
{
if (Bindings.empty())
return 0;
@@ -445,21 +490,20 @@ public:
EventMgr* m_EventMgr;
// Use templates for EventBind
EventBind* ServerEventBindings;
EventBind* PlayerEventBindings;
EventBind* GuildEventBindings;
EventBind* GroupEventBindings;
EventBind* VehicleEventBindings;
EventBind<HookMgr::ServerEvents>* ServerEventBindings;
EventBind<HookMgr::PlayerEvents>* PlayerEventBindings;
EventBind<HookMgr::GuildEvents>* GuildEventBindings;
EventBind<HookMgr::GroupEvents>* GroupEventBindings;
EventBind<HookMgr::VehicleEvents>* VehicleEventBindings;
EntryBind* PacketEventBindings;
EntryBind* CreatureEventBindings;
EntryBind* CreatureGossipBindings;
EntryBind* GameObjectEventBindings;
EntryBind* GameObjectGossipBindings;
EntryBind* ItemEventBindings;
EntryBind* ItemGossipBindings;
EntryBind* playerGossipBindings;
EntryBind<HookMgr::PacketEvents>* PacketEventBindings;
EntryBind<HookMgr::CreatureEvents>* CreatureEventBindings;
EntryBind<HookMgr::GossipEvents>* CreatureGossipBindings;
EntryBind<HookMgr::GameObjectEvents>* GameObjectEventBindings;
EntryBind<HookMgr::GossipEvents>* GameObjectGossipBindings;
EntryBind<HookMgr::ItemEvents>* ItemEventBindings;
EntryBind<HookMgr::GossipEvents>* ItemGossipBindings;
EntryBind<HookMgr::GossipEvents>* playerGossipBindings;
Eluna();
~Eluna();