diff --git a/BattleGroundHooks.cpp b/BattleGroundHooks.cpp index 5806c54..1789a19 100644 --- a/BattleGroundHooks.cpp +++ b/BattleGroundHooks.cpp @@ -4,64 +4,55 @@ * Please see the included DOCS/LICENSE.md for more information */ -#ifndef _BATTLEGROUND_HOOKS_H -#define _BATTLEGROUND_HOOKS_H - #include "Hooks.h" #include "HookHelpers.h" #include "LuaEngine.h" -#include "ElunaBinding.h" +#include "BindingMap.h" #include "ElunaTemplate.h" using namespace Hooks; +#define START_HOOK(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!BGEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + void Eluna::OnBGStart(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) { - if (!BGEventBindings->HasEvents(BG_EVENT_ON_START)) - return; - - LOCK_ELUNA; + START_HOOK(BG_EVENT_ON_START); Push(bg); Push(bgId); Push(instanceId); - CallAllFunctions(BGEventBindings, BG_EVENT_ON_START); + CallAllFunctions(BGEventBindings, key); } void Eluna::OnBGEnd(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId, Team winner) { - if (!BGEventBindings->HasEvents(BG_EVENT_ON_END)) - return; - - LOCK_ELUNA; + START_HOOK(BG_EVENT_ON_END); Push(bg); Push(bgId); Push(instanceId); Push(winner); - CallAllFunctions(BGEventBindings, BG_EVENT_ON_END); + CallAllFunctions(BGEventBindings, key); } void Eluna::OnBGCreate(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) { - if (!BGEventBindings->HasEvents(BG_EVENT_ON_CREATE)) - return; - - LOCK_ELUNA; + START_HOOK(BG_EVENT_ON_CREATE); Push(bg); Push(bgId); Push(instanceId); - CallAllFunctions(BGEventBindings, BG_EVENT_ON_CREATE); + CallAllFunctions(BGEventBindings, key); } void Eluna::OnBGDestroy(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) { - if (!BGEventBindings->HasEvents(BG_EVENT_ON_PRE_DESTROY)) - return; - - LOCK_ELUNA; + START_HOOK(BG_EVENT_ON_PRE_DESTROY); Push(bg); Push(bgId); Push(instanceId); - CallAllFunctions(BGEventBindings, BG_EVENT_ON_PRE_DESTROY); + CallAllFunctions(BGEventBindings, key); } - -#endif // _BATTLEGROUND_HOOKS_H diff --git a/BindingMap.h b/BindingMap.h new file mode 100644 index 0000000..94c4e72 --- /dev/null +++ b/BindingMap.h @@ -0,0 +1,344 @@ +/* +* Copyright (C) 2010 - 2015 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef _BINDING_MAP_H +#define _BINDING_MAP_H + +#include +#include "Common.h" +#include "ElunaUtility.h" + +extern "C" +{ +#include "lua.h" +#include "lauxlib.h" +}; + + +/* + * A set of bindings from keys of type `K` to Lua references. + */ +template +class BindingMap : public ElunaUtil::RWLockable +{ +private: + lua_State* L; + uint64 maxBindingID; + + struct Binding + { + uint64 id; + int functionReference; + uint32 remainingShots; + lua_State* L; + + Binding(lua_State* L, uint64 id, int functionReference, uint32 remainingShots) : + L(L), + id(id), + functionReference(functionReference), + remainingShots(remainingShots) + {} + + ~Binding() + { + luaL_unref(L, LUA_REGISTRYINDEX, functionReference); + } + }; + + typedef std::vector< std::unique_ptr > BindingList; + + std::unordered_map bindings; + /* + * This table is for fast removal of bindings by ID. + * + * Instead of having to look through (potentially) every BindingList to find + * the Binding with the right ID, this allows you to go directly to the + * BindingList that might have the Binding with that ID. + * + * However, you must be careful not to store pointers to BindingLists + * that no longer exist (see `void Clear(const K& key)` implementation). + */ + std::unordered_map id_lookup_table; + +public: + BindingMap(lua_State* L) : + L(L), + maxBindingID(0) + { + } + + /* + * Insert a new binding from `key` to `ref`, which lasts for `shots`-many pushes. + * + * If `shots` is 0, it will never automatically expire, but can still be + * removed with `Clear` or `Remove`. + */ + uint64 Insert(const K& key, int ref, uint32 shots) + { + WriteGuard guard(GetLock()); + + uint64 id = (++maxBindingID); + BindingList& list = bindings[key]; + list.push_back(std::unique_ptr(new Binding(L, id, ref, shots))); + id_lookup_table[id] = &list; + return id; + } + + /* + * Clear all bindings for `key`. + */ + void Clear(const K& key) + { + WriteGuard guard(GetLock()); + + if (bindings.empty()) + return; + + auto iter = bindings.find(key); + if (iter == bindings.end()) + return; + + BindingList& list = iter->second; + + // Remove all pointers to `list` from `id_lookup_table`. + for (auto i = list.begin(); i != list.end(); ++i) + { + std::unique_ptr& binding = *i; + id_lookup_table.erase(binding->id); + } + + bindings.erase(key); + } + + /* + * Clear all bindings for all keys. + */ + void Clear() + { + WriteGuard guard(GetLock()); + + if (bindings.empty()) + return; + + id_lookup_table.clear(); + bindings.clear(); + } + + /* + * Remove a specific binding identified by `id`. + * + * If `id` in invalid, nothing is removed. + */ + void Remove(uint64 id) + { + WriteGuard guard(GetLock()); + + auto iter = id_lookup_table.find(id); + if (iter == id_lookup_table.end()) + return; + + BindingList* list = iter->second; + auto i = list->begin(); + + for (; i != list->end(); ++i) + { + std::unique_ptr& binding = *i; + if (binding->id == id) + break; + } + + if (i != list->end()) + list->erase(i); + + // Unconditionally erase the ID in the lookup table because + // it was either already invalid, or it's no longer valid. + id_lookup_table.erase(id); + } + + /* + * Check whether `key` has any bindings. + */ + bool HasBindingsFor(const K& key) + { + ReadGuard guard(GetLock()); + + if (bindings.empty()) + return false; + + auto result = bindings.find(key); + if (result == bindings.end()) + return false; + + BindingList& list = result->second; + return !list.empty(); + } + + /* + * Push all Lua references for `key` onto the stack. + */ + void PushRefsFor(const K& key) + { + WriteGuard guard(GetLock()); + + if (bindings.empty()) + return; + + auto result = bindings.find(key); + if (result == bindings.end()) + return; + + BindingList& list = result->second; + for (auto i = list.begin(); i != list.end();) + { + std::unique_ptr& binding = (*i); + auto i_prev = (i++); + + lua_rawgeti(L, LUA_REGISTRYINDEX, binding->functionReference); + + if (binding->remainingShots > 0) + { + binding->remainingShots -= 1; + + if (binding->remainingShots == 0) + { + id_lookup_table.erase(binding->id); + list.erase(i_prev); + } + } + } + } +}; + + +/* + * A `BindingMap` key type for simple event ID bindings + * (ServerEvents, GuildEvents, etc.). + */ +template +struct EventKey +{ + T event_id; + + EventKey(T event_id) : + event_id(event_id) + {} +}; + +/* + * A `BindingMap` key type for event ID/Object entry ID bindings + * (CreatureEvents, GameObjectEvents, etc.). + */ +template +struct EntryKey : public EventKey +{ + uint32 entry; + + EntryKey(T event_type, uint32 entry) : + EventKey(event_type), + entry(entry) + {} +}; + +/* + * A `BindingMap` key type for event ID/unique Object bindings + * (currently just CreatureEvents). + */ +template +struct UniqueObjectKey : public EventKey +{ + uint64 guid; + uint32 instance_id; + + UniqueObjectKey(T event_type, uint64 guid, uint32 instance_id) : + EventKey(event_type), + guid(guid), + instance_id(instance_id) + {} +}; + + +/* + * Implementations of various std functions on the above key types, + * so that they can be used within an unordered_map. + */ +namespace std +{ + template + struct equal_to < EventKey > + { + bool operator()(EventKey const& lhs, EventKey const& rhs) const + { + return lhs.event_id == rhs.event_id; + } + }; + + template + struct equal_to < EntryKey > + { + bool operator()(EntryKey const& lhs, EntryKey const& rhs) const + { + return lhs.event_id == rhs.event_id + && lhs.entry == rhs.entry; + } + }; + + template + struct equal_to < UniqueObjectKey > + { + bool operator()(UniqueObjectKey const& lhs, UniqueObjectKey const& rhs) const + { + return lhs.event_id == rhs.event_id + && lhs.guid == rhs.guid + && lhs.instance_id == rhs.instance_id; + } + }; + + template + struct hash < EventKey > + { + typedef EventKey argument_type; + typedef std::size_t result_type; + + result_type operator()(argument_type const& k) const + { + result_type const h1(std::hash()(k.event_id)); + return h1; + } + }; + + template + struct hash < EntryKey > + { + typedef EntryKey argument_type; + typedef std::size_t result_type; + + result_type operator()(argument_type const& k) const + { + result_type const h1(std::hash()(k.event_id)); + result_type const h2(std::hash()(k.entry)); + + return h1 ^ (h2 << 8); // `event_id` probably won't exceed 2^8. + } + }; + + template + struct hash < UniqueObjectKey > + { + typedef UniqueObjectKey argument_type; + typedef std::size_t result_type; + + result_type operator()(argument_type const& k) const + { + result_type const h1(std::hash()(k.event_id)); + result_type const h2(std::hash()(k.instance_id)); + result_type const h3(std::hash()(k.guid)); + + return h1 ^ (h2 << 8) ^ (h3 << 24); // `instance_id` probably won't exceed 2^16. + } + }; +} + +#endif // _BINDING_MAP_H diff --git a/CreatureHooks.cpp b/CreatureHooks.cpp index 104945e..fb5f12c 100644 --- a/CreatureHooks.cpp +++ b/CreatureHooks.cpp @@ -4,187 +4,123 @@ * Please see the included DOCS/LICENSE.md for more information */ -#ifndef _CREATURE_HOOKS_H -#define _CREATURE_HOOKS_H - #include "Hooks.h" #include "HookHelpers.h" #include "LuaEngine.h" -#include "ElunaBinding.h" +#include "BindingMap.h" #include "ElunaIncludes.h" #include "ElunaTemplate.h" using namespace Hooks; +#define START_HOOK(EVENT, CREATURE) \ + if (!IsEnabled())\ + return;\ + auto entry_key = EntryKey(EVENT, CREATURE->GetEntry());\ + auto unique_key = UniqueObjectKey(EVENT, CREATURE->GET_GUID(), CREATURE->GetInstanceId());\ + if (!CreatureEventBindings->HasBindingsFor(entry_key))\ + if (!CreatureUniqueBindings->HasBindingsFor(unique_key))\ + return;\ + LOCK_ELUNA + +#define START_HOOK_WITH_RETVAL(EVENT, CREATURE, RETVAL) \ + if (!IsEnabled())\ + return RETVAL;\ + auto entry_key = EntryKey(EVENT, CREATURE->GetEntry());\ + auto unique_key = UniqueObjectKey(EVENT, CREATURE->GET_GUID(), CREATURE->GetInstanceId());\ + if (!CreatureEventBindings->HasBindingsFor(entry_key))\ + if (!CreatureUniqueBindings->HasBindingsFor(unique_key))\ + return RETVAL;\ + LOCK_ELUNA + bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Creature* pTarget) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GET_GUID(), pTarget->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget, false); Push(pCaster); Push(spellId); Push(effIndex); Push(pTarget); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry(), pTarget->GET_GUID(), pTarget->GetInstanceId()); -} - -bool Eluna::OnGossipHello(Player* pPlayer, Creature* pCreature) -{ - if (!CreatureGossipBindings->HasEvents(GOSSIP_EVENT_ON_HELLO, pCreature->GetEntry())) - return false; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pCreature); - return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_HELLO, pCreature->GetEntry(), true); -} - -bool Eluna::OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action) -{ - if (!CreatureGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry())) - return false; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pCreature); - Push(sender); - Push(action); - return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry(), true); -} - -bool Eluna::OnGossipSelectCode(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action, const char* code) -{ - if (!CreatureGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry())) - return false; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pCreature); - Push(sender); - Push(action); - Push(code); - return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry(), true); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } bool Eluna::OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GET_GUID(), pCreature->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature, false); Push(pPlayer); Push(pCreature); Push(pQuest); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GetEntry(), pCreature->GET_GUID(), pCreature->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } bool Eluna::OnQuestReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GET_GUID(), pCreature->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_QUEST_REWARD, pCreature, false); Push(pPlayer); Push(pCreature); Push(pQuest); Push(opt); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GetEntry(), pCreature->GET_GUID(), pCreature->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } uint32 Eluna::GetDialogStatus(Player* pPlayer, Creature* pCreature) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GET_GUID(), pCreature->GetInstanceId())) - return DIALOG_STATUS_SCRIPTED_NO_STATUS; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature, DIALOG_STATUS_SCRIPTED_NO_STATUS); Push(pPlayer); Push(pCreature); - CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GetEntry(), pCreature->GET_GUID(), pCreature->GetInstanceId()); + CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); return DIALOG_STATUS_SCRIPTED_NO_STATUS; } -void Eluna::OnAddToWorld(Creature* creature) +void Eluna::OnAddToWorld(Creature* pCreature) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ADD, creature->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ADD, creature->GET_GUID(), creature->GetInstanceId())) - return; - - LOCK_ELUNA; - Push(creature); - CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_ADD, creature->GetEntry(), creature->GET_GUID(), creature->GetInstanceId()); + START_HOOK(CREATURE_EVENT_ON_ADD, pCreature); + Push(pCreature); + CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } -void Eluna::OnRemoveFromWorld(Creature* creature) +void Eluna::OnRemoveFromWorld(Creature* pCreature) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REMOVE, creature->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REMOVE, creature->GET_GUID(), creature->GetInstanceId())) - return; - - LOCK_ELUNA; - Push(creature); - CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_REMOVE, creature->GetEntry(), creature->GET_GUID(), creature->GetInstanceId()); + START_HOOK(CREATURE_EVENT_ON_REMOVE, pCreature); + Push(pCreature); + CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } bool Eluna::OnSummoned(Creature* pCreature, Unit* pSummoner) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED, pCreature->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED, pCreature->GET_GUID(), pCreature->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SUMMONED, pCreature, false); Push(pCreature); Push(pSummoner); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SUMMONED, pCreature->GetEntry(), pCreature->GET_GUID(), pCreature->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } bool Eluna::UpdateAI(Creature* me, const uint32 diff) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_AIUPDATE, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_AIUPDATE, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_AIUPDATE, me, false); Push(me); Push(diff); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_AIUPDATE, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } //Called for reaction at enter to combat if not in combat yet (enemy can be NULL) //Called at creature aggro either by MoveInLOS or Attack Start bool Eluna::EnterCombat(Creature* me, Unit* target) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ENTER_COMBAT, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ENTER_COMBAT, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_ENTER_COMBAT, me, false); Push(me); Push(target); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_ENTER_COMBAT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called at any Damage from any attacker (before damage apply) bool Eluna::DamageTaken(Creature* me, Unit* attacker, uint32& damage) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_DAMAGE_TAKEN, me, false); bool result = false; Push(me); Push(attacker); Push(damage); int damageIndex = lua_gettop(L); - int n = SetupStack(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GetEntry(), me->GET_GUID(), me->GetInstanceId(), 3); + int n = SetupStack(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key, 3); while (n > 0) { @@ -211,163 +147,112 @@ bool Eluna::DamageTaken(Creature* me, Unit* attacker, uint32& damage) bool Eluna::JustDied(Creature* me, Unit* killer) { On_Reset(me); - - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DIED, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DIED, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_DIED, me, false); Push(me); Push(killer); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DIED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } //Called at creature killing another unit bool Eluna::KilledUnit(Creature* me, Unit* victim) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_TARGET_DIED, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_TARGET_DIED, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_TARGET_DIED, me, false); Push(me); Push(victim); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_TARGET_DIED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called when the creature summon successfully other creature bool Eluna::JustSummoned(Creature* me, Creature* summon) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me, false); Push(me); Push(summon); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called when a summoned creature is despawned bool Eluna::SummonedCreatureDespawn(Creature* me, Creature* summon) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me, false); Push(me); Push(summon); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } //Called at waypoint reached or PointMovement end bool Eluna::MovementInform(Creature* me, uint32 type, uint32 id) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REACH_WP, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REACH_WP, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_REACH_WP, me, false); Push(me); Push(type); Push(id); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_REACH_WP, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called before EnterCombat even before the creature is in combat. bool Eluna::AttackStart(Creature* me, Unit* target) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_PRE_COMBAT, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_PRE_COMBAT, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_PRE_COMBAT, me, false); Push(me); Push(target); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_PRE_COMBAT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called for reaction at stopping attack at no attackers or targets bool Eluna::EnterEvadeMode(Creature* me) { On_Reset(me); - - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_LEAVE_COMBAT, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_LEAVE_COMBAT, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_LEAVE_COMBAT, me, false); Push(me); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_LEAVE_COMBAT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc) bool Eluna::AttackedBy(Creature* me, Unit* attacker) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ATTACKED_AT, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ATTACKED_AT, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_ATTACKED_AT, me, false); Push(me); Push(attacker); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_ATTACKED_AT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called when creature is spawned or respawned (for reseting variables) bool Eluna::JustRespawned(Creature* me) { On_Reset(me); - - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SPAWN, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SPAWN, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SPAWN, me, false); Push(me); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SPAWN, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called at reaching home after evade bool Eluna::JustReachedHome(Creature* me) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REACH_HOME, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REACH_HOME, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_REACH_HOME, me, false); Push(me); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_REACH_HOME, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called at text emote receive from player bool Eluna::ReceiveEmote(Creature* me, Player* player, uint32 emoteId) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_RECEIVE_EMOTE, me, false); Push(me); Push(player); Push(emoteId); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // called when the corpse of this creature gets removed bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_CORPSE_REMOVED, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_CORPSE_REMOVED, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_CORPSE_REMOVED, me, false); bool result = false; Push(me); Push(respawnDelay); int respawnDelayIndex = lua_gettop(L); - int n = SetupStack(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_CORPSE_REMOVED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId(), 2); + int n = SetupStack(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key, 2); while (n > 0) { @@ -392,96 +277,67 @@ bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay) bool Eluna::MoveInLineOfSight(Creature* me, Unit* who) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_MOVE_IN_LOS, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_MOVE_IN_LOS, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_MOVE_IN_LOS, me, false); Push(me); Push(who); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_MOVE_IN_LOS, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called on creature initial spawn, respawn, death, evade (leave combat) void Eluna::On_Reset(Creature* me) // Not an override, custom { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_RESET, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_RESET, me->GET_GUID(), me->GetInstanceId())) - return; - - LOCK_ELUNA; + START_HOOK(CREATURE_EVENT_ON_RESET, me); Push(me); - CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_RESET, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called when hit by a spell bool Eluna::SpellHit(Creature* me, Unit* caster, SpellInfo const* spell) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_HIT_BY_SPELL, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_HIT_BY_SPELL, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_HIT_BY_SPELL, me, false); Push(me); Push(caster); Push(spell->Id); // Pass spell object? - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_HIT_BY_SPELL, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called when spell hits a target bool Eluna::SpellHitTarget(Creature* me, Unit* target, SpellInfo const* spell) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me, false); Push(me); Push(target); Push(spell->Id); // Pass spell object? - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } #ifdef TRINITY bool Eluna::SummonedCreatureDies(Creature* me, Creature* summon, Unit* killer) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me, false); Push(me); Push(summon); Push(killer); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called when owner takes damage bool Eluna::OwnerAttackedBy(Creature* me, Unit* attacker) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me, false); Push(me); Push(attacker); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } // Called when owner attacks something bool Eluna::OwnerAttacked(Creature* me, Unit* target) { - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_OWNER_ATTACKED, me, false); Push(me); Push(target); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_OWNER_ATTACKED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); } #endif // TRINITY -#endif // _CREATURE_HOOKS_H diff --git a/ElunaBinding.h b/ElunaBinding.h deleted file mode 100644 index 85f3bd2..0000000 --- a/ElunaBinding.h +++ /dev/null @@ -1,573 +0,0 @@ -/* -* Copyright (C) 2010 - 2015 Eluna Lua Engine -* This program is free software licensed under GPL version 3 -* Please see the included DOCS/LICENSE.md for more information -*/ - -#ifndef _ELUNA_BINDING_H -#define _ELUNA_BINDING_H - -#include "Common.h" -#include "LuaEngine.h" -#include "ElunaUtility.h" - -extern "C" -{ -#include "lua.h" -#include "lauxlib.h" -}; - -#ifdef WIN32 -// VC++ complains about UniqueBind because one of its template types is really long. -#pragma warning(disable:4503) -#endif - -class ElunaBind : public ElunaUtil::RWLockable -{ -public: - struct Binding - { - int functionReference; - bool isTemporary; - uint32 remainingShots; - int cancelCallbackRef; // Reference to a callback that will cancel this binding, or 0. - Eluna& E; - - Binding(Eluna& _E, int funcRef, uint32 shots, int cancelCallbackRef) : - functionReference(funcRef), - isTemporary(shots != 0 && cancelCallbackRef == 0), - remainingShots(shots), - cancelCallbackRef(cancelCallbackRef), - E(_E) - { - } - - ~Binding() - { - // Remove our function and cancel callback from the registry when the Binding is deleted. - if (cancelCallbackRef > 0) - luaL_unref(E.L, LUA_REGISTRYINDEX, cancelCallbackRef); - - luaL_unref(E.L, LUA_REGISTRYINDEX, functionReference); - } - }; - typedef std::vector FunctionRefVector; - typedef UNORDERED_MAP EventToFunctionsMap; - - Eluna& E; - const char* groupName; - - ElunaBind(const char* bindGroupName, Eluna& _E) : E(_E), groupName(bindGroupName) - { - } - - virtual ~ElunaBind() - { - Clear(); - } - - // unregisters all registered functions and clears all registered events from the bindings - virtual void Clear() { }; - - virtual void ClearOne(int ref, uint32 event_id, uint32 entry, uint64 guid) = 0; -}; - -template -class EventBind : public ElunaBind -{ -public: - EventBind(const char* bindGroupName, Eluna& _E) : ElunaBind(bindGroupName, _E) - { - } - - // unregisters all registered functions and clears all registered events from the bind std::maps (reset) - void Clear() override - { - WriteGuard guard(GetLock()); - - for (EventToFunctionsMap::iterator itr = Bindings.begin(); itr != Bindings.end(); ++itr) - { - FunctionRefVector& funcrefvec = itr->second; - std::vector cancelRefVector; - - for (FunctionRefVector::iterator it = funcrefvec.begin(); it != funcrefvec.end(); ++it) - { - Binding* binding = (*it); - - // Can't call the callback now, since it might modify `v` and crash the server. - // Just add the ref to a list and call them all after this loop. - if (binding->cancelCallbackRef) - cancelRefVector.push_back(binding->cancelCallbackRef); - else - delete binding; // Don't bother removing from list, clear is called at end anyway. - } - - // Call all of the cancel callbacks for bindings with cancel callbacks. - for (std::vector::iterator i = cancelRefVector.begin(); i != cancelRefVector.end(); ++i) - { - lua_rawgeti(E.L, LUA_REGISTRYINDEX, (*i)); - lua_call(E.L, 0, 0); - } - - funcrefvec.clear(); - } - Bindings.clear(); - } - - void Clear(uint32 event_id) - { - WriteGuard guard(GetLock()); - FunctionRefVector& v = Bindings[event_id]; - std::vector cancelRefVector; - - for (FunctionRefVector::iterator itr = v.begin(); itr != v.end(); ++itr) - { - Binding* binding = (*itr); - - // Can't call the callback now, since it might modify `v` and crash the server. - // Just add the ref to a list and call them all after this loop. - if (binding->cancelCallbackRef) - cancelRefVector.push_back(binding->cancelCallbackRef); - else - delete binding; // Don't bother removing from list, clear is called at end anyway. - } - - // Call all of the cancel callbacks for bindings with cancel callbacks. - for (std::vector::iterator i = cancelRefVector.begin(); i != cancelRefVector.end(); ++i) - { - lua_rawgeti(E.L, LUA_REGISTRYINDEX, (*i)); - lua_call(E.L, 0, 0); - } - - v.clear(); - } - - void ClearOne(int ref, uint32 event_id, uint32 entry, uint64 guid) override - { - ASSERT(entry == 0 && guid == 0); - WriteGuard guard(GetLock()); - - FunctionRefVector& funcrefvec = Bindings[event_id]; - - for (FunctionRefVector::iterator i = funcrefvec.begin(); i != funcrefvec.end(); ++i) - { - Binding* binding = (*i); - - if (binding->functionReference == ref) - { - i = funcrefvec.erase(i); - delete binding; - return; - } - } - - ASSERT(false && "tried to clear function ref that doesn't exist"); - } - - // Pushes the function references and updates the counters on the binds and erases them if the counter would reach 0 - void PushFuncRefs(lua_State* L, int event_id) - { - WriteGuard guard(GetLock()); - - for (FunctionRefVector::iterator it = Bindings[event_id].begin(); it != Bindings[event_id].end();) - { - FunctionRefVector::iterator it_old = it++; - Binding* binding = (*it_old); - - lua_rawgeti(L, LUA_REGISTRYINDEX, binding->functionReference); - - if (binding->isTemporary) - { - // Bad things will happen if there's a cancel callback (due to ref reuse). - ASSERT(binding->cancelCallbackRef == 0); - - binding->remainingShots--; - if (binding->remainingShots == 0) - { - delete binding; - Bindings[event_id].erase(it_old); - } - } - } - - if (Bindings[event_id].empty()) - Bindings.erase(event_id); - }; - - void Insert(int eventId, int funcRef, uint32 shots, int callbackRef = 0) // Inserts a new registered event - { - WriteGuard guard(GetLock()); - Bindings[eventId].push_back(new Binding(E, funcRef, shots, callbackRef)); - } - - // Checks if there are events for ID - bool HasEvents(T eventId) - { - ReadGuard guard(GetLock()); - - if (!E.IsEnabled()) - return false; - - if (Bindings.empty()) - return false; - if (Bindings.find(eventId) == Bindings.end()) - return false; - return true; - } - - EventToFunctionsMap Bindings; // Binding store Bindings[eventId] = {(funcRef, counter)}; -}; - -template -class EntryBind : public ElunaBind -{ -public: - typedef UNORDERED_MAP EntryToEventsMap; - - EntryBind(const char* bindGroupName, Eluna& _E) : ElunaBind(bindGroupName, _E) - { - } - - // unregisters all registered functions and clears all registered events from the bindmap - void Clear() override - { - WriteGuard guard(GetLock()); - - for (EntryToEventsMap::iterator itr = Bindings.begin(); itr != Bindings.end(); ++itr) - { - EventToFunctionsMap& funcmap = itr->second; - for (EventToFunctionsMap::iterator it = funcmap.begin(); it != funcmap.end(); ++it) - { - FunctionRefVector& funcrefvec = it->second; - std::vector cancelRefVector; - - for (FunctionRefVector::iterator i = funcrefvec.begin(); i != funcrefvec.end(); ++i) - { - Binding* binding = (*i); - - // Can't call the callback now, since it might modify `v` and crash the server. - // Just add the ref to a list and call them all after this loop. - if (binding->cancelCallbackRef) - cancelRefVector.push_back(binding->cancelCallbackRef); - else - delete binding; // Don't bother removing from list, clear is called at end anyway. - } - - // Call all of the cancel callbacks for bindings with cancel callbacks. - for (std::vector::iterator i = cancelRefVector.begin(); i != cancelRefVector.end(); ++i) - { - lua_rawgeti(E.L, LUA_REGISTRYINDEX, (*i)); - lua_call(E.L, 0, 0); - } - - funcrefvec.clear(); - } - funcmap.clear(); - } - Bindings.clear(); - } - - void Clear(uint32 entry, uint32 event_id) - { - WriteGuard guard(GetLock()); - FunctionRefVector& v = Bindings[entry][event_id]; - std::vector cancelRefVector; - - for (FunctionRefVector::iterator itr = v.begin(); itr != v.end(); ++itr) - { - Binding* binding = (*itr); - - // Can't call the callback now, since it might modify `v` and crash the server. - // Just add the ref to a list and call them all after this loop. - if (binding->cancelCallbackRef) - cancelRefVector.push_back(binding->cancelCallbackRef); - else - delete binding; // Don't bother removing from list, clear is called at end anyway. - } - - // Call all of the cancel callbacks for bindings with cancel callbacks. - for (std::vector::iterator i = cancelRefVector.begin(); i != cancelRefVector.end(); ++i) - { - lua_rawgeti(E.L, LUA_REGISTRYINDEX, (*i)); - lua_call(E.L, 0, 0); - } - - v.clear(); - } - - void ClearOne(int ref, uint32 event_id, uint32 entry, uint64 guid) override - { - ASSERT(entry != 0 && guid == 0); - WriteGuard guard(GetLock()); - - FunctionRefVector& funcrefvec = Bindings[entry][event_id]; - - for (FunctionRefVector::iterator i = funcrefvec.begin(); i != funcrefvec.end(); ++i) - { - Binding* binding = (*i); - - if (binding->functionReference == ref) - { - i = funcrefvec.erase(i); - delete binding; - return; - } - } - - ASSERT(false && "tried to clear function ref that doesn't exist"); - } - - // Pushes the function references and updates the counters on the binds and erases them if the counter would reach 0 - void PushFuncRefs(lua_State* L, int event_id, uint32 entry) - { - WriteGuard guard(GetLock()); - - for (FunctionRefVector::iterator it = Bindings[entry][event_id].begin(); it != Bindings[entry][event_id].end();) - { - FunctionRefVector::iterator it_old = it++; - Binding* binding = (*it_old); - - lua_rawgeti(L, LUA_REGISTRYINDEX, binding->functionReference); - - if (binding->isTemporary) - { - // Bad things will happen if there's a cancel callback (due to ref reuse). - ASSERT(binding->cancelCallbackRef == 0); - - binding->remainingShots--; - if (binding->remainingShots == 0) - { - delete binding; - Bindings[entry][event_id].erase(it_old); - } - } - } - - if (Bindings[entry][event_id].empty()) - Bindings[entry].erase(event_id); - - if (Bindings[entry].empty()) - Bindings.erase(entry); - }; - - void Insert(uint32 entryId, int eventId, int funcRef, uint32 shots, int callbackRef = 0) // Inserts a new registered event - { - WriteGuard guard(GetLock()); - Bindings[entryId][eventId].push_back(new Binding(E, funcRef, shots, callbackRef)); - } - - // Returns true if the entry has registered binds - bool HasEvents(T eventId, uint32 entryId) - { - ReadGuard guard(GetLock()); - - if (Bindings.empty()) - return false; - - EntryToEventsMap::const_iterator itr = Bindings.find(entryId); - if (itr == Bindings.end()) - return false; - - return itr->second.find(eventId) != itr->second.end(); - } - - bool HasEvents(uint32 entryId) - { - ReadGuard guard(GetLock()); - - if (!E.IsEnabled()) - return false; - - if (Bindings.empty()) - return false; - - return Bindings.find(entryId) != Bindings.end(); - } - - EntryToEventsMap Bindings; // Binding store Bindings[entryId][eventId] = {(funcRef, counter)}; -}; - -template -class UniqueBind : public ElunaBind -{ -public: - typedef UNORDERED_MAP InstanceToEventsMap; - typedef UNORDERED_MAP GUIDToInstancesMap; - - UniqueBind(const char* bindGroupName, Eluna& _E) : ElunaBind(bindGroupName, _E) - { - } - - // unregisters all registered functions and clears all registered events from the bindmap - void Clear() override - { - WriteGuard guard(GetLock()); - - for (GUIDToInstancesMap::iterator iter = Bindings.begin(); iter != Bindings.end(); ++iter) - { - InstanceToEventsMap& eventsMap = iter->second; - for (InstanceToEventsMap::iterator itr = eventsMap.begin(); itr != eventsMap.end(); ++itr) - { - EventToFunctionsMap& funcmap = itr->second; - for (EventToFunctionsMap::iterator it = funcmap.begin(); it != funcmap.end(); ++it) - { - FunctionRefVector& funcrefvec = it->second; - std::vector cancelRefVector; - - for (FunctionRefVector::iterator i = funcrefvec.begin(); i != funcrefvec.end(); ++i) - { - Binding* binding = (*i); - - // Can't call the callback now, since it might modify `v` and crash the server. - // Just add the ref to a list and call them all after this loop. - if (binding->cancelCallbackRef) - cancelRefVector.push_back(binding->cancelCallbackRef); - else - delete binding; // Don't bother removing from list, clear is called at end anyway. - } - - // Call all of the cancel callbacks for bindings with cancel callbacks. - for (std::vector::iterator i = cancelRefVector.begin(); i != cancelRefVector.end(); ++i) - { - lua_rawgeti(E.L, LUA_REGISTRYINDEX, (*i)); - lua_call(E.L, 0, 0); - } - funcrefvec.clear(); - } - funcmap.clear(); - } - eventsMap.clear(); - } - Bindings.clear(); - } - - void Clear(uint64 guid, uint32 instanceId, uint32 event_id) - { - WriteGuard guard(GetLock()); - FunctionRefVector& v = Bindings[guid][instanceId][event_id]; - std::vector cancelRefVector; - - for (FunctionRefVector::iterator itr = v.begin(); itr != v.end(); ++itr) - { - Binding* binding = (*itr); - - // Can't call the callback now, since it might modify `v` and crash the server. - // Just add the ref to a list and call them all after this loop. - if (binding->cancelCallbackRef) - cancelRefVector.push_back(binding->cancelCallbackRef); - else - delete binding; // Don't bother removing from list, clear is called at end anyway. - } - - // Call all of the cancel callbacks for bindings with cancel callbacks. - for (std::vector::iterator i = cancelRefVector.begin(); i != cancelRefVector.end(); ++i) - { - lua_rawgeti(E.L, LUA_REGISTRYINDEX, (*i)); - lua_call(E.L, 0, 0); - } - - v.clear(); - } - - void ClearOne(int ref, uint32 event_id, uint32 instance_id, uint64 guid) override - { - ASSERT(guid != 0); - WriteGuard guard(GetLock()); - - FunctionRefVector& funcrefvec = Bindings[guid][instance_id][event_id]; - - for (FunctionRefVector::iterator i = funcrefvec.begin(); i != funcrefvec.end(); ++i) - { - Binding* binding = (*i); - - if (binding->functionReference == ref) - { - i = funcrefvec.erase(i); - delete binding; - return; - } - } - - ASSERT(false && "tried to clear function ref that doesn't exist"); - } - - // Pushes the function references and updates the counters on the binds and erases them if the counter would reach 0 - void PushFuncRefs(lua_State* L, int event_id, uint64 guid, uint32 instanceId) - { - WriteGuard guard(GetLock()); - FunctionRefVector& v = Bindings[guid][instanceId][event_id]; - - for (FunctionRefVector::iterator it = v.begin(); it != v.end();) - { - FunctionRefVector::iterator it_old = it++; - Binding* binding = (*it_old); - - lua_rawgeti(L, LUA_REGISTRYINDEX, binding->functionReference); - - if (binding->isTemporary) - { - // Bad things will happen if there's a cancel callback (due to ref reuse). - ASSERT(binding->cancelCallbackRef == 0); - - binding->remainingShots--; - if (binding->remainingShots == 0) - { - delete binding; - v.erase(it_old); - } - } - } - - if (Bindings[guid][instanceId][event_id].empty()) - Bindings[guid][instanceId].erase(event_id); - - if (Bindings[guid][instanceId].empty()) - Bindings[guid].erase(instanceId); - - if (Bindings[guid].empty()) - Bindings.erase(guid); - }; - - void Insert(uint64 guid, uint32 instanceId, int eventId, int funcRef, uint32 shots, int callbackRef = 0) // Inserts a new registered event - { - WriteGuard guard(GetLock()); - Bindings[guid][instanceId][eventId].push_back(new Binding(E, funcRef, shots, callbackRef)); - } - - // Returns true if the entry has registered binds - bool HasEvents(T eventId, uint64 guid, uint32 instanceId) - { - ReadGuard guard(GetLock()); - - if (Bindings.empty()) - return false; - - GUIDToInstancesMap::const_iterator itr = Bindings.find(guid); - if (itr == Bindings.end()) - return false; - - InstanceToEventsMap::const_iterator it = itr->second.find(instanceId); - if (it == itr->second.end()) - return false; - - return it->second.find(eventId) != it->second.end(); - } - - bool HasEvents(uint64 guid, uint32 instanceId) - { - ReadGuard guard(GetLock()); - - if (Bindings.empty()) - return false; - - GUIDToInstancesMap::const_iterator itr = Bindings.find(guid); - if (itr == Bindings.end()) - return false; - - return itr->second.find(instanceId) != itr->second.end(); - } - - GUIDToInstancesMap Bindings; // Binding store Bindings[guid][instanceId][eventId] = {(funcRef, counter)}; -}; - -#endif diff --git a/ElunaEventMgr.h b/ElunaEventMgr.h index ecf879e..6771701 100644 --- a/ElunaEventMgr.h +++ b/ElunaEventMgr.h @@ -54,7 +54,7 @@ class ElunaEventProcessor public: typedef std::multimap EventList; - typedef UNORDERED_MAP EventMap; + typedef std::unordered_map EventMap; ElunaEventProcessor(Eluna** _E, WorldObject* _obj); ~ElunaEventProcessor(); @@ -80,7 +80,7 @@ private: class EventMgr : public ElunaUtil::RWLockable { public: - typedef UNORDERED_SET ProcessorSet; + typedef std::unordered_set ProcessorSet; ProcessorSet processors; ElunaEventProcessor* globalProcessor; Eluna** E; diff --git a/ElunaUtility.h b/ElunaUtility.h index 83ef118..f04e6ec 100644 --- a/ElunaUtility.h +++ b/ElunaUtility.h @@ -7,6 +7,8 @@ #ifndef _ELUNA_UTIL_H #define _ELUNA_UTIL_H +#include +#include #include "Common.h" #include "SharedDefines.h" #include "ObjectGuid.h" @@ -28,8 +30,6 @@ #ifdef USING_BOOST #include #include -#else -#include #endif #ifdef TRINITY @@ -50,15 +50,6 @@ typedef QueryNamedResult ElunaQuery; #define GetTemplate GetProto #endif -#ifndef UNORDERED_MAP -#include -#define UNORDERED_MAP std::unordered_map -#endif -#ifndef UNORDERED_SET -#include -#define UNORDERED_SET std::unordered_set -#endif - #ifndef MAKE_NEW_GUID #define MAKE_NEW_GUID(l, e, h) ObjectGuid(h, e, l) #endif @@ -132,11 +123,11 @@ namespace ElunaUtil public: #ifdef USING_BOOST - typedef boost::recursive_mutex LockType; - typedef boost::shared_lock ReadGuard; - typedef boost::unique_lock WriteGuard; + typedef boost::shared_mutex LockType; + typedef boost::shared_lock ReadGuard; + typedef boost::unique_lock WriteGuard; #else - typedef ACE_Recursive_Thread_Mutex LockType; + typedef ACE_RW_Thread_Mutex LockType; typedef ACE_Read_Guard ReadGuard; typedef ACE_Write_Guard WriteGuard; #endif diff --git a/GameObjectHooks.cpp b/GameObjectHooks.cpp index 2c6387e..739e3e7 100644 --- a/GameObjectHooks.cpp +++ b/GameObjectHooks.cpp @@ -4,119 +4,76 @@ * Please see the included DOCS/LICENSE.md for more information */ -#ifndef _GAMEOBJECT_HOOKS_H -#define _GAMEOBJECT_HOOKS_H - #include "Hooks.h" #include "HookHelpers.h" #include "LuaEngine.h" -#include "ElunaBinding.h" +#include "BindingMap.h" #include "ElunaIncludes.h" #include "ElunaEventMgr.h" #include "ElunaTemplate.h" using namespace Hooks; +#define START_HOOK(EVENT, ENTRY) \ + if (!IsEnabled())\ + return;\ + auto key = EntryKey(EVENT, ENTRY);\ + if (!GameObjectEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +#define START_HOOK_WITH_RETVAL(EVENT, ENTRY, RETVAL) \ + if (!IsEnabled())\ + return RETVAL;\ + auto key = EntryKey(EVENT, ENTRY);\ + if (!GameObjectEventBindings->HasBindingsFor(key))\ + return RETVAL;\ + LOCK_ELUNA + bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, GameObject* pTarget) { - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry(), false); Push(pCaster); Push(spellId); Push(effIndex); Push(pTarget); - return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()); -} - -bool Eluna::OnGossipHello(Player* pPlayer, GameObject* pGameObject) -{ - if (!GameObjectGossipBindings->HasEvents(GOSSIP_EVENT_ON_HELLO, pGameObject->GetEntry())) - return false; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pGameObject); - return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_HELLO, pGameObject->GetEntry(), true); -} - -bool Eluna::OnGossipSelect(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action) -{ - if (!GameObjectGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry())) - return false; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pGameObject); - Push(sender); - Push(action); - return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry(), true); -} - -bool Eluna::OnGossipSelectCode(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action, const char* code) -{ - if (!GameObjectGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry())) - return false; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pGameObject); - Push(sender); - Push(action); - Push(code); - return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry(), true); -} - -bool Eluna::OnQuestAccept(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_QUEST_ACCEPT, pGameObject->GetEntry())) - return false; - - LOCK_ELUNA; - Push(pPlayer); - Push(pGameObject); - Push(pQuest); - return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_QUEST_ACCEPT, pGameObject->GetEntry()); + return CallAllFunctionsBool(GameObjectEventBindings, key); } void Eluna::UpdateAI(GameObject* pGameObject, uint32 diff) { - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_AIUPDATE, pGameObject->GetEntry())) - return; - - LOCK_ELUNA; + START_HOOK(GAMEOBJECT_EVENT_ON_AIUPDATE, pGameObject->GetEntry()); pGameObject->elunaEvents->Update(diff); Push(pGameObject); Push(diff); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_AIUPDATE, pGameObject->GetEntry()); + CallAllFunctions(GameObjectEventBindings, key); +} + +bool Eluna::OnQuestAccept(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest) +{ + START_HOOK_WITH_RETVAL(GAMEOBJECT_EVENT_ON_QUEST_ACCEPT, pGameObject->GetEntry(), false); + Push(pPlayer); + Push(pGameObject); + Push(pQuest); + return CallAllFunctionsBool(GameObjectEventBindings, key); } bool Eluna::OnQuestReward(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest, uint32 opt) { - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_QUEST_REWARD, pGameObject->GetEntry())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(GAMEOBJECT_EVENT_ON_QUEST_REWARD, pGameObject->GetEntry(), false); Push(pPlayer); Push(pGameObject); Push(pQuest); Push(opt); - return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_QUEST_REWARD, pGameObject->GetEntry()); + return CallAllFunctionsBool(GameObjectEventBindings, key); } uint32 Eluna::GetDialogStatus(Player* pPlayer, GameObject* pGameObject) { - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DIALOG_STATUS, pGameObject->GetEntry())) - return DIALOG_STATUS_SCRIPTED_NO_STATUS; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(GAMEOBJECT_EVENT_ON_DIALOG_STATUS, pGameObject->GetEntry(), false); Push(pPlayer); Push(pGameObject); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DIALOG_STATUS, pGameObject->GetEntry()); + CallAllFunctions(GameObjectEventBindings, key); return DIALOG_STATUS_SCRIPTED_NO_STATUS; // DIALOG_STATUS_UNDEFINED } @@ -124,89 +81,63 @@ uint32 Eluna::GetDialogStatus(Player* pPlayer, GameObject* pGameObject) #ifndef TBC void Eluna::OnDestroyed(GameObject* pGameObject, Player* pPlayer) { - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry())) - return; - - LOCK_ELUNA; + START_HOOK(GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry()); Push(pGameObject); Push(pPlayer); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry()); + CallAllFunctions(GameObjectEventBindings, key); } void Eluna::OnDamaged(GameObject* pGameObject, Player* pPlayer) { - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry())) - return; - - LOCK_ELUNA; + START_HOOK(GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry()); Push(pGameObject); Push(pPlayer); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry()); + CallAllFunctions(GameObjectEventBindings, key); } #endif #endif void Eluna::OnLootStateChanged(GameObject* pGameObject, uint32 state) { - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry())) - return; - - LOCK_ELUNA; + START_HOOK(GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry()); Push(pGameObject); Push(state); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry()); + CallAllFunctions(GameObjectEventBindings, key); } void Eluna::OnGameObjectStateChanged(GameObject* pGameObject, uint32 state) { - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, pGameObject->GetEntry())) - return; - - LOCK_ELUNA; + START_HOOK(GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, pGameObject->GetEntry()); Push(pGameObject); Push(state); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, pGameObject->GetEntry()); + CallAllFunctions(GameObjectEventBindings, key); } -void Eluna::OnSpawn(GameObject* gameobject) +void Eluna::OnSpawn(GameObject* pGameObject) { - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_SPAWN, gameobject->GetEntry())) - return; - - LOCK_ELUNA; - Push(gameobject); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_SPAWN, gameobject->GetEntry()); + START_HOOK(GAMEOBJECT_EVENT_ON_SPAWN, pGameObject->GetEntry()); + Push(pGameObject); + CallAllFunctions(GameObjectEventBindings, key); } -void Eluna::OnAddToWorld(GameObject* gameobject) +void Eluna::OnAddToWorld(GameObject* pGameObject) { - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_ADD, gameobject->GetEntry())) - return; - - LOCK_ELUNA; - Push(gameobject); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_ADD, gameobject->GetEntry()); + START_HOOK(GAMEOBJECT_EVENT_ON_ADD, pGameObject->GetEntry()); + Push(pGameObject); + CallAllFunctions(GameObjectEventBindings, key); } -void Eluna::OnRemoveFromWorld(GameObject* gameobject) +void Eluna::OnRemoveFromWorld(GameObject* pGameObject) { - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_REMOVE, gameobject->GetEntry())) - return; - - LOCK_ELUNA; - Push(gameobject); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_REMOVE, gameobject->GetEntry()); + START_HOOK(GAMEOBJECT_EVENT_ON_REMOVE, pGameObject->GetEntry()); + Push(pGameObject); + CallAllFunctions(GameObjectEventBindings, key); } bool Eluna::OnGameObjectUse(Player* pPlayer, GameObject* pGameObject) { - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_USE, pGameObject->GetEntry())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(GAMEOBJECT_EVENT_ON_USE, pGameObject->GetEntry(), false); Push(pGameObject); Push(pPlayer); - return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_USE, pGameObject->GetEntry()); + return CallAllFunctionsBool(GameObjectEventBindings, key); } - -#endif // _GAMEOBJECT_HOOKS_H diff --git a/GlobalMethods.h b/GlobalMethods.h index 190435a..ef9d9e7 100644 --- a/GlobalMethods.h +++ b/GlobalMethods.h @@ -7,7 +7,7 @@ #ifndef GLOBALMETHODS_H #define GLOBALMETHODS_H -#include "ElunaBinding.h" +#include "BindingMap.h" /*** * These functions can be used anywhere at any time, including at start-up. @@ -503,18 +503,11 @@ namespace LuaGlobalFunctions uint32 ev = Eluna::CHECKVAL(L, 2); luaL_checktype(L, 3, LUA_TFUNCTION); uint32 shots = Eluna::CHECKVAL(L, 4, 0); - bool returnCallback = Eluna::CHECKVAL(L, 5, false); - - if (shots > 0 && returnCallback) - { - luaL_argerror(L, 5, "cannot return a callback if shots is > 0"); - return 0; - } lua_pushvalue(L, 3); int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); if (functionRef >= 0) - return E->Register(L, regtype, entry, 0, 0, ev, functionRef, shots, returnCallback); + return E->Register(L, regtype, entry, 0, 0, ev, functionRef, shots); else luaL_argerror(L, 3, "unable to make a ref to function"); return 0; @@ -525,18 +518,11 @@ namespace LuaGlobalFunctions uint32 ev = Eluna::CHECKVAL(L, 1); luaL_checktype(L, 2, LUA_TFUNCTION); uint32 shots = Eluna::CHECKVAL(L, 3, 0); - bool returnCallback = Eluna::CHECKVAL(L, 4, false); - - if (shots > 0 && returnCallback) - { - luaL_argerror(L, 5, "cannot return a callback if shots is > 0"); - return 0; - } lua_pushvalue(L, 2); int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); if (functionRef >= 0) - return E->Register(L, regtype, 0, 0, 0, ev, functionRef, shots, returnCallback); + return E->Register(L, regtype, 0, 0, 0, ev, functionRef, shots); else luaL_argerror(L, 2, "unable to make a ref to function"); return 0; @@ -549,18 +535,11 @@ namespace LuaGlobalFunctions uint32 ev = Eluna::CHECKVAL(L, 3); luaL_checktype(L, 4, LUA_TFUNCTION); uint32 shots = Eluna::CHECKVAL(L, 5, 0); - bool returnCallback = Eluna::CHECKVAL(L, 6, false); - - if (shots > 0 && returnCallback) - { - luaL_argerror(L, 5, "cannot return a callback if shots is > 0"); - return 0; - } lua_pushvalue(L, 4); int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); if (functionRef >= 0) - return E->Register(L, regtype, 0, guid, instanceId, ev, functionRef, shots, returnCallback); + return E->Register(L, regtype, 0, guid, instanceId, ev, functionRef, shots); else luaL_argerror(L, 4, "unable to make a ref to function"); return 0; @@ -569,16 +548,6 @@ namespace LuaGlobalFunctions /** * Registers a server event handler. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearServerEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearServerEvents] work as normal. - * * enum ServerEvents * { * // Server @@ -634,14 +603,12 @@ namespace LuaGlobalFunctions * SERVER_EVENT_COUNT * }; * - * @proto (event, function) - * @proto (event, function, shots) - * @proto cancel = (event, function, 0, true) + * @proto cancel = (event, function) + * @proto cancel = (event, function, shots) * * @param uint32 event : server event ID, refer to ServerEvents above * @param function function : function that will be called when the event occurs * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -653,16 +620,6 @@ namespace LuaGlobalFunctions /** * Registers a [Player] event handler. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearPlayerEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearPlayerEvents] work as normal. - * *
      * enum PlayerEvents
      * {
@@ -715,14 +672,12 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @proto (event, function) - * @proto (event, function, shots) - * @proto cancel = (event, function, 0, true) + * @proto cancel = (event, function) + * @proto cancel = (event, function, shots) * * @param uint32 event : [Player] event Id, refer to PlayerEvents above * @param function function : function to register * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -734,16 +689,6 @@ namespace LuaGlobalFunctions /** * Registers a [Guild] event handler. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearGuildEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearGuildEvents] work as normal. - * *
      * enum GuildEvents
      * {
@@ -764,14 +709,12 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @proto (event, function) - * @proto (event, function, shots) - * @proto cancel = (event, function, 0, true) + * @proto cancel = (event, function) + * @proto cancel = (event, function, shots) * * @param uint32 event : [Guild] event Id, refer to GuildEvents above * @param function function : function to register * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -783,16 +726,6 @@ namespace LuaGlobalFunctions /** * Registers a [Group] event handler. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearGroupEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearGroupEvents] work as normal. - * *
      * enum GroupEvents
      * {
@@ -808,14 +741,12 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @proto (event, function) - * @proto (event, function, shots) - * @proto cancel = (event, function, 0, true) + * @proto cancel = (event, function) + * @proto cancel = (event, function, shots) * * @param uint32 event : [Group] event Id, refer to GroupEvents above * @param function function : function to register * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -828,16 +759,6 @@ namespace LuaGlobalFunctions /** * Registers a [BattleGround] event handler. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearBattleGroundEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearBattleGroundEvents] work as normal. - * *
      * enum BGEvents
      * {
@@ -849,14 +770,12 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @proto (event, function) - * @proto (event, function, shots) - * @proto cancel = (event, function, 0, true) + * @proto cancel = (event, function) + * @proto cancel = (event, function, shots) * * @param uint32 event : [BattleGround] event Id, refer to BGEvents above * @param function function : function to register * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -868,16 +787,6 @@ namespace LuaGlobalFunctions /** * Registers a [WorldPacket] event handler. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearPacketEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearPacketEvents] work as normal. - * *
      * enum PacketEvents
      * {
@@ -889,15 +798,13 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @proto (entry, event, function) - * @proto (entry, event, function, shots) - * @proto cancel = (entry, event, function, 0, true) + * @proto cancel = (entry, event, function) + * @proto cancel = (entry, event, function, shots) * * @param uint32 entry : opcode * @param uint32 event : packet event Id, refer to PacketEvents above * @param function function : function to register * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -909,16 +816,6 @@ namespace LuaGlobalFunctions /** * Registers a [Creature] gossip event handler. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearCreatureGossipEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearCreatureGossipEvents] work as normal. - * *
      * enum GossipEvents
      * {
@@ -928,15 +825,13 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @proto (menu_id, event, function) - * @proto (menu_id, event, function, shots) - * @proto cancel = (menu_id, event, function, 0, true) + * @proto cancel = (menu_id, event, function) + * @proto cancel = (menu_id, event, function, shots) * * @param uint32 menu_id : [Creature] entry Id * @param uint32 event : [Creature] gossip event Id, refer to GossipEvents above * @param function function : function to register * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -948,16 +843,6 @@ namespace LuaGlobalFunctions /** * Registers a [GameObject] gossip event handler. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearGameObjectGossipEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearGameObjectGossipEvents] work as normal. - * *
      * enum GossipEvents
      * {
@@ -967,15 +852,13 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @proto (menu_id, event, function) - * @proto (menu_id, event, function, shots) - * @proto cancel = (menu_id, event, function, 0, true) + * @proto cancel = (menu_id, event, function) + * @proto cancel = (menu_id, event, function, shots) * * @param uint32 menu_id : [GameObject] entry Id * @param uint32 event : [GameObject] gossip event Id, refer to GossipEvents above * @param function function : function to register * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -987,16 +870,6 @@ namespace LuaGlobalFunctions /** * Registers an [Item] event handler. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearItemEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearItemEvents] work as normal. - * *
      * enum ItemEvents
      * {
@@ -1009,15 +882,13 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @proto (entry, event, function) - * @proto (entry, event, function, shots) - * @proto cancel = (entry, event, function, 0, true) + * @proto cancel = (entry, event, function) + * @proto cancel = (entry, event, function, shots) * * @param uint32 entry : [Item] entry Id * @param uint32 event : [Item] event Id, refer to ItemEvents above * @param function function : function to register * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -1029,16 +900,6 @@ namespace LuaGlobalFunctions /** * Registers an [Item] gossip event handler. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearItemGossipEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearItemGossipEvents] work as normal. - * *
      * enum GossipEvents
      * {
@@ -1048,15 +909,13 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @proto (entry, event, function) - * @proto (entry, event, function, shots) - * @proto cancel = (entry, event, function, 0, true) + * @proto cancel = (entry, event, function) + * @proto cancel = (entry, event, function, shots) * * @param uint32 entry : [Item] entry Id * @param uint32 event : [Item] gossip event Id, refer to GossipEvents above * @param function function : function to register * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -1068,16 +927,6 @@ namespace LuaGlobalFunctions /** * Registers a [Player] gossip event handler. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearPlayerGossipEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearPlayerGossipEvents] work as normal. - * *
      * enum GossipEvents
      * {
@@ -1087,15 +936,13 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @proto (menu_id, event, function) - * @proto (menu_id, event, function, shots) - * @proto cancel = (menu_id, event, function, 0, true) + * @proto cancel = (menu_id, event, function) + * @proto cancel = (menu_id, event, function, shots) * * @param uint32 menu_id : [Player] gossip menu Id * @param uint32 event : [Player] gossip event Id, refer to GossipEvents above * @param function function : function to register * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -1107,16 +954,6 @@ namespace LuaGlobalFunctions /** * Registers a [Creature] event handler. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearCreatureEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearCreatureEvents] work as normal. - * *
      * enum CreatureEvents
      * {
@@ -1161,15 +998,13 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @proto (entry, event, function) - * @proto (entry, event, function, shots) - * @proto cancel = (entry, event, function, 0, true) + * @proto cancel = (entry, event, function) + * @proto cancel = (entry, event, function, shots) * * @param uint32 entry : the ID of one or more [Creature]s * @param uint32 event : refer to CreatureEvents above * @param function function : function that will be called when the event occurs * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -1181,16 +1016,6 @@ namespace LuaGlobalFunctions /** * Registers a [Creature] event handler for a *single* [Creature]. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearUniqueCreatureEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearUniqueCreatureEvents] work as normal. - * *
      * enum CreatureEvents
      * {
@@ -1235,16 +1060,14 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @proto (guid, instance_id, event, function) - * @proto (guid, instance_id, event, function, shots) - * @proto cancel = (guid, instance_id, event, function, 0, true) + * @proto cancel = (guid, instance_id, event, function) + * @proto cancel = (guid, instance_id, event, function, shots) * * @param uint64 guid : the GUID of a single [Creature] * @param uint32 instance_id : the instance ID of a single [Creature] * @param uint32 event : refer to CreatureEvents above * @param function function : function that will be called when the event occurs * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -1256,16 +1079,6 @@ namespace LuaGlobalFunctions /** * Registers a [GameObject] event handler. * - * If `return_callback` is `true`, a function will be returned which - * cancels this event binding. - * - * (The returned function is the **only** way to cancel the bindings; - * `shots` must be `0` (e.g. the binding will never expire), and - * [Global:ClearGameObjectEvents] will skip this binding.) - * - * If `return_callback` is `false`, nothing is returned, and `shots` and - * [Global:ClearGameObjectEvents] work as normal. - * *
      * enum GameObjectEvents
      * {
@@ -1286,15 +1099,13 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @proto (entry, event, function) - * @proto (entry, event, function, shots) - * @proto cancel = (entry, event, function, 0, true) + * @proto cancel = (entry, event, function) + * @proto cancel = (entry, event, function, shots) * * @param uint32 entry : [GameObject] entry Id * @param uint32 event : [GameObject] event Id, refer to GameObjectEvents above * @param function function : function to register * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" - * @param bool return_callback = false * * @return function cancel : a function that cancels the binding when called */ @@ -2632,15 +2443,16 @@ namespace LuaGlobalFunctions */ int ClearBattleGroundEvents(Eluna* E, lua_State* L) { + typedef EventKey Key; + if (lua_isnoneornil(L, 1)) { - for (uint32 i = Hooks::BG_EVENT_ON_START; i < Hooks::BG_EVENT_COUNT; ++i) - E->BGEventBindings->Clear(i); + E->BGEventBindings->Clear(); } else { uint32 event_type = Eluna::CHECKVAL(L, 1); - E->BGEventBindings->Clear(event_type); + E->BGEventBindings->Clear(Key((Hooks::BGEvents)event_type)); } return 0; } @@ -2662,18 +2474,20 @@ namespace LuaGlobalFunctions */ int ClearCreatureEvents(Eluna* E, lua_State* L) { + typedef EntryKey Key; + if (lua_isnoneornil(L, 2)) { uint32 entry = Eluna::CHECKVAL(L, 1); - for (uint32 i = Hooks::CREATURE_EVENT_ON_ENTER_COMBAT; i < Hooks::CREATURE_EVENT_COUNT; ++i) - E->CreatureEventBindings->Clear(entry, i); + for (uint32 i = 1; i < Hooks::CREATURE_EVENT_COUNT; ++i) + E->CreatureEventBindings->Clear(Key((Hooks::CreatureEvents)i, entry)); } else { uint32 entry = Eluna::CHECKVAL(L, 1); uint32 event_type = Eluna::CHECKVAL(L, 2); - E->CreatureEventBindings->Clear(entry, event_type); + E->CreatureEventBindings->Clear(Key((Hooks::CreatureEvents)event_type, entry)); } return 0; } @@ -2696,20 +2510,22 @@ namespace LuaGlobalFunctions */ int ClearUniqueCreatureEvents(Eluna* E, lua_State* L) { + typedef UniqueObjectKey Key; + if (lua_isnoneornil(L, 3)) { uint64 guid = Eluna::CHECKVAL(L, 1); uint32 instanceId = Eluna::CHECKVAL(L, 2); - for (uint32 i = Hooks::CREATURE_EVENT_ON_ENTER_COMBAT; i < Hooks::CREATURE_EVENT_COUNT; ++i) - E->CreatureUniqueBindings->Clear(guid, instanceId, i); + for (uint32 i = 1; i < Hooks::CREATURE_EVENT_COUNT; ++i) + E->CreatureUniqueBindings->Clear(Key((Hooks::CreatureEvents)i, guid, instanceId)); } else { uint64 guid = Eluna::CHECKVAL(L, 1); uint32 instanceId = Eluna::CHECKVAL(L, 2); uint32 event_type = Eluna::CHECKVAL(L, 3); - E->CreatureUniqueBindings->Clear(guid, instanceId, event_type); + E->CreatureUniqueBindings->Clear(Key((Hooks::CreatureEvents)event_type, guid, instanceId)); } return 0; } @@ -2731,18 +2547,20 @@ namespace LuaGlobalFunctions */ int ClearCreatureGossipEvents(Eluna* E, lua_State* L) { + typedef EntryKey Key; + if (lua_isnoneornil(L, 2)) { uint32 entry = Eluna::CHECKVAL(L, 1); - for (uint32 i = Hooks::GOSSIP_EVENT_ON_HELLO; i < Hooks::GOSSIP_EVENT_COUNT; ++i) - E->CreatureGossipBindings->Clear(entry, i); + for (uint32 i = 1; i < Hooks::GOSSIP_EVENT_COUNT; ++i) + E->CreatureGossipBindings->Clear(Key((Hooks::GossipEvents)i, entry)); } else { uint32 entry = Eluna::CHECKVAL(L, 1); uint32 event_type = Eluna::CHECKVAL(L, 2); - E->CreatureGossipBindings->Clear(entry, event_type); + E->CreatureGossipBindings->Clear(Key((Hooks::GossipEvents)event_type, entry)); } return 0; } @@ -2764,18 +2582,20 @@ namespace LuaGlobalFunctions */ int ClearGameObjectEvents(Eluna* E, lua_State* L) { + typedef EntryKey Key; + if (lua_isnoneornil(L, 2)) { uint32 entry = Eluna::CHECKVAL(L, 1); - for (uint32 i = Hooks::GAMEOBJECT_EVENT_ON_AIUPDATE; i < Hooks::GAMEOBJECT_EVENT_COUNT; ++i) - E->GameObjectEventBindings->Clear(entry, i); + for (uint32 i = 1; i < Hooks::GAMEOBJECT_EVENT_COUNT; ++i) + E->GameObjectEventBindings->Clear(Key((Hooks::GameObjectEvents)i, entry)); } else { uint32 entry = Eluna::CHECKVAL(L, 1); uint32 event_type = Eluna::CHECKVAL(L, 2); - E->GameObjectEventBindings->Clear(entry, event_type); + E->GameObjectEventBindings->Clear(Key((Hooks::GameObjectEvents)event_type, entry)); } return 0; } @@ -2797,18 +2617,20 @@ namespace LuaGlobalFunctions */ int ClearGameObjectGossipEvents(Eluna* E, lua_State* L) { + typedef EntryKey Key; + if (lua_isnoneornil(L, 2)) { uint32 entry = Eluna::CHECKVAL(L, 1); - for (uint32 i = Hooks::GOSSIP_EVENT_ON_HELLO; i < Hooks::GOSSIP_EVENT_COUNT; ++i) - E->GameObjectGossipBindings->Clear(entry, i); + for (uint32 i = 1; i < Hooks::GOSSIP_EVENT_COUNT; ++i) + E->GameObjectGossipBindings->Clear(Key((Hooks::GossipEvents)i, entry)); } else { uint32 entry = Eluna::CHECKVAL(L, 1); uint32 event_type = Eluna::CHECKVAL(L, 2); - E->GameObjectGossipBindings->Clear(entry, event_type); + E->GameObjectGossipBindings->Clear(Key((Hooks::GossipEvents)event_type, entry)); } return 0; } @@ -2826,15 +2648,16 @@ namespace LuaGlobalFunctions */ int ClearGroupEvents(Eluna* E, lua_State* L) { + typedef EventKey Key; + if (lua_isnoneornil(L, 1)) { - for (uint32 i = Hooks::GROUP_EVENT_ON_MEMBER_ADD; i < Hooks::GROUP_EVENT_COUNT; ++i) - E->GroupEventBindings->Clear(i); + E->GroupEventBindings->Clear(); } else { uint32 event_type = Eluna::CHECKVAL(L, 1); - E->GroupEventBindings->Clear(event_type); + E->GroupEventBindings->Clear(Key((Hooks::GroupEvents)event_type)); } return 0; } @@ -2852,15 +2675,16 @@ namespace LuaGlobalFunctions */ int ClearGuildEvents(Eluna* E, lua_State* L) { + typedef EventKey Key; + if (lua_isnoneornil(L, 1)) { - for (uint32 i = Hooks::GUILD_EVENT_ON_ADD_MEMBER; i < Hooks::GUILD_EVENT_COUNT; ++i) - E->GuildEventBindings->Clear(i); + E->GuildEventBindings->Clear(); } else { uint32 event_type = Eluna::CHECKVAL(L, 1); - E->GuildEventBindings->Clear(event_type); + E->GuildEventBindings->Clear(Key((Hooks::GuildEvents)event_type)); } return 0; } @@ -2882,18 +2706,20 @@ namespace LuaGlobalFunctions */ int ClearItemEvents(Eluna* E, lua_State* L) { + typedef EntryKey Key; + if (lua_isnoneornil(L, 2)) { uint32 entry = Eluna::CHECKVAL(L, 1); - for (uint32 i = Hooks::ITEM_EVENT_ON_DUMMY_EFFECT; i < Hooks::ITEM_EVENT_COUNT; ++i) - E->ItemEventBindings->Clear(entry, i); + for (uint32 i = 1; i < Hooks::ITEM_EVENT_COUNT; ++i) + E->ItemEventBindings->Clear(Key((Hooks::ItemEvents)i, entry)); } else { uint32 entry = Eluna::CHECKVAL(L, 1); uint32 event_type = Eluna::CHECKVAL(L, 2); - E->ItemEventBindings->Clear(entry, event_type); + E->ItemEventBindings->Clear(Key((Hooks::ItemEvents)event_type, entry)); } return 0; } @@ -2915,18 +2741,20 @@ namespace LuaGlobalFunctions */ int ClearItemGossipEvents(Eluna* E, lua_State* L) { + typedef EntryKey Key; + if (lua_isnoneornil(L, 2)) { uint32 entry = Eluna::CHECKVAL(L, 1); - for (uint32 i = Hooks::GOSSIP_EVENT_ON_HELLO; i < Hooks::GOSSIP_EVENT_COUNT; ++i) - E->ItemGossipBindings->Clear(entry, i); + for (uint32 i = 1; i < Hooks::GOSSIP_EVENT_COUNT; ++i) + E->ItemGossipBindings->Clear(Key((Hooks::GossipEvents)i, entry)); } else { uint32 entry = Eluna::CHECKVAL(L, 1); uint32 event_type = Eluna::CHECKVAL(L, 2); - E->ItemGossipBindings->Clear(entry, event_type); + E->ItemGossipBindings->Clear(Key((Hooks::GossipEvents)event_type, entry)); } return 0; } @@ -2945,18 +2773,20 @@ namespace LuaGlobalFunctions */ int ClearPacketEvents(Eluna* E, lua_State* L) { + typedef EntryKey Key; + if (lua_isnoneornil(L, 2)) { uint32 entry = Eluna::CHECKVAL(L, 1); - for (uint32 i = Hooks::PACKET_EVENT_ON_PACKET_RECEIVE; i < Hooks::PACKET_EVENT_COUNT; ++i) - E->PacketEventBindings->Clear(entry, i); + for (uint32 i = 1; i < Hooks::PACKET_EVENT_COUNT; ++i) + E->PacketEventBindings->Clear(Key((Hooks::PacketEvents)i, entry)); } else { uint32 entry = Eluna::CHECKVAL(L, 1); uint32 event_type = Eluna::CHECKVAL(L, 2); - E->PacketEventBindings->Clear(entry, event_type); + E->PacketEventBindings->Clear(Key((Hooks::PacketEvents)event_type, entry)); } return 0; } @@ -2974,15 +2804,16 @@ namespace LuaGlobalFunctions */ int ClearPlayerEvents(Eluna* E, lua_State* L) { + typedef EventKey Key; + if (lua_isnoneornil(L, 1)) { - for (uint32 i = Hooks::PLAYER_EVENT_ON_CHARACTER_CREATE; i < Hooks::PLAYER_EVENT_COUNT; ++i) - E->PlayerEventBindings->Clear(i); + E->PlayerEventBindings->Clear(); } else { uint32 event_type = Eluna::CHECKVAL(L, 1); - E->PlayerEventBindings->Clear(event_type); + E->PlayerEventBindings->Clear(Key((Hooks::PlayerEvents)event_type)); } return 0; } @@ -3001,18 +2832,20 @@ namespace LuaGlobalFunctions */ int ClearPlayerGossipEvents(Eluna* E, lua_State* L) { + typedef EntryKey Key; + if (lua_isnoneornil(L, 2)) { uint32 entry = Eluna::CHECKVAL(L, 1); - for (uint32 i = Hooks::GOSSIP_EVENT_ON_HELLO; i < Hooks::GOSSIP_EVENT_COUNT; ++i) - E->playerGossipBindings->Clear(entry, i); + for (uint32 i = 1; i < Hooks::GOSSIP_EVENT_COUNT; ++i) + E->PlayerGossipBindings->Clear(Key((Hooks::GossipEvents)i, entry)); } else { uint32 entry = Eluna::CHECKVAL(L, 1); uint32 event_type = Eluna::CHECKVAL(L, 2); - E->playerGossipBindings->Clear(entry, event_type); + E->PlayerGossipBindings->Clear(Key((Hooks::GossipEvents)event_type, entry)); } return 0; } @@ -3030,15 +2863,16 @@ namespace LuaGlobalFunctions */ int ClearServerEvents(Eluna* E, lua_State* L) { + typedef EventKey Key; + if (lua_isnoneornil(L, 1)) { - for (uint32 i = Hooks::SERVER_EVENT_ON_NETWORK_START; i < Hooks::SERVER_EVENT_COUNT; ++i) - E->ServerEventBindings->Clear(i); + E->ServerEventBindings->Clear(); } else { uint32 event_type = Eluna::CHECKVAL(L, 1); - E->ServerEventBindings->Clear(event_type); + E->ServerEventBindings->Clear(Key((Hooks::ServerEvents)event_type)); } return 0; } diff --git a/GossipHooks.cpp b/GossipHooks.cpp new file mode 100644 index 0000000..718b86f --- /dev/null +++ b/GossipHooks.cpp @@ -0,0 +1,137 @@ +/* +* Copyright (C) 2010 - 2015 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaIncludes.h" +#include "ElunaTemplate.h" + +using namespace Hooks; + +#define START_HOOK(BINDINGS, EVENT, ENTRY) \ + if (!IsEnabled())\ + return;\ + auto key = EntryKey(EVENT, ENTRY);\ + if (!BINDINGS->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +#define START_HOOK_WITH_RETVAL(BINDINGS, EVENT, ENTRY, RETVAL) \ + if (!IsEnabled())\ + return RETVAL;\ + auto key = EntryKey(EVENT, ENTRY);\ + if (!BINDINGS->HasBindingsFor(key))\ + return RETVAL;\ + LOCK_ELUNA + +bool Eluna::OnGossipHello(Player* pPlayer, GameObject* pGameObject) +{ + START_HOOK_WITH_RETVAL(GameObjectGossipBindings, GOSSIP_EVENT_ON_HELLO, pGameObject->GetEntry(), false); + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pGameObject); + return CallAllFunctionsBool(GameObjectGossipBindings, key, true); +} + +bool Eluna::OnGossipSelect(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action) +{ + START_HOOK_WITH_RETVAL(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry(), false); + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pGameObject); + Push(sender); + Push(action); + return CallAllFunctionsBool(GameObjectGossipBindings, key, true); +} + +bool Eluna::OnGossipSelectCode(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action, const char* code) +{ + START_HOOK_WITH_RETVAL(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry(), false); + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pGameObject); + Push(sender); + Push(action); + Push(code); + return CallAllFunctionsBool(GameObjectGossipBindings, key, true); +} + +void Eluna::HandleGossipSelectOption(Player* pPlayer, uint32 menuId, uint32 sender, uint32 action, const std::string& code) +{ + START_HOOK(PlayerGossipBindings, GOSSIP_EVENT_ON_SELECT, menuId); + pPlayer->PlayerTalkClass->ClearMenus(); + + Push(pPlayer); // receiver + Push(pPlayer); // sender, just not to mess up the amount of args. + Push(sender); + Push(action); + if (code.empty()) + Push(); + else + Push(code); + + CallAllFunctions(PlayerGossipBindings, key); +} + +bool Eluna::OnItemGossip(Player* pPlayer, Item* pItem, SpellCastTargets const& /*targets*/) +{ + START_HOOK_WITH_RETVAL(ItemGossipBindings, GOSSIP_EVENT_ON_HELLO, pItem->GetEntry(), true); + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pItem); + return CallAllFunctionsBool(ItemGossipBindings, key, true); +} + +void Eluna::HandleGossipSelectOption(Player* pPlayer, Item* pItem, uint32 sender, uint32 action, const std::string& code) +{ + START_HOOK(ItemGossipBindings, GOSSIP_EVENT_ON_SELECT, pItem->GetEntry()); + pPlayer->PlayerTalkClass->ClearMenus(); + + Push(pPlayer); + Push(pItem); + Push(sender); + Push(action); + if (code.empty()) + Push(); + else + Push(code); + + CallAllFunctions(ItemGossipBindings, key); +} + +bool Eluna::OnGossipHello(Player* pPlayer, Creature* pCreature) +{ + START_HOOK_WITH_RETVAL(CreatureGossipBindings, GOSSIP_EVENT_ON_HELLO, pCreature->GetEntry(), false); + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pCreature); + return CallAllFunctionsBool(CreatureGossipBindings, key, true); +} + +bool Eluna::OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action) +{ + START_HOOK_WITH_RETVAL(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry(), false); + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pCreature); + Push(sender); + Push(action); + return CallAllFunctionsBool(CreatureGossipBindings, key, true); +} + +bool Eluna::OnGossipSelectCode(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action, const char* code) +{ + START_HOOK_WITH_RETVAL(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry(), false); + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pCreature); + Push(sender); + Push(action); + Push(code); + return CallAllFunctionsBool(CreatureGossipBindings, key, true); +} diff --git a/GroupHooks.cpp b/GroupHooks.cpp index d36e4ca..a891665 100644 --- a/GroupHooks.cpp +++ b/GroupHooks.cpp @@ -4,83 +4,68 @@ * Please see the included DOCS/LICENSE.md for more information */ -#ifndef _GROUP_HOOKS_H -#define _GROUP_HOOKS_H - #include "Hooks.h" #include "HookHelpers.h" #include "LuaEngine.h" -#include "ElunaBinding.h" +#include "BindingMap.h" #include "ElunaTemplate.h" using namespace Hooks; +#define START_HOOK(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!GroupEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + void Eluna::OnAddMember(Group* group, uint64 guid) { - if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_ADD)) - return; - - LOCK_ELUNA; + START_HOOK(GROUP_EVENT_ON_MEMBER_ADD); Push(group); Push(guid); - CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_ADD); + CallAllFunctions(GroupEventBindings, key); } void Eluna::OnInviteMember(Group* group, uint64 guid) { - if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_INVITE)) - return; - - LOCK_ELUNA; + START_HOOK(GROUP_EVENT_ON_MEMBER_INVITE); Push(group); Push(guid); - CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_INVITE); + CallAllFunctions(GroupEventBindings, key); } void Eluna::OnRemoveMember(Group* group, uint64 guid, uint8 method) { - if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_REMOVE)) - return; - - LOCK_ELUNA; + START_HOOK(GROUP_EVENT_ON_MEMBER_REMOVE); Push(group); Push(guid); Push(method); - CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_REMOVE); + CallAllFunctions(GroupEventBindings, key); } void Eluna::OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid) { - if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_LEADER_CHANGE)) - return; - - LOCK_ELUNA; + START_HOOK(GROUP_EVENT_ON_LEADER_CHANGE); Push(group); Push(newLeaderGuid); Push(oldLeaderGuid); - CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_LEADER_CHANGE); + CallAllFunctions(GroupEventBindings, key); } void Eluna::OnDisband(Group* group) { - if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_DISBAND)) - return; - - LOCK_ELUNA; + START_HOOK(GROUP_EVENT_ON_DISBAND); Push(group); - CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_DISBAND); + CallAllFunctions(GroupEventBindings, key); } void Eluna::OnCreate(Group* group, uint64 leaderGuid, GroupType groupType) { - if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_CREATE)) - return; - - LOCK_ELUNA; + START_HOOK(GROUP_EVENT_ON_CREATE); Push(group); Push(leaderGuid); Push(groupType); - CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_CREATE); + CallAllFunctions(GroupEventBindings, key); } - -#endif // _GROUP_HOOKS_H diff --git a/GuildHooks.cpp b/GuildHooks.cpp index 4f57bfa..5d1079a 100644 --- a/GuildHooks.cpp +++ b/GuildHooks.cpp @@ -4,97 +4,81 @@ * Please see the included DOCS/LICENSE.md for more information */ -#ifndef _GUILD_HOOKS_H -#define _GUILD_HOOKS_H - #include "Hooks.h" #include "HookHelpers.h" #include "LuaEngine.h" -#include "ElunaBinding.h" +#include "BindingMap.h" #include "ElunaTemplate.h" using namespace Hooks; +#define START_HOOK(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!GuildEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + void Eluna::OnAddMember(Guild* guild, Player* player, uint32 plRank) { - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_ADD_MEMBER)) - return; - - LOCK_ELUNA; + START_HOOK(GUILD_EVENT_ON_ADD_MEMBER); Push(guild); Push(player); Push(plRank); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_ADD_MEMBER); + CallAllFunctions(GuildEventBindings, key); } void Eluna::OnRemoveMember(Guild* guild, Player* player, bool isDisbanding) { - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_REMOVE_MEMBER)) - return; - - LOCK_ELUNA; + START_HOOK(GUILD_EVENT_ON_REMOVE_MEMBER); Push(guild); Push(player); Push(isDisbanding); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_REMOVE_MEMBER); + CallAllFunctions(GuildEventBindings, key); } void Eluna::OnMOTDChanged(Guild* guild, const std::string& newMotd) { - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MOTD_CHANGE)) - return; - - LOCK_ELUNA; + START_HOOK(GUILD_EVENT_ON_MOTD_CHANGE); Push(guild); Push(newMotd); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_MOTD_CHANGE); + CallAllFunctions(GuildEventBindings, key); } void Eluna::OnInfoChanged(Guild* guild, const std::string& newInfo) { - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_INFO_CHANGE)) - return; - - LOCK_ELUNA; + START_HOOK(GUILD_EVENT_ON_INFO_CHANGE); Push(guild); Push(newInfo); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_INFO_CHANGE); + CallAllFunctions(GuildEventBindings, key); } void Eluna::OnCreate(Guild* guild, Player* leader, const std::string& name) { - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_CREATE)) - return; - - LOCK_ELUNA; + START_HOOK(GUILD_EVENT_ON_CREATE); Push(guild); Push(leader); Push(name); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_CREATE); + CallAllFunctions(GuildEventBindings, key); } void Eluna::OnDisband(Guild* guild) { - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_DISBAND)) - return; - - LOCK_ELUNA; + START_HOOK(GUILD_EVENT_ON_DISBAND); Push(guild); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_DISBAND); + CallAllFunctions(GuildEventBindings, key); } void Eluna::OnMemberWitdrawMoney(Guild* guild, Player* player, uint32& amount, bool isRepair) // isRepair not a part of Mangos, implement? { - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MONEY_WITHDRAW)) - return; - - LOCK_ELUNA; + START_HOOK(GUILD_EVENT_ON_MONEY_WITHDRAW); Push(guild); Push(player); Push(amount); Push(isRepair); // isRepair not a part of Mangos, implement? int amountIndex = lua_gettop(L) - 1; - int n = SetupStack(GuildEventBindings, GUILD_EVENT_ON_MONEY_WITHDRAW, 4); + int n = SetupStack(GuildEventBindings, key, 4); while (n > 0) { @@ -115,15 +99,12 @@ void Eluna::OnMemberWitdrawMoney(Guild* guild, Player* player, uint32& amount, b void Eluna::OnMemberDepositMoney(Guild* guild, Player* player, uint32& amount) { - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MONEY_DEPOSIT)) - return; - - LOCK_ELUNA; + START_HOOK(GUILD_EVENT_ON_MONEY_DEPOSIT); Push(guild); Push(player); Push(amount); int amountIndex = lua_gettop(L); - int n = SetupStack(GuildEventBindings, GUILD_EVENT_ON_MONEY_DEPOSIT, 3); + int n = SetupStack(GuildEventBindings, key, 3); while (n > 0) { @@ -145,10 +126,7 @@ void Eluna::OnMemberDepositMoney(Guild* guild, Player* player, uint32& amount) void Eluna::OnItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId, bool isDestBank, uint8 destContainer, uint8 destSlotId) { - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_ITEM_MOVE)) - return; - - LOCK_ELUNA; + START_HOOK(GUILD_EVENT_ON_ITEM_MOVE); Push(guild); Push(player); Push(pItem); @@ -158,29 +136,23 @@ void Eluna::OnItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank Push(isDestBank); Push(destContainer); Push(destSlotId); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_ITEM_MOVE); + CallAllFunctions(GuildEventBindings, key); } void Eluna::OnEvent(Guild* guild, uint8 eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank) { - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_EVENT)) - return; - - LOCK_ELUNA; + START_HOOK(GUILD_EVENT_ON_EVENT); Push(guild); Push(eventType); Push(playerGuid1); Push(playerGuid2); Push(newRank); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_EVENT); + CallAllFunctions(GuildEventBindings, key); } void Eluna::OnBankEvent(Guild* guild, uint8 eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) { - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_BANK_EVENT)) - return; - - LOCK_ELUNA; + START_HOOK(GUILD_EVENT_ON_BANK_EVENT); Push(guild); Push(eventType); Push(tabId); @@ -188,7 +160,5 @@ void Eluna::OnBankEvent(Guild* guild, uint8 eventType, uint8 tabId, uint32 playe Push(itemOrMoney); Push(itemStackCount); Push(destTabId); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_BANK_EVENT); + CallAllFunctions(GuildEventBindings, key); } - -#endif // _GUILD_HOOKS_H diff --git a/HookHelpers.h b/HookHelpers.h index e36f1cd..844791f 100644 --- a/HookHelpers.h +++ b/HookHelpers.h @@ -14,18 +14,15 @@ * Sets up the stack so that event handlers can be called. * * Returns the number of functions that were pushed onto the stack. - * - * Use the simpler overloads for just EventBind or EntryBind instead of this overload in hooks. */ -template -int Eluna::SetupStack(EventBind* event_bindings, EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, int number_of_arguments) +template +int Eluna::SetupStack(BindingMap* bindings1, BindingMap* bindings2, const K1& key1, const K2& key2, int number_of_arguments) { - // Ensure that if `entry_bindings` is not NULL, a valid entry is supplied. - ASSERT(!entry_bindings || (entry_bindings && entry > 0)); ASSERT(number_of_arguments == this->push_counter); + ASSERT(key1.event_id == key2.event_id); // Stack: [arguments] - Push(event_id); + Push(key1.event_id); this->push_counter = 0; ++number_of_arguments; // Stack: [arguments], event_id @@ -37,14 +34,9 @@ int Eluna::SetupStack(EventBind* event_bindings, EntryBind* entry_bindings lua_insert(L, first_argument_index); // Stack: event_id, [arguments] - if (event_bindings) - event_bindings->PushFuncRefs(L, (int)event_id); - - if (entry_bindings) - entry_bindings->PushFuncRefs(L, (int)event_id, entry); - - if (guid_bindings) - guid_bindings->PushFuncRefs(L, (int)event_id, guid, instanceId); + bindings1->PushRefsFor(key1); + if (bindings2) + bindings2->PushRefsFor(key2); // Stack: event_id, [arguments], [functions] int number_of_functions = lua_gettop(L) - arguments_top; @@ -70,13 +62,13 @@ void Eluna::ReplaceArgument(T value, uint8 index) /* * Call all event handlers registered to the event ID/entry combination and ignore any results. */ -template -void Eluna::CallAllFunctions(EventBind* event_bindings, EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId) +template +void Eluna::CallAllFunctions(BindingMap* bindings1, BindingMap* bindings2, const K1& key1, const K2& key2) { int number_of_arguments = this->push_counter; // Stack: [arguments] - int number_of_functions = SetupStack(event_bindings, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments); + int number_of_functions = SetupStack(bindings1, bindings2, key1, key2, number_of_arguments); // Stack: event_id, [arguments], [functions] while (number_of_functions > 0) @@ -96,15 +88,15 @@ void Eluna::CallAllFunctions(EventBind* event_bindings, EntryBind* entry_b * and returns `default_value` if ALL event handlers returned `default_value`, * otherwise returns the opposite of `default_value`. */ -template -bool Eluna::CallAllFunctionsBool(EventBind* event_bindings, EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value) +template +bool Eluna::CallAllFunctionsBool(BindingMap* bindings1, BindingMap* bindings2, const K1& key1, const K2& key2, bool default_value/* = false*/) { bool result = default_value; // Note: number_of_arguments here does not count in eventID, which is pushed in SetupStack int number_of_arguments = this->push_counter; // Stack: [arguments] - int number_of_functions = SetupStack(event_bindings, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments); + int number_of_functions = SetupStack(bindings1, bindings2, key1, key2, number_of_arguments); // Stack: event_id, [arguments], [functions] while (number_of_functions > 0) diff --git a/Hooks.h b/Hooks.h index e7b7609..262307e 100644 --- a/Hooks.h +++ b/Hooks.h @@ -13,7 +13,7 @@ * A. If results will be IGNORED: * * // Return early if there are no bindings. - * if (!WhateverBindings->HasEvents(SOME_EVENT_TYPE)) + * if (!WhateverBindings->HasBindingsFor(SOME_EVENT_TYPE)) * return; * * // Lock out any other threads. @@ -31,7 +31,7 @@ * B. If results will be USED: * * // Return early if there are no bindings. - * if (!WhateverBindings->HasEvents(SOME_EVENT_TYPE)) + * if (!WhateverBindings->HasBindingsFor(SOME_EVENT_TYPE)) * return; * * // Lock out any other threads. diff --git a/ItemHooks.cpp b/ItemHooks.cpp index 196cf2c..58db391 100644 --- a/ItemHooks.cpp +++ b/ItemHooks.cpp @@ -4,41 +4,40 @@ * Please see the included DOCS/LICENSE.md for more information */ -#ifndef _ITEM_HOOKS_H -#define _ITEM_HOOKS_H - #include "Hooks.h" #include "HookHelpers.h" #include "LuaEngine.h" -#include "ElunaBinding.h" +#include "BindingMap.h" #include "ElunaIncludes.h" #include "ElunaTemplate.h" using namespace Hooks; +#define START_HOOK_WITH_RETVAL(EVENT, ENTRY, RETVAL) \ + if (!IsEnabled())\ + return RETVAL;\ + auto key = EntryKey(EVENT, ENTRY);\ + if (!ItemEventBindings->HasBindingsFor(key))\ + return RETVAL;\ + LOCK_ELUNA + bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Item* pTarget) { - if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry(), false); Push(pCaster); Push(spellId); Push(effIndex); Push(pTarget); - return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()); + return CallAllFunctionsBool(ItemEventBindings, key); } bool Eluna::OnQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest) { - if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_QUEST_ACCEPT, pItem->GetEntry())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_QUEST_ACCEPT, pItem->GetEntry(), false); Push(pPlayer); Push(pItem); Push(pQuest); - return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_QUEST_ACCEPT, pItem->GetEntry()); + return CallAllFunctionsBool(ItemEventBindings, key); } bool Eluna::OnUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) @@ -73,10 +72,7 @@ bool Eluna::OnUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) bool Eluna::OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) { - if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_USE, pItem->GetEntry())) - return true; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_USE, pItem->GetEntry(), true); Push(pPlayer); Push(pItem); #ifndef TRINITY @@ -105,41 +101,21 @@ bool Eluna::OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targ Push(); #endif - return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_USE, pItem->GetEntry(), true); -} - -bool Eluna::OnItemGossip(Player* pPlayer, Item* pItem, SpellCastTargets const& /*targets*/) -{ - if (!ItemGossipBindings->HasEvents(GOSSIP_EVENT_ON_HELLO, pItem->GetEntry())) - return true; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pItem); - return CallAllFunctionsBool(ItemGossipBindings, GOSSIP_EVENT_ON_HELLO, pItem->GetEntry(), true); + return CallAllFunctionsBool(ItemEventBindings, key, true); } bool Eluna::OnExpire(Player* pPlayer, ItemTemplate const* pProto) { - if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_EXPIRE, pProto->ItemId)) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_EXPIRE, pProto->ItemId, false); Push(pPlayer); Push(pProto->ItemId); - return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_EXPIRE, pProto->ItemId); + return CallAllFunctionsBool(ItemEventBindings, key); } -bool Eluna::OnRemove(Player* pPlayer, Item* item) +bool Eluna::OnRemove(Player* pPlayer, Item* pItem) { - if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_REMOVE, item->GetEntry())) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_REMOVE, pItem->GetEntry(), false); Push(pPlayer); - Push(item); - return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_REMOVE, item->GetEntry()); + Push(pItem); + return CallAllFunctionsBool(ItemEventBindings, key); } - -#endif // _ITEM_HOOKS_H diff --git a/LuaEngine.cpp b/LuaEngine.cpp index dc988b1..7905abe 100644 --- a/LuaEngine.cpp +++ b/LuaEngine.cpp @@ -6,7 +6,7 @@ #include "Hooks.h" #include "LuaEngine.h" -#include "ElunaBinding.h" +#include "BindingMap.h" #include "ElunaEventMgr.h" #include "ElunaIncludes.h" #include "ElunaTemplate.h" @@ -151,7 +151,7 @@ GameObjectEventBindings(NULL), GameObjectGossipBindings(NULL), ItemEventBindings(NULL), ItemGossipBindings(NULL), -playerGossipBindings(NULL), +PlayerGossipBindings(NULL), CreatureUniqueBindings(NULL) { @@ -189,8 +189,6 @@ void Eluna::CloseLua() void Eluna::OpenLua() { - CreateBindStores(); - enabled = eConfigMgr->GetBoolDefault("Eluna.Enabled", true); if (!IsEnabled()) { @@ -199,6 +197,7 @@ void Eluna::OpenLua() } L = luaL_newstate(); + CreateBindStores(); // open base lua libraries luaL_openlibs(L); @@ -229,23 +228,23 @@ void Eluna::CreateBindStores() { DestroyBindStores(); - ServerEventBindings = new EventBind("ServerEvents", *this); - PlayerEventBindings = new EventBind("PlayerEvents", *this); - GuildEventBindings = new EventBind("GuildEvents", *this); - GroupEventBindings = new EventBind("GroupEvents", *this); - VehicleEventBindings = new EventBind("VehicleEvents", *this); - BGEventBindings = new EventBind("BGEvents", *this); + ServerEventBindings = new BindingMap< EventKey >(L); + PlayerEventBindings = new BindingMap< EventKey >(L); + GuildEventBindings = new BindingMap< EventKey >(L); + GroupEventBindings = new BindingMap< EventKey >(L); + VehicleEventBindings = new BindingMap< EventKey >(L); + BGEventBindings = new BindingMap< EventKey >(L); - PacketEventBindings = new EntryBind("PacketEvents", *this); - CreatureEventBindings = new EntryBind("CreatureEvents", *this); - CreatureGossipBindings = new EntryBind("GossipEvents (creature)", *this); - GameObjectEventBindings = new EntryBind("GameObjectEvents", *this); - GameObjectGossipBindings = new EntryBind("GossipEvents (gameobject)", *this); - ItemEventBindings = new EntryBind("ItemEvents", *this); - ItemGossipBindings = new EntryBind("GossipEvents (item)", *this); - playerGossipBindings = new EntryBind("GossipEvents (player)", *this); + PacketEventBindings = new BindingMap< EntryKey >(L); + CreatureEventBindings = new BindingMap< EntryKey >(L); + CreatureGossipBindings = new BindingMap< EntryKey >(L); + GameObjectEventBindings = new BindingMap< EntryKey >(L); + GameObjectGossipBindings = new BindingMap< EntryKey >(L); + ItemEventBindings = new BindingMap< EntryKey >(L); + ItemGossipBindings = new BindingMap< EntryKey >(L); + PlayerGossipBindings = new BindingMap< EntryKey >(L); - CreatureUniqueBindings = new UniqueBind("CreatureEvents (unique)", *this); + CreatureUniqueBindings = new BindingMap< UniqueObjectKey >(L); } void Eluna::DestroyBindStores() @@ -263,7 +262,7 @@ void Eluna::DestroyBindStores() delete GameObjectGossipBindings; delete ItemEventBindings; delete ItemGossipBindings; - delete playerGossipBindings; + delete PlayerGossipBindings; delete BGEventBindings; delete CreatureUniqueBindings; @@ -281,7 +280,7 @@ void Eluna::DestroyBindStores() GameObjectGossipBindings = NULL; ItemEventBindings = NULL; ItemGossipBindings = NULL; - playerGossipBindings = NULL; + PlayerGossipBindings = NULL; BGEventBindings = NULL; CreatureUniqueBindings = NULL; @@ -435,7 +434,7 @@ void Eluna::RunScripts() scripts.insert(scripts.end(), lua_extensions.begin(), lua_extensions.end()); scripts.insert(scripts.end(), lua_scripts.begin(), lua_scripts.end()); - UNORDERED_MAP loaded; // filename, path + std::unordered_map loaded; // filename, path lua_getglobal(L, "package"); // Stack: package @@ -907,333 +906,239 @@ ElunaObject* Eluna::CHECKTYPE(lua_State* luastate, int narg, const char* tname, return *ptrHold; } +template static int cancelBinding(lua_State *L) { - int ref = lua_tointeger(L, lua_upvalueindex(1)); - uint32 event_id = lua_tounsigned(L, lua_upvalueindex(2)); - uint32 entry_id = lua_tounsigned(L, lua_upvalueindex(3)); - uint64 guid = Eluna::CHECKVAL(L, lua_upvalueindex(4)); + uint64 bindingID = Eluna::CHECKVAL(L, lua_upvalueindex(1)); - // This marker (initially `false`) is used to protect against calling this callback twice. - // After the first call, `alreadyCalled` will be `true`, so we know not to proceed. - bool alreadyCalled = lua_toboolean(L, lua_upvalueindex(5)); + BindingMap* bindings = (BindingMap*)lua_touserdata(L, lua_upvalueindex(2)); + ASSERT(bindings != NULL); - if (alreadyCalled) - return 0; - else - { - lua_pushboolean(L, true); - lua_replace(L, lua_upvalueindex(5)); - } - - ElunaBind* bindings1 = (ElunaBind*)lua_touserdata(L, lua_upvalueindex(6)); - ASSERT(bindings1 != NULL); - bindings1->ClearOne(ref, event_id, entry_id, guid); + bindings->Remove(bindingID); return 0; } -static int createCancelCallback(lua_State* L, int ref, ElunaBind* bindings1, uint32 event_id, uint32 entry_id = 0, uint64 guid = 0) +template +static void createCancelCallback(lua_State* L, uint64 bindingID, BindingMap* bindings) { - lua_pushinteger(L, ref); - lua_pushunsigned(L, event_id); - lua_pushunsigned(L, entry_id); - Eluna::Push(L, guid); - lua_pushboolean(L, false); - lua_pushlightuserdata(L, bindings1); - // Stack: ref, event_id, entry_id, guid, false, bindings1 + Eluna::Push(L, bindingID); + lua_pushlightuserdata(L, bindings); + // Stack: bindingID, bindings - lua_pushcclosure(L, &cancelBinding, 6); - // Stack: cancel_callback - - lua_pushvalue(L, -1); - return luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushcclosure(L, &cancelBinding, 2); // Stack: cancel_callback } // Saves the function reference ID given to the register type's store for given entry under the given event -int Eluna::Register(lua_State* L, uint8 regtype, uint32 id, uint64 guid, uint32 instanceId, uint32 evt, int functionRef, uint32 shots, bool returnCallback) +int Eluna::Register(lua_State* L, uint8 regtype, uint32 entry, uint64 guid, uint32 instanceId, uint32 event_id, int functionRef, uint32 shots) { + uint64 bindingID; + switch (regtype) { case Hooks::REGTYPE_SERVER: - if (evt < Hooks::SERVER_EVENT_COUNT) + if (event_id < Hooks::SERVER_EVENT_COUNT) { - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, ServerEventBindings, evt); - ServerEventBindings->Insert(evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - ServerEventBindings->Insert(evt, functionRef, shots); - return 0; // Stack: (empty) + auto key = EventKey((Hooks::ServerEvents)event_id); + bindingID = ServerEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, ServerEventBindings); + return 1; // Stack: callback } break; case Hooks::REGTYPE_PLAYER: - if (evt < Hooks::PLAYER_EVENT_COUNT) + if (event_id < Hooks::PLAYER_EVENT_COUNT) { - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, PlayerEventBindings, evt); - PlayerEventBindings->Insert(evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - PlayerEventBindings->Insert(evt, functionRef, shots); - return 0; // Stack: (empty) + auto key = EventKey((Hooks::PlayerEvents)event_id); + bindingID = PlayerEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, PlayerEventBindings); + return 1; // Stack: callback } break; case Hooks::REGTYPE_GUILD: - if (evt < Hooks::GUILD_EVENT_COUNT) + if (event_id < Hooks::GUILD_EVENT_COUNT) { - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, GuildEventBindings, evt); - GuildEventBindings->Insert(evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - GuildEventBindings->Insert(evt, functionRef, shots); - return 0; // Stack: (empty) + auto key = EventKey((Hooks::GuildEvents)event_id); + bindingID = GuildEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, GuildEventBindings); + return 1; // Stack: callback } break; case Hooks::REGTYPE_GROUP: - if (evt < Hooks::GROUP_EVENT_COUNT) + if (event_id < Hooks::GROUP_EVENT_COUNT) { - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, GroupEventBindings, evt); - GroupEventBindings->Insert(evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - GroupEventBindings->Insert(evt, functionRef, shots); - return 0; // Stack: (empty) + auto key = EventKey((Hooks::GroupEvents)event_id); + bindingID = GroupEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, GroupEventBindings); + return 1; // Stack: callback } break; case Hooks::REGTYPE_VEHICLE: - if (evt < Hooks::VEHICLE_EVENT_COUNT) + if (event_id < Hooks::VEHICLE_EVENT_COUNT) { - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, VehicleEventBindings, evt); - VehicleEventBindings->Insert(evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - VehicleEventBindings->Insert(evt, functionRef, shots); - return 0; // Stack: (empty) + auto key = EventKey((Hooks::VehicleEvents)event_id); + bindingID = VehicleEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, VehicleEventBindings); + return 1; // Stack: callback } break; case Hooks::REGTYPE_BG: - if (evt < Hooks::BG_EVENT_COUNT) + if (event_id < Hooks::BG_EVENT_COUNT) { - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, BGEventBindings, evt); - BGEventBindings->Insert(evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - BGEventBindings->Insert(evt, functionRef, shots); - return 0; // Stack: (empty) + auto key = EventKey((Hooks::BGEvents)event_id); + bindingID = BGEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, BGEventBindings); + return 1; // Stack: callback } break; case Hooks::REGTYPE_PACKET: - if (evt < Hooks::PACKET_EVENT_COUNT) + if (event_id < Hooks::PACKET_EVENT_COUNT) { - if (id >= NUM_MSG_TYPES) + if (entry >= NUM_MSG_TYPES) { luaL_unref(L, LUA_REGISTRYINDEX, functionRef); - luaL_error(L, "Couldn't find a creature with (ID: %d)!", id); + luaL_error(L, "Couldn't find a creature with (ID: %d)!", entry); return 0; // Stack: (empty) } - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, PacketEventBindings, evt, id); - PacketEventBindings->Insert(id, evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - PacketEventBindings->Insert(id, evt, functionRef, shots); - return 0; // Stack: (empty) + auto key = EntryKey((Hooks::PacketEvents)event_id, entry); + bindingID = PacketEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, PacketEventBindings); + return 1; // Stack: callback } break; case Hooks::REGTYPE_CREATURE: - if (evt < Hooks::CREATURE_EVENT_COUNT) + if (event_id < Hooks::CREATURE_EVENT_COUNT) { - if (id != 0) + if (entry != 0) { - if (!eObjectMgr->GetCreatureTemplate(id)) + if (!eObjectMgr->GetCreatureTemplate(entry)) { luaL_unref(L, LUA_REGISTRYINDEX, functionRef); - luaL_error(L, "Couldn't find a creature with (ID: %d)!", id); + luaL_error(L, "Couldn't find a creature with (ID: %d)!", entry); return 0; // Stack: (empty) } - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, CreatureEventBindings, evt, id); - CreatureEventBindings->Insert(id, evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - CreatureEventBindings->Insert(id, evt, functionRef, shots); + auto key = EntryKey((Hooks::CreatureEvents)event_id, entry); + bindingID = CreatureEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, CreatureEventBindings); } else { ASSERT(guid != 0); - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, CreatureUniqueBindings, evt, instanceId, guid); - CreatureUniqueBindings->Insert(guid, instanceId, evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - CreatureUniqueBindings->Insert(guid, instanceId, evt, functionRef, shots); + auto key = UniqueObjectKey((Hooks::CreatureEvents)event_id, guid, instanceId); + bindingID = CreatureUniqueBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, CreatureUniqueBindings); } - - return 0; // Stack: (empty) + return 1; // Stack: callback } break; case Hooks::REGTYPE_CREATURE_GOSSIP: - if (evt < Hooks::GOSSIP_EVENT_COUNT) + if (event_id < Hooks::GOSSIP_EVENT_COUNT) { - if (!eObjectMgr->GetCreatureTemplate(id)) + if (!eObjectMgr->GetCreatureTemplate(entry)) { luaL_unref(L, LUA_REGISTRYINDEX, functionRef); - luaL_error(L, "Couldn't find a creature with (ID: %d)!", id); + luaL_error(L, "Couldn't find a creature with (ID: %d)!", entry); return 0; // Stack: (empty) } - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, CreatureGossipBindings, evt, id); - CreatureGossipBindings->Insert(id, evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - CreatureGossipBindings->Insert(id, evt, functionRef, shots); - return 0; // Stack: (empty) + auto key = EntryKey((Hooks::GossipEvents)event_id, entry); + bindingID = CreatureGossipBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, CreatureGossipBindings); + return 1; // Stack: callback } break; case Hooks::REGTYPE_GAMEOBJECT: - if (evt < Hooks::GAMEOBJECT_EVENT_COUNT) + if (event_id < Hooks::GAMEOBJECT_EVENT_COUNT) { - if (!eObjectMgr->GetGameObjectTemplate(id)) + if (!eObjectMgr->GetGameObjectTemplate(entry)) { luaL_unref(L, LUA_REGISTRYINDEX, functionRef); - luaL_error(L, "Couldn't find a gameobject with (ID: %d)!", id); + luaL_error(L, "Couldn't find a gameobject with (ID: %d)!", entry); return 0; // Stack: (empty) } - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, GameObjectEventBindings, evt, id); - GameObjectEventBindings->Insert(id, evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - GameObjectEventBindings->Insert(id, evt, functionRef, shots); - return 0; // Stack: (empty) + auto key = EntryKey((Hooks::GameObjectEvents)event_id, entry); + bindingID = GameObjectEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, GameObjectEventBindings); + return 1; // Stack: callback } break; case Hooks::REGTYPE_GAMEOBJECT_GOSSIP: - if (evt < Hooks::GOSSIP_EVENT_COUNT) + if (event_id < Hooks::GOSSIP_EVENT_COUNT) { - if (!eObjectMgr->GetGameObjectTemplate(id)) + if (!eObjectMgr->GetGameObjectTemplate(entry)) { luaL_unref(L, LUA_REGISTRYINDEX, functionRef); - luaL_error(L, "Couldn't find a gameobject with (ID: %d)!", id); + luaL_error(L, "Couldn't find a gameobject with (ID: %d)!", entry); return 0; // Stack: (empty) } - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, GameObjectGossipBindings, evt, id); - GameObjectGossipBindings->Insert(id, evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - GameObjectGossipBindings->Insert(id, evt, functionRef, shots); - return 0; // Stack: (empty) + auto key = EntryKey((Hooks::GossipEvents)event_id, entry); + bindingID = GameObjectGossipBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, GameObjectGossipBindings); + return 1; // Stack: callback } break; case Hooks::REGTYPE_ITEM: - if (evt < Hooks::ITEM_EVENT_COUNT) + if (event_id < Hooks::ITEM_EVENT_COUNT) { - if (!eObjectMgr->GetItemTemplate(id)) + if (!eObjectMgr->GetItemTemplate(entry)) { luaL_unref(L, LUA_REGISTRYINDEX, functionRef); - luaL_error(L, "Couldn't find a item with (ID: %d)!", id); + luaL_error(L, "Couldn't find a item with (ID: %d)!", entry); return 0; // Stack: (empty) } - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, ItemEventBindings, evt, id); - ItemEventBindings->Insert(id, evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - ItemEventBindings->Insert(id, evt, functionRef, shots); - return 0; // Stack: (empty) + auto key = EntryKey((Hooks::ItemEvents)event_id, entry); + bindingID = ItemEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, ItemEventBindings); + return 1; // Stack: callback } break; case Hooks::REGTYPE_ITEM_GOSSIP: - if (evt < Hooks::GOSSIP_EVENT_COUNT) + if (event_id < Hooks::GOSSIP_EVENT_COUNT) { - if (!eObjectMgr->GetItemTemplate(id)) + if (!eObjectMgr->GetItemTemplate(entry)) { luaL_unref(L, LUA_REGISTRYINDEX, functionRef); - luaL_error(L, "Couldn't find a item with (ID: %d)!", id); + luaL_error(L, "Couldn't find a item with (ID: %d)!", entry); return 0; // Stack: (empty) } - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, ItemGossipBindings, evt, id); - ItemGossipBindings->Insert(id, evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - ItemGossipBindings->Insert(id, evt, functionRef, shots); - return 0; // Stack: (empty) + auto key = EntryKey((Hooks::GossipEvents)event_id, entry); + bindingID = ItemGossipBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, ItemGossipBindings); + return 1; // Stack: callback } break; case Hooks::REGTYPE_PLAYER_GOSSIP: - if (evt < Hooks::GOSSIP_EVENT_COUNT) + if (event_id < Hooks::GOSSIP_EVENT_COUNT) { - if (returnCallback) - { - int callbackRef = createCancelCallback(L, functionRef, playerGossipBindings, evt, id); - playerGossipBindings->Insert(id, evt, functionRef, shots, callbackRef); - return 1; // Stack: callback - } - - playerGossipBindings->Insert(id, evt, functionRef, shots); - return 0; // Stack: (empty) + auto key = EntryKey((Hooks::GossipEvents)event_id, entry); + bindingID = PlayerGossipBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, PlayerGossipBindings); + return 1; // Stack: callback } break; } luaL_unref(L, LUA_REGISTRYINDEX, functionRef); - luaL_error(L, "Unknown event type (regtype %d, id %d, event %d)", regtype, id, evt); + luaL_error(L, "Unknown event type (regtype %hhu, event %u, entry %u, guid " UI64FMTD ", instance %u)", regtype, event_id, entry, guid, instanceId); return 0; } @@ -1283,9 +1188,20 @@ int Eluna::CallOneFunction(int number_of_functions, int number_of_arguments, int CreatureAI* Eluna::GetAI(Creature* creature) { - if (CreatureEventBindings->HasEvents(creature->GetEntry()) || - CreatureUniqueBindings->HasEvents(creature->GET_GUID(), creature->GetInstanceId())) - return new ElunaCreatureAI(creature); + if (!IsEnabled()) + return NULL; + + for (int i = 1; i < Hooks::CREATURE_EVENT_COUNT; ++i) + { + Hooks::CreatureEvents event_id = (Hooks::CreatureEvents)i; + + auto entryKey = EntryKey(event_id, creature->GetEntry()); + auto uniqueKey = UniqueObjectKey(event_id, creature->GET_GUID(), creature->GetInstanceId()); + + if (CreatureEventBindings->HasBindingsFor(entryKey) || + CreatureUniqueBindings->HasBindingsFor(uniqueKey)) + return new ElunaCreatureAI(creature); + } return NULL; } diff --git a/LuaEngine.h b/LuaEngine.h index 44c9dca..2da30c5 100644 --- a/LuaEngine.h +++ b/LuaEngine.h @@ -86,14 +86,12 @@ typedef VehicleInfo Vehicle; struct lua_State; class EventMgr; class ElunaObject; -template -class ElunaTemplate; -template -class EventBind; -template -class EntryBind; -template -class UniqueBind; +template class ElunaTemplate; + +template class BindingMap; +template struct EventKey; +template struct EntryKey; +template struct UniqueObjectKey; struct LuaScript { @@ -164,53 +162,26 @@ private: // Some helpers for hooks to call event handlers. // The bodies of the templates are in HookHelpers.h, so if you want to use them you need to #include "HookHelpers.h". - template int SetupStack(EventBind* event_bindings, EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, int number_of_arguments); - int CallOneFunction(int number_of_functions, int number_of_arguments, int number_of_results); - void CleanUpStack(int number_of_arguments); - template void ReplaceArgument(T value, uint8 index); - template void CallAllFunctions(EventBind* event_bindings, EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId); - template bool CallAllFunctionsBool(EventBind* event_bindings, EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value); + template int SetupStack(BindingMap* bindings1, BindingMap* bindings2, const K1& key1, const K2& key2, int number_of_arguments); + int CallOneFunction(int number_of_functions, int number_of_arguments, int number_of_results); + void CleanUpStack(int number_of_arguments); + template void ReplaceArgument(T value, uint8 index); + template void CallAllFunctions(BindingMap* bindings1, BindingMap* bindings2, const K1& key1, const K2& key2); + template bool CallAllFunctionsBool(BindingMap* bindings1, BindingMap* bindings2, const K1& key1, const K2& key2, bool default_value = false); - // Convenient overloads for Setup. Use these in hooks instead of original. - template int SetupStack(EventBind* event_bindings, T event_id, int number_of_arguments) + // Same as above but for only one binding instead of two. + // `key` is passed twice because there's no NULL for references, but it's not actually used if `bindings2` is NULL. + template int SetupStack(BindingMap* bindings, const K& key, int number_of_arguments) { - return SetupStack(event_bindings, (EntryBind*)NULL, (UniqueBind*)NULL, event_id, 0, 0, 0, number_of_arguments); + return SetupStack(bindings, NULL, key, key, number_of_arguments); } - template int SetupStack(EntryBind* entry_bindings, T event_id, uint32 entry, int number_of_arguments) + template void CallAllFunctions(BindingMap* bindings, const K& key) { - return SetupStack((EventBind*)NULL, entry_bindings, (UniqueBind*)NULL, event_id, entry, 0, 0, number_of_arguments); + CallAllFunctions(bindings, NULL, key, key); } - template int SetupStack(EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, int number_of_arguments) + template bool CallAllFunctionsBool(BindingMap* bindings, const K& key, bool default_value = false) { - return SetupStack((EventBind*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments); - } - - // Convenient overloads for CallAllFunctions. Use these in hooks instead of original. - template void CallAllFunctions(EventBind* event_bindings, T event_id) - { - CallAllFunctions(event_bindings, (EntryBind*)NULL, (UniqueBind*)NULL, event_id, 0, 0, 0); - } - template void CallAllFunctions(EntryBind* entry_bindings, T event_id, uint32 entry) - { - CallAllFunctions((EventBind*)NULL, entry_bindings, (UniqueBind*)NULL, event_id, entry, 0, 0); - } - template void CallAllFunctions(EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId) - { - CallAllFunctions((EventBind*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId); - } - - // Convenient overloads for CallAllFunctionsBool. Use these in hooks instead of original. - template bool CallAllFunctionsBool(EventBind* event_bindings, T event_id, bool default_value = false) - { - return CallAllFunctionsBool(event_bindings, (EntryBind*)NULL, (UniqueBind*)NULL, event_id, 0, 0, 0, default_value); - } - template bool CallAllFunctionsBool(EntryBind* entry_bindings, T event_id, uint32 entry, bool default_value = false) - { - return CallAllFunctionsBool((EventBind*)NULL, entry_bindings, (UniqueBind*)NULL, event_id, entry, 0, 0, default_value); - } - template bool CallAllFunctionsBool(EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value = false) - { - return CallAllFunctionsBool((EventBind*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, default_value); + return CallAllFunctionsBool(bindings, NULL, key, key, default_value); } public: @@ -219,23 +190,23 @@ public: lua_State* L; EventMgr* eventMgr; - EventBind* ServerEventBindings; - EventBind* PlayerEventBindings; - EventBind* GuildEventBindings; - EventBind* GroupEventBindings; - EventBind* VehicleEventBindings; - EventBind* BGEventBindings; + BindingMap< EventKey >* ServerEventBindings; + BindingMap< EventKey >* PlayerEventBindings; + BindingMap< EventKey >* GuildEventBindings; + BindingMap< EventKey >* GroupEventBindings; + BindingMap< EventKey >* VehicleEventBindings; + BindingMap< EventKey >* BGEventBindings; - EntryBind* PacketEventBindings; - EntryBind* CreatureEventBindings; - EntryBind* CreatureGossipBindings; - EntryBind* GameObjectEventBindings; - EntryBind* GameObjectGossipBindings; - EntryBind* ItemEventBindings; - EntryBind* ItemGossipBindings; - EntryBind* playerGossipBindings; + BindingMap< EntryKey >* PacketEventBindings; + BindingMap< EntryKey >* CreatureEventBindings; + BindingMap< EntryKey >* CreatureGossipBindings; + BindingMap< EntryKey >* GameObjectEventBindings; + BindingMap< EntryKey >* GameObjectGossipBindings; + BindingMap< EntryKey >* ItemEventBindings; + BindingMap< EntryKey >* ItemGossipBindings; + BindingMap< EntryKey >* PlayerGossipBindings; - UniqueBind* CreatureUniqueBindings; + BindingMap< UniqueObjectKey >* CreatureUniqueBindings; static void Initialize(); static void Uninitialize(); @@ -272,7 +243,7 @@ public: bool ShouldReload() const { return reload; } bool IsEnabled() const { return enabled && IsInitialized(); } bool HasLuaState() const { return L != NULL; } - int Register(lua_State* L, uint8 reg, uint32 id, uint64 guid, uint32 instanceId, uint32 evt, int func, uint32 shots, bool returnCallback); + int Register(lua_State* L, uint8 reg, uint32 entry, uint64 guid, uint32 instanceId, uint32 event_id, int functionRef, uint32 shots); // Non-static pushes, to be used in hooks. // These just call the correct static version with the main thread's Lua state. diff --git a/PacketHooks.cpp b/PacketHooks.cpp new file mode 100644 index 0000000..a7e10c5 --- /dev/null +++ b/PacketHooks.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2010 - 2015 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaIncludes.h" +#include "ElunaTemplate.h" + +using namespace Hooks; + +#define START_HOOK_SERVER(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!ServerEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +#define START_HOOK_PACKET(EVENT, OPCODE) \ + if (!IsEnabled())\ + return;\ + auto key = EntryKey(EVENT, OPCODE);\ + if (!PacketEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +bool Eluna::OnPacketSend(WorldSession* session, WorldPacket& packet) +{ + bool result = true; + Player* player = NULL; + if (session) + player = session->GetPlayer(); + OnPacketSendAny(player, packet, result); + OnPacketSendOne(player, packet, result); + return result; +} +void Eluna::OnPacketSendAny(Player* player, WorldPacket& packet, bool& result) +{ + START_HOOK_SERVER(SERVER_EVENT_ON_PACKET_SEND); + Push(new WorldPacket(packet)); + Push(player); + int n = SetupStack(ServerEventBindings, key, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isuserdata(L, r + 1)) + if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) + packet = *data; + + lua_pop(L, 2); + } + + CleanUpStack(2); +} + +void Eluna::OnPacketSendOne(Player* player, WorldPacket& packet, bool& result) +{ + START_HOOK_PACKET(PACKET_EVENT_ON_PACKET_SEND, packet.GetOpcode()); + Push(new WorldPacket(packet)); + Push(player); + int n = SetupStack(PacketEventBindings, key, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isuserdata(L, r + 1)) + if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) + packet = *data; + + lua_pop(L, 2); + } + + CleanUpStack(2); +} + +bool Eluna::OnPacketReceive(WorldSession* session, WorldPacket& packet) +{ + bool result = true; + Player* player = NULL; + if (session) + player = session->GetPlayer(); + OnPacketReceiveAny(player, packet, result); + OnPacketReceiveOne(player, packet, result); + return result; +} + +void Eluna::OnPacketReceiveAny(Player* player, WorldPacket& packet, bool& result) +{ + START_HOOK_SERVER(SERVER_EVENT_ON_PACKET_RECEIVE); + Push(new WorldPacket(packet)); + Push(player); + int n = SetupStack(ServerEventBindings, key, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isuserdata(L, r + 1)) + if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) + packet = *data; + + lua_pop(L, 2); + } + + CleanUpStack(2); +} + +void Eluna::OnPacketReceiveOne(Player* player, WorldPacket& packet, bool& result) +{ + START_HOOK_PACKET(PACKET_EVENT_ON_PACKET_SEND, packet.GetOpcode()); + Push(new WorldPacket(packet)); + Push(player); + int n = SetupStack(PacketEventBindings, key, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isuserdata(L, r + 1)) + if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) + packet = *data; + + lua_pop(L, 2); + } + + CleanUpStack(2); +} diff --git a/PlayerHooks.cpp b/PlayerHooks.cpp index 3569cc4..4759024 100644 --- a/PlayerHooks.cpp +++ b/PlayerHooks.cpp @@ -4,69 +4,39 @@ * Please see the included DOCS/LICENSE.md for more information */ -#ifndef _PLAYER_HOOKS_H -#define _PLAYER_HOOKS_H - #include "Hooks.h" #include "HookHelpers.h" #include "LuaEngine.h" -#include "ElunaBinding.h" +#include "BindingMap.h" #include "ElunaIncludes.h" #include "ElunaTemplate.h" using namespace Hooks; +#define START_HOOK(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!PlayerEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +#define START_HOOK_WITH_RETVAL(EVENT, RETVAL) \ + if (!IsEnabled())\ + return RETVAL;\ + auto key = EventKey(EVENT);\ + if (!PlayerEventBindings->HasBindingsFor(key))\ + return RETVAL;\ + LOCK_ELUNA + void Eluna::OnLearnTalents(Player* pPlayer, uint32 talentId, uint32 talentRank, uint32 spellid) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LEARN_TALENTS)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_LEARN_TALENTS); Push(pPlayer); Push(talentId); Push(talentRank); Push(spellid); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEARN_TALENTS); -} - -void Eluna::HandleGossipSelectOption(Player* pPlayer, Item* item, uint32 sender, uint32 action, const std::string& code) -{ - if (!ItemGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, item->GetEntry())) - return; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - - Push(pPlayer); - Push(item); - Push(sender); - Push(action); - if (code.empty()) - Push(); - else - Push(code); - - CallAllFunctions(ItemGossipBindings, GOSSIP_EVENT_ON_SELECT, item->GetEntry()); -} - -void Eluna::HandleGossipSelectOption(Player* pPlayer, uint32 menuId, uint32 sender, uint32 action, const std::string& code) -{ - if (!playerGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, menuId)) - return; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - - Push(pPlayer); // receiver - Push(pPlayer); // sender, just not to mess up the amount of args. - Push(sender); - Push(action); - if (code.empty()) - Push(); - else - Push(code); - - CallAllFunctions(playerGossipBindings, GOSSIP_EVENT_ON_SELECT, menuId); + CallAllFunctions(PlayerEventBindings, key); } // Player @@ -95,103 +65,76 @@ bool Eluna::OnCommand(Player* player, const char* text) } } - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_COMMAND)) - return true; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_COMMAND, true); Push(player); Push(fullcmd); - return CallAllFunctionsBool(PlayerEventBindings, PLAYER_EVENT_ON_COMMAND, true); + return CallAllFunctionsBool(PlayerEventBindings, key, true); } void Eluna::OnLootItem(Player* pPlayer, Item* pItem, uint32 count, uint64 guid) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOOT_ITEM)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_LOOT_ITEM); Push(pPlayer); Push(pItem); Push(count); Push(guid); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_ITEM); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnLootMoney(Player* pPlayer, uint32 amount) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOOT_MONEY)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_LOOT_MONEY); Push(pPlayer); Push(amount); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_MONEY); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnFirstLogin(Player* pPlayer) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_FIRST_LOGIN)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_FIRST_LOGIN); Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_FIRST_LOGIN); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnRepop(Player* pPlayer) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_REPOP)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_REPOP); Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_REPOP); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnResurrect(Player* pPlayer) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_RESURRECT)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_RESURRECT); Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_RESURRECT); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnQuestAbandon(Player* pPlayer, uint32 questId) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_QUEST_ABANDON)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_QUEST_ABANDON); Push(pPlayer); Push(questId); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_QUEST_ABANDON); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnEquip(Player* pPlayer, Item* pItem, uint8 bag, uint8 slot) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_EQUIP)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_EQUIP); Push(pPlayer); Push(pItem); Push(bag); Push(slot); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_EQUIP); + CallAllFunctions(PlayerEventBindings, key); } InventoryResult Eluna::OnCanUseItem(const Player* pPlayer, uint32 itemEntry) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CAN_USE_ITEM)) - return EQUIP_ERR_OK; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_CAN_USE_ITEM, EQUIP_ERR_OK); InventoryResult result = EQUIP_ERR_OK; Push(pPlayer); Push(itemEntry); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CAN_USE_ITEM, 2); + int n = SetupStack(PlayerEventBindings, key, 2); while (n > 0) { @@ -208,101 +151,74 @@ InventoryResult Eluna::OnCanUseItem(const Player* pPlayer, uint32 itemEntry) } void Eluna::OnPlayerEnterCombat(Player* pPlayer, Unit* pEnemy) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_ENTER_COMBAT)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_ENTER_COMBAT); Push(pPlayer); Push(pEnemy); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_ENTER_COMBAT); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnPlayerLeaveCombat(Player* pPlayer) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LEAVE_COMBAT)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_LEAVE_COMBAT); Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEAVE_COMBAT); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnPVPKill(Player* pKiller, Player* pKilled) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILL_PLAYER)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_KILL_PLAYER); Push(pKiller); Push(pKilled); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILL_PLAYER); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnCreatureKill(Player* pKiller, Creature* pKilled) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILL_CREATURE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_KILL_CREATURE); Push(pKiller); Push(pKilled); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILL_CREATURE); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnPlayerKilledByCreature(Creature* pKiller, Player* pKilled) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILLED_BY_CREATURE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_KILLED_BY_CREATURE); Push(pKiller); Push(pKilled); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILLED_BY_CREATURE); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnLevelChanged(Player* pPlayer, uint8 oldLevel) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LEVEL_CHANGE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_LEVEL_CHANGE); Push(pPlayer); Push(oldLevel); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEVEL_CHANGE); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnFreeTalentPointsChanged(Player* pPlayer, uint32 newPoints) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TALENTS_CHANGE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_TALENTS_CHANGE); Push(pPlayer); Push(newPoints); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_CHANGE); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnTalentsReset(Player* pPlayer, bool noCost) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TALENTS_RESET)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_TALENTS_RESET); Push(pPlayer); Push(noCost); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_RESET); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnMoneyChanged(Player* pPlayer, int32& amount) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_MONEY_CHANGE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_MONEY_CHANGE); Push(pPlayer); Push(amount); int amountIndex = lua_gettop(L); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_MONEY_CHANGE, 2); + int n = SetupStack(PlayerEventBindings, key, 2); while (n > 0) { @@ -323,15 +239,12 @@ void Eluna::OnMoneyChanged(Player* pPlayer, int32& amount) void Eluna::OnGiveXP(Player* pPlayer, uint32& amount, Unit* pVictim) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GIVE_XP)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_GIVE_XP); Push(pPlayer); Push(amount); Push(pVictim); int amountIndex = lua_gettop(L) - 1; - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GIVE_XP, 3); + int n = SetupStack(PlayerEventBindings, key, 3); while (n > 0) { @@ -352,16 +265,13 @@ void Eluna::OnGiveXP(Player* pPlayer, uint32& amount, Unit* pVictim) void Eluna::OnReputationChange(Player* pPlayer, uint32 factionID, int32& standing, bool incremental) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_REPUTATION_CHANGE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_REPUTATION_CHANGE); Push(pPlayer); Push(factionID); Push(standing); Push(incremental); int standingIndex = lua_gettop(L) - 1; - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_REPUTATION_CHANGE, 4); + int n = SetupStack(PlayerEventBindings, key, 4); while (n > 0) { @@ -382,183 +292,115 @@ void Eluna::OnReputationChange(Player* pPlayer, uint32 factionID, int32& standin void Eluna::OnDuelRequest(Player* pTarget, Player* pChallenger) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_REQUEST)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_DUEL_REQUEST); Push(pTarget); Push(pChallenger); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_REQUEST); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnDuelStart(Player* pStarter, Player* pChallenger) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_START)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_DUEL_START); Push(pStarter); Push(pChallenger); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_START); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnDuelEnd(Player* pWinner, Player* pLoser, DuelCompleteType type) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_END)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_DUEL_END); Push(pWinner); Push(pLoser); Push(type); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_END); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnEmote(Player* pPlayer, uint32 emote) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_EMOTE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_EMOTE); Push(pPlayer); Push(emote); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_EMOTE); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnTextEmote(Player* pPlayer, uint32 textEmote, uint32 emoteNum, uint64 guid) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TEXT_EMOTE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_TEXT_EMOTE); Push(pPlayer); Push(textEmote); Push(emoteNum); Push(guid); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TEXT_EMOTE); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnSpellCast(Player* pPlayer, Spell* pSpell, bool skipCheck) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_SPELL_CAST)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_SPELL_CAST); Push(pPlayer); Push(pSpell); Push(skipCheck); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_SPELL_CAST); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnLogin(Player* pPlayer) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOGIN)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_LOGIN); Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOGIN); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnLogout(Player* pPlayer) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOGOUT)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_LOGOUT); Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOGOUT); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnCreate(Player* pPlayer) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHARACTER_CREATE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_CHARACTER_CREATE); Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_CREATE); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnDelete(uint32 guidlow) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHARACTER_DELETE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_CHARACTER_DELETE); Push(guidlow); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_DELETE); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnSave(Player* pPlayer) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_SAVE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_SAVE); Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_SAVE); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnBindToInstance(Player* pPlayer, Difficulty difficulty, uint32 mapid, bool permanent) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_BIND_TO_INSTANCE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_BIND_TO_INSTANCE); Push(pPlayer); Push(difficulty); Push(mapid); Push(permanent); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_BIND_TO_INSTANCE); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnUpdateZone(Player* pPlayer, uint32 newZone, uint32 newArea) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_UPDATE_ZONE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_UPDATE_ZONE); Push(pPlayer); Push(newZone); Push(newArea); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_UPDATE_ZONE); + CallAllFunctions(PlayerEventBindings, key); } void Eluna::OnMapChanged(Player* player) { - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_MAP_CHANGE)) - return; - - LOCK_ELUNA; + START_HOOK(PLAYER_EVENT_ON_MAP_CHANGE); Push(player); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_MAP_CHANGE); -} - -// AddOns -bool Eluna::OnAddonMessage(Player* sender, uint32 type, std::string& msg, Player* receiver, Guild* guild, Group* group, Channel* channel) -{ - if (!ServerEventBindings->HasEvents(ADDON_EVENT_ON_MESSAGE)) - return true; - - LOCK_ELUNA; - Push(sender); - Push(type); - const char* c_msg = msg.c_str(); - Push(strtok((char*)c_msg, "\t")); // prefix - Push(strtok(NULL, "")); // msg - if (receiver) - Push(receiver); - else if (guild) - Push(guild); - else if (group) - Push(group); - else if (channel) - Push(channel->GetChannelId()); - else - Push(); - - return CallAllFunctionsBool(ServerEventBindings, ADDON_EVENT_ON_MESSAGE, true); + CallAllFunctions(PlayerEventBindings, key); } bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg) @@ -566,16 +408,13 @@ bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg) if (lang == LANG_ADDON) return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, NULL); - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHAT)) - return true; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_CHAT, true); bool result = true; Push(pPlayer); Push(msg); Push(type); Push(lang); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CHAT, 4); + int n = SetupStack(PlayerEventBindings, key, 4); while (n > 0) { @@ -599,17 +438,14 @@ bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, if (lang == LANG_ADDON) return OnAddonMessage(pPlayer, type, msg, NULL, NULL, pGroup, NULL); - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GROUP_CHAT)) - return true; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_GROUP_CHAT, true); bool result = true; Push(pPlayer); Push(msg); Push(type); Push(lang); Push(pGroup); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GROUP_CHAT, 5); + int n = SetupStack(PlayerEventBindings, key, 5); while (n > 0) { @@ -633,17 +469,14 @@ bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, if (lang == LANG_ADDON) return OnAddonMessage(pPlayer, type, msg, NULL, pGuild, NULL, NULL); - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GUILD_CHAT)) - return true; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_GUILD_CHAT, true); bool result = true; Push(pPlayer); Push(msg); Push(type); Push(lang); Push(pGuild); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GUILD_CHAT, 5); + int n = SetupStack(PlayerEventBindings, key, 5); while (n > 0) { @@ -667,17 +500,14 @@ bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, if (lang == LANG_ADDON) return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, pChannel); - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHANNEL_CHAT)) - return true; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_CHANNEL_CHAT, true); bool result = true; Push(pPlayer); Push(msg); Push(type); Push(lang); Push(pChannel->GetChannelId()); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CHANNEL_CHAT, 5); + int n = SetupStack(PlayerEventBindings, key, 5); while (n > 0) { @@ -701,17 +531,14 @@ bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, if (lang == LANG_ADDON) return OnAddonMessage(pPlayer, type, msg, pReceiver, NULL, NULL, NULL); - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_WHISPER)) - return true; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_WHISPER, true); bool result = true; Push(pPlayer); Push(msg); Push(type); Push(lang); Push(pReceiver); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_WHISPER, 5); + int n = SetupStack(PlayerEventBindings, key, 5); while (n > 0) { @@ -729,5 +556,3 @@ bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, CleanUpStack(5); return result; } - -#endif // _PLAYER_HOOKS_H diff --git a/ServerHooks.cpp b/ServerHooks.cpp index 5ea59ee..69cb5be 100644 --- a/ServerHooks.cpp +++ b/ServerHooks.cpp @@ -4,19 +4,54 @@ * Please see the included DOCS/LICENSE.md for more information */ -#ifndef _SERVER_HOOKS_H -#define _SERVER_HOOKS_H - #include "Hooks.h" #include "HookHelpers.h" #include "LuaEngine.h" -#include "ElunaBinding.h" +#include "BindingMap.h" #include "ElunaEventMgr.h" #include "ElunaIncludes.h" #include "ElunaTemplate.h" using namespace Hooks; +#define START_HOOK(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!ServerEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +#define START_HOOK_WITH_RETVAL(EVENT, RETVAL) \ + if (!IsEnabled())\ + return RETVAL;\ + auto key = EventKey(EVENT);\ + if (!ServerEventBindings->HasBindingsFor(key))\ + return RETVAL;\ + LOCK_ELUNA + +bool Eluna::OnAddonMessage(Player* sender, uint32 type, std::string& msg, Player* receiver, Guild* guild, Group* group, Channel* channel) +{ + START_HOOK_WITH_RETVAL(ADDON_EVENT_ON_MESSAGE, true); + Push(sender); + Push(type); + const char* c_msg = msg.c_str(); + Push(strtok((char*)c_msg, "\t")); // prefix + Push(strtok(NULL, "")); // msg + if (receiver) + Push(receiver); + else if (guild) + Push(guild); + else if (group) + Push(group); + else if (channel) + Push(channel->GetChannelId()); + else + Push(); + + return CallAllFunctionsBool(ServerEventBindings, key, true); +} + void Eluna::OnTimedEvent(int funcRef, uint32 delay, uint32 calls, WorldObject* obj) { LOCK_ELUNA; @@ -40,53 +75,38 @@ void Eluna::OnTimedEvent(int funcRef, uint32 delay, uint32 calls, WorldObject* o void Eluna::OnLuaStateClose() { - if (!ServerEventBindings->HasEvents(ELUNA_EVENT_ON_LUA_STATE_CLOSE)) - return; - - LOCK_ELUNA; - CallAllFunctions(ServerEventBindings, ELUNA_EVENT_ON_LUA_STATE_CLOSE); + START_HOOK(ELUNA_EVENT_ON_LUA_STATE_CLOSE); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnLuaStateOpen() { - if (!ServerEventBindings->HasEvents(ELUNA_EVENT_ON_LUA_STATE_OPEN)) - return; - - LOCK_ELUNA; - CallAllFunctions(ServerEventBindings, ELUNA_EVENT_ON_LUA_STATE_OPEN); + START_HOOK(ELUNA_EVENT_ON_LUA_STATE_OPEN); + CallAllFunctions(ServerEventBindings, key); } // areatrigger bool Eluna::OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* pTrigger) { - if (!ServerEventBindings->HasEvents(TRIGGER_EVENT_ON_TRIGGER)) - return false; - - LOCK_ELUNA; + START_HOOK_WITH_RETVAL(TRIGGER_EVENT_ON_TRIGGER, false); Push(pPlayer); Push(pTrigger->id); - return CallAllFunctionsBool(ServerEventBindings, TRIGGER_EVENT_ON_TRIGGER); + return CallAllFunctionsBool(ServerEventBindings, key); } // weather void Eluna::OnChange(Weather* weather, uint32 zone, WeatherState state, float grade) { - if (!ServerEventBindings->HasEvents(WEATHER_EVENT_ON_CHANGE)) - return; - - LOCK_ELUNA; + START_HOOK(WEATHER_EVENT_ON_CHANGE); Push(zone); Push(state); Push(grade); - CallAllFunctions(ServerEventBindings, WEATHER_EVENT_ON_CHANGE); + CallAllFunctions(ServerEventBindings, key); } // Auction House void Eluna::OnAdd(AuctionHouseObject* /*ah*/, AuctionEntry* entry) { - if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_ADD)) - return; - Player* owner = eObjectAccessor->FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER)); #ifdef TRINITY Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow); @@ -100,7 +120,7 @@ void Eluna::OnAdd(AuctionHouseObject* /*ah*/, AuctionEntry* entry) if (!owner || !item) return; - LOCK_ELUNA; + START_HOOK(AUCTION_EVENT_ON_ADD); Push(entry->Id); Push(owner); Push(item); @@ -109,14 +129,11 @@ void Eluna::OnAdd(AuctionHouseObject* /*ah*/, AuctionEntry* entry) Push(entry->startbid); Push(entry->bid); Push(entry->bidder); - CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_ADD); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnRemove(AuctionHouseObject* /*ah*/, AuctionEntry* entry) { - if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_REMOVE)) - return; - Player* owner = eObjectAccessor->FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER)); #ifdef TRINITY Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow); @@ -130,7 +147,7 @@ void Eluna::OnRemove(AuctionHouseObject* /*ah*/, AuctionEntry* entry) if (!owner || !item) return; - LOCK_ELUNA; + START_HOOK(AUCTION_EVENT_ON_REMOVE); Push(entry->Id); Push(owner); Push(item); @@ -139,14 +156,11 @@ void Eluna::OnRemove(AuctionHouseObject* /*ah*/, AuctionEntry* entry) Push(entry->startbid); Push(entry->bid); Push(entry->bidder); - CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_REMOVE); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnSuccessful(AuctionHouseObject* /*ah*/, AuctionEntry* entry) { - if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_SUCCESSFUL)) - return; - Player* owner = eObjectAccessor->FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER)); #ifdef TRINITY Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow); @@ -160,7 +174,7 @@ void Eluna::OnSuccessful(AuctionHouseObject* /*ah*/, AuctionEntry* entry) if (!owner || !item) return; - LOCK_ELUNA; + START_HOOK(AUCTION_EVENT_ON_SUCCESSFUL); Push(entry->Id); Push(owner); Push(item); @@ -169,14 +183,11 @@ void Eluna::OnSuccessful(AuctionHouseObject* /*ah*/, AuctionEntry* entry) Push(entry->startbid); Push(entry->bid); Push(entry->bidder); - CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_SUCCESSFUL); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnExpire(AuctionHouseObject* /*ah*/, AuctionEntry* entry) { - if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_EXPIRE)) - return; - Player* owner = eObjectAccessor->FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER)); #ifdef TRINITY Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow); @@ -190,7 +201,7 @@ void Eluna::OnExpire(AuctionHouseObject* /*ah*/, AuctionEntry* entry) if (!owner || !item) return; - LOCK_ELUNA; + START_HOOK(AUCTION_EVENT_ON_EXPIRE); Push(entry->Id); Push(owner); Push(item); @@ -199,177 +210,35 @@ void Eluna::OnExpire(AuctionHouseObject* /*ah*/, AuctionEntry* entry) Push(entry->startbid); Push(entry->bid); Push(entry->bidder); - CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_EXPIRE); -} - -// Packet -bool Eluna::OnPacketSend(WorldSession* session, WorldPacket& packet) -{ - bool result = true; - Player* player = NULL; - if (session) - player = session->GetPlayer(); - OnPacketSendAny(player, packet, result); - OnPacketSendOne(player, packet, result); - return result; -} -void Eluna::OnPacketSendAny(Player* player, WorldPacket& packet, bool& result) -{ - if (!ServerEventBindings->HasEvents(SERVER_EVENT_ON_PACKET_SEND)) - return; - - LOCK_ELUNA; - Push(new WorldPacket(packet)); - Push(player); - int n = SetupStack(ServerEventBindings, SERVER_EVENT_ON_PACKET_SEND, 2); - - while (n > 0) - { - int r = CallOneFunction(n--, 2, 2); - - if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) - result = false; - - if (lua_isuserdata(L, r + 1)) - if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) - packet = *data; - - lua_pop(L, 2); - } - - CleanUpStack(2); -} - -void Eluna::OnPacketSendOne(Player* player, WorldPacket& packet, bool& result) -{ - if (!PacketEventBindings->HasEvents(PACKET_EVENT_ON_PACKET_SEND, packet.GetOpcode())) - return; - - LOCK_ELUNA; - Push(new WorldPacket(packet)); - Push(player); - int n = SetupStack(PacketEventBindings, PACKET_EVENT_ON_PACKET_SEND, OpcodesList(packet.GetOpcode()), 2); - - while (n > 0) - { - int r = CallOneFunction(n--, 2, 2); - - if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) - result = false; - - if (lua_isuserdata(L, r + 1)) - if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) - packet = *data; - - lua_pop(L, 2); - } - - CleanUpStack(2); -} - -bool Eluna::OnPacketReceive(WorldSession* session, WorldPacket& packet) -{ - bool result = true; - Player* player = NULL; - if (session) - player = session->GetPlayer(); - OnPacketReceiveAny(player, packet, result); - OnPacketReceiveOne(player, packet, result); - return result; -} - -void Eluna::OnPacketReceiveAny(Player* player, WorldPacket& packet, bool& result) -{ - if (!ServerEventBindings->HasEvents(SERVER_EVENT_ON_PACKET_RECEIVE)) - return; - - LOCK_ELUNA; - Push(new WorldPacket(packet)); - Push(player); - int n = SetupStack(ServerEventBindings, SERVER_EVENT_ON_PACKET_RECEIVE, 2); - - while (n > 0) - { - int r = CallOneFunction(n--, 2, 2); - - if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) - result = false; - - if (lua_isuserdata(L, r + 1)) - if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) - packet = *data; - - lua_pop(L, 2); - } - - CleanUpStack(2); -} - -void Eluna::OnPacketReceiveOne(Player* player, WorldPacket& packet, bool& result) -{ - if (!PacketEventBindings->HasEvents(PACKET_EVENT_ON_PACKET_RECEIVE, packet.GetOpcode())) - return; - - LOCK_ELUNA; - Push(new WorldPacket(packet)); - Push(player); - int n = SetupStack(PacketEventBindings, PACKET_EVENT_ON_PACKET_RECEIVE, OpcodesList(), 2); - - while (n > 0) - { - int r = CallOneFunction(n--, 2, 2); - - if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) - result = false; - - if (lua_isuserdata(L, r + 1)) - if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) - packet = *data; - - lua_pop(L, 2); - } - - CleanUpStack(2); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnOpenStateChange(bool open) { - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_OPEN_STATE_CHANGE)) - return; - - LOCK_ELUNA; + START_HOOK(WORLD_EVENT_ON_OPEN_STATE_CHANGE); Push(open); - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_OPEN_STATE_CHANGE); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnConfigLoad(bool reload) { - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_CONFIG_LOAD)) - return; - - LOCK_ELUNA; + START_HOOK(WORLD_EVENT_ON_CONFIG_LOAD); Push(reload); - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_CONFIG_LOAD); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask) { - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN_INIT)) - return; - - LOCK_ELUNA; + START_HOOK(WORLD_EVENT_ON_SHUTDOWN_INIT); Push(code); Push(mask); - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_INIT); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnShutdownCancel() { - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN_CANCEL)) - return; - - LOCK_ELUNA; - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_CANCEL); + START_HOOK(WORLD_EVENT_ON_SHUTDOWN_CANCEL); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnWorldUpdate(uint32 diff) @@ -382,106 +251,74 @@ void Eluna::OnWorldUpdate(uint32 diff) eventMgr->globalProcessor->Update(diff); - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_UPDATE)) - return; - - LOCK_ELUNA; + START_HOOK(WORLD_EVENT_ON_UPDATE); Push(diff); - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_UPDATE); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnStartup() { - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_STARTUP)) - return; - - LOCK_ELUNA; - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_STARTUP); + START_HOOK(WORLD_EVENT_ON_STARTUP); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnShutdown() { - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN)) - return; - - LOCK_ELUNA; - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN); + START_HOOK(WORLD_EVENT_ON_SHUTDOWN); + CallAllFunctions(ServerEventBindings, key); } /* Map */ void Eluna::OnCreate(Map* map) { - if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_CREATE)) - return; - - LOCK_ELUNA; + START_HOOK(MAP_EVENT_ON_CREATE); Push(map); - CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_CREATE); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnDestroy(Map* map) { - if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_DESTROY)) - return; - - LOCK_ELUNA; + START_HOOK(MAP_EVENT_ON_DESTROY); Push(map); - CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_DESTROY); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnPlayerEnter(Map* map, Player* player) { - if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_PLAYER_ENTER)) - return; - - LOCK_ELUNA; + START_HOOK(MAP_EVENT_ON_PLAYER_ENTER); Push(map); Push(player); - CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_PLAYER_ENTER); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnPlayerLeave(Map* map, Player* player) { - if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_PLAYER_LEAVE)) - return; - - LOCK_ELUNA; + START_HOOK(MAP_EVENT_ON_PLAYER_LEAVE); Push(map); Push(player); - CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_PLAYER_LEAVE); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnUpdate(Map* map, uint32 diff) { - if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_UPDATE)) - return; - - LOCK_ELUNA; + START_HOOK(MAP_EVENT_ON_UPDATE); // enable this for multithread // eventMgr->globalProcessor->Update(diff); Push(map); Push(diff); - CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_UPDATE); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnRemove(GameObject* gameobject) { - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_DELETE_GAMEOBJECT)) - return; - - LOCK_ELUNA; + START_HOOK(WORLD_EVENT_ON_DELETE_GAMEOBJECT); Push(gameobject); - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_DELETE_GAMEOBJECT); + CallAllFunctions(ServerEventBindings, key); } void Eluna::OnRemove(Creature* creature) { - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_DELETE_CREATURE)) - return; - - LOCK_ELUNA; + START_HOOK(WORLD_EVENT_ON_DELETE_CREATURE); Push(creature); - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_DELETE_CREATURE); + CallAllFunctions(ServerEventBindings, key); } - -#endif // _SERVER_HOOKS_H diff --git a/VehicleHooks.cpp b/VehicleHooks.cpp index 47223c5..c43c679 100644 --- a/VehicleHooks.cpp +++ b/VehicleHooks.cpp @@ -4,13 +4,10 @@ * Please see the included DOCS/LICENSE.md for more information */ -#ifndef _VEHICLE_HOOKS_H -#define _VEHICLE_HOOKS_H - #include "Hooks.h" #include "HookHelpers.h" #include "LuaEngine.h" -#include "ElunaBinding.h" +#include "BindingMap.h" #include "ElunaTemplate.h" #ifndef CLASSIC @@ -18,61 +15,53 @@ using namespace Hooks; +#define START_HOOK(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!VehicleEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + // Vehicle void Eluna::OnInstall(Vehicle* vehicle) { - if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_INSTALL)) - return; - - LOCK_ELUNA; + START_HOOK(VEHICLE_EVENT_ON_INSTALL); Push(vehicle); - CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL); + CallAllFunctions(VehicleEventBindings, key); } void Eluna::OnUninstall(Vehicle* vehicle) { - if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_UNINSTALL)) - return; - - LOCK_ELUNA; + START_HOOK(VEHICLE_EVENT_ON_UNINSTALL); Push(vehicle); - CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_UNINSTALL); + CallAllFunctions(VehicleEventBindings, key); } void Eluna::OnInstallAccessory(Vehicle* vehicle, Creature* accessory) { - if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_INSTALL_ACCESSORY)) - return; - - LOCK_ELUNA; + START_HOOK(VEHICLE_EVENT_ON_INSTALL_ACCESSORY); Push(vehicle); Push(accessory); - CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL_ACCESSORY); + CallAllFunctions(VehicleEventBindings, key); } void Eluna::OnAddPassenger(Vehicle* vehicle, Unit* passenger, int8 seatId) { - if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_ADD_PASSENGER)) - return; - - LOCK_ELUNA; + START_HOOK(VEHICLE_EVENT_ON_ADD_PASSENGER); Push(vehicle); Push(passenger); Push(seatId); - CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_ADD_PASSENGER); + CallAllFunctions(VehicleEventBindings, key); } void Eluna::OnRemovePassenger(Vehicle* vehicle, Unit* passenger) { - if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_REMOVE_PASSENGER)) - return; - - LOCK_ELUNA; + START_HOOK(VEHICLE_EVENT_ON_REMOVE_PASSENGER); Push(vehicle); Push(passenger); - CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_REMOVE_PASSENGER); + CallAllFunctions(VehicleEventBindings, key); } #endif // CLASSIC #endif // TBC -#endif // _VEHICLE_HOOKS_H