Merge new_bindings, closes #151

Refer to 6194ddb43c for new C++11 required changes for mangos based cores
This commit is contained in:
Patman64
2015-06-01 20:37:32 +03:00
committed by Rochet2
parent 5c68b7301a
commit 7397c98a61
20 changed files with 1350 additions and 2231 deletions

View File

@@ -4,64 +4,55 @@
* Please see the included DOCS/LICENSE.md for more information * Please see the included DOCS/LICENSE.md for more information
*/ */
#ifndef _BATTLEGROUND_HOOKS_H
#define _BATTLEGROUND_HOOKS_H
#include "Hooks.h" #include "Hooks.h"
#include "HookHelpers.h" #include "HookHelpers.h"
#include "LuaEngine.h" #include "LuaEngine.h"
#include "ElunaBinding.h" #include "BindingMap.h"
#include "ElunaTemplate.h" #include "ElunaTemplate.h"
using namespace Hooks; using namespace Hooks;
#define START_HOOK(EVENT) \
if (!IsEnabled())\
return;\
auto key = EventKey<BGEvents>(EVENT);\
if (!BGEventBindings->HasBindingsFor(key))\
return;\
LOCK_ELUNA
void Eluna::OnBGStart(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) void Eluna::OnBGStart(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId)
{ {
if (!BGEventBindings->HasEvents(BG_EVENT_ON_START)) START_HOOK(BG_EVENT_ON_START);
return;
LOCK_ELUNA;
Push(bg); Push(bg);
Push(bgId); Push(bgId);
Push(instanceId); Push(instanceId);
CallAllFunctions(BGEventBindings, BG_EVENT_ON_START); CallAllFunctions(BGEventBindings, key);
} }
void Eluna::OnBGEnd(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId, Team winner) void Eluna::OnBGEnd(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId, Team winner)
{ {
if (!BGEventBindings->HasEvents(BG_EVENT_ON_END)) START_HOOK(BG_EVENT_ON_END);
return;
LOCK_ELUNA;
Push(bg); Push(bg);
Push(bgId); Push(bgId);
Push(instanceId); Push(instanceId);
Push(winner); Push(winner);
CallAllFunctions(BGEventBindings, BG_EVENT_ON_END); CallAllFunctions(BGEventBindings, key);
} }
void Eluna::OnBGCreate(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) void Eluna::OnBGCreate(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId)
{ {
if (!BGEventBindings->HasEvents(BG_EVENT_ON_CREATE)) START_HOOK(BG_EVENT_ON_CREATE);
return;
LOCK_ELUNA;
Push(bg); Push(bg);
Push(bgId); Push(bgId);
Push(instanceId); Push(instanceId);
CallAllFunctions(BGEventBindings, BG_EVENT_ON_CREATE); CallAllFunctions(BGEventBindings, key);
} }
void Eluna::OnBGDestroy(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) void Eluna::OnBGDestroy(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId)
{ {
if (!BGEventBindings->HasEvents(BG_EVENT_ON_PRE_DESTROY)) START_HOOK(BG_EVENT_ON_PRE_DESTROY);
return;
LOCK_ELUNA;
Push(bg); Push(bg);
Push(bgId); Push(bgId);
Push(instanceId); Push(instanceId);
CallAllFunctions(BGEventBindings, BG_EVENT_ON_PRE_DESTROY); CallAllFunctions(BGEventBindings, key);
} }
#endif // _BATTLEGROUND_HOOKS_H

344
BindingMap.h Normal file
View File

@@ -0,0 +1,344 @@
/*
* Copyright (C) 2010 - 2015 Eluna Lua Engine <http://emudevs.com/>
* 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 <memory>
#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<typename K>
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<Binding> > BindingList;
std::unordered_map<K, BindingList> 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<uint64, BindingList*> 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<Binding>(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>& 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>& 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>& 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 <typename T>
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 <typename T>
struct EntryKey : public EventKey<T>
{
uint32 entry;
EntryKey(T event_type, uint32 entry) :
EventKey<T>(event_type),
entry(entry)
{}
};
/*
* A `BindingMap` key type for event ID/unique Object bindings
* (currently just CreatureEvents).
*/
template <typename T>
struct UniqueObjectKey : public EventKey<T>
{
uint64 guid;
uint32 instance_id;
UniqueObjectKey(T event_type, uint64 guid, uint32 instance_id) :
EventKey<T>(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<typename T>
struct equal_to < EventKey<T> >
{
bool operator()(EventKey<T> const& lhs, EventKey<T> const& rhs) const
{
return lhs.event_id == rhs.event_id;
}
};
template<typename T>
struct equal_to < EntryKey<T> >
{
bool operator()(EntryKey<T> const& lhs, EntryKey<T> const& rhs) const
{
return lhs.event_id == rhs.event_id
&& lhs.entry == rhs.entry;
}
};
template<typename T>
struct equal_to < UniqueObjectKey<T> >
{
bool operator()(UniqueObjectKey<T> const& lhs, UniqueObjectKey<T> const& rhs) const
{
return lhs.event_id == rhs.event_id
&& lhs.guid == rhs.guid
&& lhs.instance_id == rhs.instance_id;
}
};
template<typename T>
struct hash < EventKey<T> >
{
typedef EventKey<T> argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& k) const
{
result_type const h1(std::hash<uint32>()(k.event_id));
return h1;
}
};
template<typename T>
struct hash < EntryKey<T> >
{
typedef EntryKey<T> argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& k) const
{
result_type const h1(std::hash<uint32>()(k.event_id));
result_type const h2(std::hash<uint32>()(k.entry));
return h1 ^ (h2 << 8); // `event_id` probably won't exceed 2^8.
}
};
template<typename T>
struct hash < UniqueObjectKey<T> >
{
typedef UniqueObjectKey<T> argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& k) const
{
result_type const h1(std::hash<uint32>()(k.event_id));
result_type const h2(std::hash<uint32>()(k.instance_id));
result_type const h3(std::hash<uint64>()(k.guid));
return h1 ^ (h2 << 8) ^ (h3 << 24); // `instance_id` probably won't exceed 2^16.
}
};
}
#endif // _BINDING_MAP_H

View File

@@ -4,187 +4,123 @@
* Please see the included DOCS/LICENSE.md for more information * Please see the included DOCS/LICENSE.md for more information
*/ */
#ifndef _CREATURE_HOOKS_H
#define _CREATURE_HOOKS_H
#include "Hooks.h" #include "Hooks.h"
#include "HookHelpers.h" #include "HookHelpers.h"
#include "LuaEngine.h" #include "LuaEngine.h"
#include "ElunaBinding.h" #include "BindingMap.h"
#include "ElunaIncludes.h" #include "ElunaIncludes.h"
#include "ElunaTemplate.h" #include "ElunaTemplate.h"
using namespace Hooks; using namespace Hooks;
#define START_HOOK(EVENT, CREATURE) \
if (!IsEnabled())\
return;\
auto entry_key = EntryKey<CreatureEvents>(EVENT, CREATURE->GetEntry());\
auto unique_key = UniqueObjectKey<CreatureEvents>(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<CreatureEvents>(EVENT, CREATURE->GetEntry());\
auto unique_key = UniqueObjectKey<CreatureEvents>(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) bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Creature* pTarget)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GET_GUID(), pTarget->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(pCaster); Push(pCaster);
Push(spellId); Push(spellId);
Push(effIndex); Push(effIndex);
Push(pTarget); Push(pTarget);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry(), pTarget->GET_GUID(), pTarget->GetInstanceId()); return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key);
}
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);
} }
bool Eluna::OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest) bool Eluna::OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GET_GUID(), pCreature->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pCreature); Push(pCreature);
Push(pQuest); 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) bool Eluna::OnQuestReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_QUEST_REWARD, pCreature, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GET_GUID(), pCreature->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pCreature); Push(pCreature);
Push(pQuest); Push(pQuest);
Push(opt); 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) uint32 Eluna::GetDialogStatus(Player* pPlayer, Creature* pCreature)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature, DIALOG_STATUS_SCRIPTED_NO_STATUS);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GET_GUID(), pCreature->GetInstanceId()))
return DIALOG_STATUS_SCRIPTED_NO_STATUS;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pCreature); 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; 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())) START_HOOK(CREATURE_EVENT_ON_ADD, pCreature);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ADD, creature->GET_GUID(), creature->GetInstanceId())) Push(pCreature);
return; CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key);
LOCK_ELUNA;
Push(creature);
CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_ADD, creature->GetEntry(), creature->GET_GUID(), creature->GetInstanceId());
} }
void Eluna::OnRemoveFromWorld(Creature* creature) void Eluna::OnRemoveFromWorld(Creature* pCreature)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REMOVE, creature->GetEntry())) START_HOOK(CREATURE_EVENT_ON_REMOVE, pCreature);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REMOVE, creature->GET_GUID(), creature->GetInstanceId())) Push(pCreature);
return; CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key);
LOCK_ELUNA;
Push(creature);
CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_REMOVE, creature->GetEntry(), creature->GET_GUID(), creature->GetInstanceId());
} }
bool Eluna::OnSummoned(Creature* pCreature, Unit* pSummoner) bool Eluna::OnSummoned(Creature* pCreature, Unit* pSummoner)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED, pCreature->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SUMMONED, pCreature, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED, pCreature->GET_GUID(), pCreature->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(pCreature); Push(pCreature);
Push(pSummoner); 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) bool Eluna::UpdateAI(Creature* me, const uint32 diff)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_AIUPDATE, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_AIUPDATE, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_AIUPDATE, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(diff); 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 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 //Called at creature aggro either by MoveInLOS or Attack Start
bool Eluna::EnterCombat(Creature* me, Unit* target) bool Eluna::EnterCombat(Creature* me, Unit* target)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ENTER_COMBAT, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_ENTER_COMBAT, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ENTER_COMBAT, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(target); 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) // Called at any Damage from any attacker (before damage apply)
bool Eluna::DamageTaken(Creature* me, Unit* attacker, uint32& damage) bool Eluna::DamageTaken(Creature* me, Unit* attacker, uint32& damage)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_DAMAGE_TAKEN, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
bool result = false; bool result = false;
Push(me); Push(me);
Push(attacker); Push(attacker);
Push(damage); Push(damage);
int damageIndex = lua_gettop(L); 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) while (n > 0)
{ {
@@ -211,163 +147,112 @@ bool Eluna::DamageTaken(Creature* me, Unit* attacker, uint32& damage)
bool Eluna::JustDied(Creature* me, Unit* killer) bool Eluna::JustDied(Creature* me, Unit* killer)
{ {
On_Reset(me); On_Reset(me);
START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_DIED, me, false);
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;
Push(me); Push(me);
Push(killer); 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 //Called at creature killing another unit
bool Eluna::KilledUnit(Creature* me, Unit* victim) bool Eluna::KilledUnit(Creature* me, Unit* victim)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_TARGET_DIED, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_TARGET_DIED, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_TARGET_DIED, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(victim); 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 // Called when the creature summon successfully other creature
bool Eluna::JustSummoned(Creature* me, Creature* summon) bool Eluna::JustSummoned(Creature* me, Creature* summon)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(summon); 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 // Called when a summoned creature is despawned
bool Eluna::SummonedCreatureDespawn(Creature* me, Creature* summon) bool Eluna::SummonedCreatureDespawn(Creature* me, Creature* summon)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(summon); 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 //Called at waypoint reached or PointMovement end
bool Eluna::MovementInform(Creature* me, uint32 type, uint32 id) bool Eluna::MovementInform(Creature* me, uint32 type, uint32 id)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REACH_WP, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_REACH_WP, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REACH_WP, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(type); Push(type);
Push(id); 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. // Called before EnterCombat even before the creature is in combat.
bool Eluna::AttackStart(Creature* me, Unit* target) bool Eluna::AttackStart(Creature* me, Unit* target)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_PRE_COMBAT, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_PRE_COMBAT, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_PRE_COMBAT, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(target); 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 // Called for reaction at stopping attack at no attackers or targets
bool Eluna::EnterEvadeMode(Creature* me) bool Eluna::EnterEvadeMode(Creature* me)
{ {
On_Reset(me); On_Reset(me);
START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_LEAVE_COMBAT, me, false);
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;
Push(me); 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) // Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
bool Eluna::AttackedBy(Creature* me, Unit* attacker) bool Eluna::AttackedBy(Creature* me, Unit* attacker)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ATTACKED_AT, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_ATTACKED_AT, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ATTACKED_AT, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(attacker); 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) // Called when creature is spawned or respawned (for reseting variables)
bool Eluna::JustRespawned(Creature* me) bool Eluna::JustRespawned(Creature* me)
{ {
On_Reset(me); On_Reset(me);
START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SPAWN, me, false);
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;
Push(me); 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 // Called at reaching home after evade
bool Eluna::JustReachedHome(Creature* me) bool Eluna::JustReachedHome(Creature* me)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REACH_HOME, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_REACH_HOME, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REACH_HOME, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); 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 // Called at text emote receive from player
bool Eluna::ReceiveEmote(Creature* me, Player* player, uint32 emoteId) bool Eluna::ReceiveEmote(Creature* me, Player* player, uint32 emoteId)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_RECEIVE_EMOTE, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(player); Push(player);
Push(emoteId); 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 // called when the corpse of this creature gets removed
bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay) bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_CORPSE_REMOVED, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_CORPSE_REMOVED, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_CORPSE_REMOVED, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
bool result = false; bool result = false;
Push(me); Push(me);
Push(respawnDelay); Push(respawnDelay);
int respawnDelayIndex = lua_gettop(L); 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) while (n > 0)
{ {
@@ -392,96 +277,67 @@ bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay)
bool Eluna::MoveInLineOfSight(Creature* me, Unit* who) bool Eluna::MoveInLineOfSight(Creature* me, Unit* who)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_MOVE_IN_LOS, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_MOVE_IN_LOS, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_MOVE_IN_LOS, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(who); 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) // Called on creature initial spawn, respawn, death, evade (leave combat)
void Eluna::On_Reset(Creature* me) // Not an override, custom void Eluna::On_Reset(Creature* me) // Not an override, custom
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_RESET, me->GetEntry())) START_HOOK(CREATURE_EVENT_ON_RESET, me);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_RESET, me->GET_GUID(), me->GetInstanceId()))
return;
LOCK_ELUNA;
Push(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 // Called when hit by a spell
bool Eluna::SpellHit(Creature* me, Unit* caster, SpellInfo const* spell) bool Eluna::SpellHit(Creature* me, Unit* caster, SpellInfo const* spell)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_HIT_BY_SPELL, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_HIT_BY_SPELL, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_HIT_BY_SPELL, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(caster); Push(caster);
Push(spell->Id); // Pass spell object? 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 // Called when spell hits a target
bool Eluna::SpellHitTarget(Creature* me, Unit* target, SpellInfo const* spell) bool Eluna::SpellHitTarget(Creature* me, Unit* target, SpellInfo const* spell)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(target); Push(target);
Push(spell->Id); // Pass spell object? 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 #ifdef TRINITY
bool Eluna::SummonedCreatureDies(Creature* me, Creature* summon, Unit* killer) bool Eluna::SummonedCreatureDies(Creature* me, Creature* summon, Unit* killer)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(summon); Push(summon);
Push(killer); 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 // Called when owner takes damage
bool Eluna::OwnerAttackedBy(Creature* me, Unit* attacker) bool Eluna::OwnerAttackedBy(Creature* me, Unit* attacker)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(attacker); 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 // Called when owner attacks something
bool Eluna::OwnerAttacked(Creature* me, Unit* target) bool Eluna::OwnerAttacked(Creature* me, Unit* target)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED, me->GetEntry())) START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_OWNER_ATTACKED, me, false);
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me); Push(me);
Push(target); 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 // TRINITY
#endif // _CREATURE_HOOKS_H

View File

@@ -1,573 +0,0 @@
/*
* Copyright (C) 2010 - 2015 Eluna Lua Engine <http://emudevs.com/>
* 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<Binding*> FunctionRefVector;
typedef UNORDERED_MAP<int, FunctionRefVector> 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<typename T>
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<int> 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<int>::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<int> 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<int>::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<typename T>
class EntryBind : public ElunaBind
{
public:
typedef UNORDERED_MAP<uint32, EventToFunctionsMap> 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<int> 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<int>::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<int> 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<int>::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<typename T>
class UniqueBind : public ElunaBind
{
public:
typedef UNORDERED_MAP<uint32, EventToFunctionsMap> InstanceToEventsMap;
typedef UNORDERED_MAP<uint64, InstanceToEventsMap> 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<int> 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<int>::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<int> 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<int>::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

View File

@@ -54,7 +54,7 @@ class ElunaEventProcessor
public: public:
typedef std::multimap<uint64, LuaEvent*> EventList; typedef std::multimap<uint64, LuaEvent*> EventList;
typedef UNORDERED_MAP<int, LuaEvent*> EventMap; typedef std::unordered_map<int, LuaEvent*> EventMap;
ElunaEventProcessor(Eluna** _E, WorldObject* _obj); ElunaEventProcessor(Eluna** _E, WorldObject* _obj);
~ElunaEventProcessor(); ~ElunaEventProcessor();
@@ -80,7 +80,7 @@ private:
class EventMgr : public ElunaUtil::RWLockable class EventMgr : public ElunaUtil::RWLockable
{ {
public: public:
typedef UNORDERED_SET<ElunaEventProcessor*> ProcessorSet; typedef std::unordered_set<ElunaEventProcessor*> ProcessorSet;
ProcessorSet processors; ProcessorSet processors;
ElunaEventProcessor* globalProcessor; ElunaEventProcessor* globalProcessor;
Eluna** E; Eluna** E;

View File

@@ -7,6 +7,8 @@
#ifndef _ELUNA_UTIL_H #ifndef _ELUNA_UTIL_H
#define _ELUNA_UTIL_H #define _ELUNA_UTIL_H
#include <unordered_map>
#include <unordered_set>
#include "Common.h" #include "Common.h"
#include "SharedDefines.h" #include "SharedDefines.h"
#include "ObjectGuid.h" #include "ObjectGuid.h"
@@ -28,8 +30,6 @@
#ifdef USING_BOOST #ifdef USING_BOOST
#include <boost/thread/locks.hpp> #include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp> #include <boost/thread/shared_mutex.hpp>
#else
#include <ace/Recursive_Thread_Mutex.h>
#endif #endif
#ifdef TRINITY #ifdef TRINITY
@@ -50,15 +50,6 @@ typedef QueryNamedResult ElunaQuery;
#define GetTemplate GetProto #define GetTemplate GetProto
#endif #endif
#ifndef UNORDERED_MAP
#include <unordered_map>
#define UNORDERED_MAP std::unordered_map
#endif
#ifndef UNORDERED_SET
#include <unordered_set>
#define UNORDERED_SET std::unordered_set
#endif
#ifndef MAKE_NEW_GUID #ifndef MAKE_NEW_GUID
#define MAKE_NEW_GUID(l, e, h) ObjectGuid(h, e, l) #define MAKE_NEW_GUID(l, e, h) ObjectGuid(h, e, l)
#endif #endif
@@ -132,11 +123,11 @@ namespace ElunaUtil
public: public:
#ifdef USING_BOOST #ifdef USING_BOOST
typedef boost::recursive_mutex LockType; typedef boost::shared_mutex LockType;
typedef boost::shared_lock<boost::shared_mutex> ReadGuard; typedef boost::shared_lock<LockType> ReadGuard;
typedef boost::unique_lock<boost::shared_mutex> WriteGuard; typedef boost::unique_lock<LockType> WriteGuard;
#else #else
typedef ACE_Recursive_Thread_Mutex LockType; typedef ACE_RW_Thread_Mutex LockType;
typedef ACE_Read_Guard<LockType> ReadGuard; typedef ACE_Read_Guard<LockType> ReadGuard;
typedef ACE_Write_Guard<LockType> WriteGuard; typedef ACE_Write_Guard<LockType> WriteGuard;
#endif #endif

View File

@@ -4,119 +4,76 @@
* Please see the included DOCS/LICENSE.md for more information * Please see the included DOCS/LICENSE.md for more information
*/ */
#ifndef _GAMEOBJECT_HOOKS_H
#define _GAMEOBJECT_HOOKS_H
#include "Hooks.h" #include "Hooks.h"
#include "HookHelpers.h" #include "HookHelpers.h"
#include "LuaEngine.h" #include "LuaEngine.h"
#include "ElunaBinding.h" #include "BindingMap.h"
#include "ElunaIncludes.h" #include "ElunaIncludes.h"
#include "ElunaEventMgr.h" #include "ElunaEventMgr.h"
#include "ElunaTemplate.h" #include "ElunaTemplate.h"
using namespace Hooks; using namespace Hooks;
#define START_HOOK(EVENT, ENTRY) \
if (!IsEnabled())\
return;\
auto key = EntryKey<GameObjectEvents>(EVENT, ENTRY);\
if (!GameObjectEventBindings->HasBindingsFor(key))\
return;\
LOCK_ELUNA
#define START_HOOK_WITH_RETVAL(EVENT, ENTRY, RETVAL) \
if (!IsEnabled())\
return RETVAL;\
auto key = EntryKey<GameObjectEvents>(EVENT, ENTRY);\
if (!GameObjectEventBindings->HasBindingsFor(key))\
return RETVAL;\
LOCK_ELUNA
bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, GameObject* pTarget) bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, GameObject* pTarget)
{ {
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry())) START_HOOK_WITH_RETVAL(GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry(), false);
return false;
LOCK_ELUNA;
Push(pCaster); Push(pCaster);
Push(spellId); Push(spellId);
Push(effIndex); Push(effIndex);
Push(pTarget); Push(pTarget);
return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()); return CallAllFunctionsBool(GameObjectEventBindings, key);
}
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());
} }
void Eluna::UpdateAI(GameObject* pGameObject, uint32 diff) void Eluna::UpdateAI(GameObject* pGameObject, uint32 diff)
{ {
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_AIUPDATE, pGameObject->GetEntry())) START_HOOK(GAMEOBJECT_EVENT_ON_AIUPDATE, pGameObject->GetEntry());
return;
LOCK_ELUNA;
pGameObject->elunaEvents->Update(diff); pGameObject->elunaEvents->Update(diff);
Push(pGameObject); Push(pGameObject);
Push(diff); 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) bool Eluna::OnQuestReward(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest, uint32 opt)
{ {
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_QUEST_REWARD, pGameObject->GetEntry())) START_HOOK_WITH_RETVAL(GAMEOBJECT_EVENT_ON_QUEST_REWARD, pGameObject->GetEntry(), false);
return false;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pGameObject); Push(pGameObject);
Push(pQuest); Push(pQuest);
Push(opt); Push(opt);
return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_QUEST_REWARD, pGameObject->GetEntry()); return CallAllFunctionsBool(GameObjectEventBindings, key);
} }
uint32 Eluna::GetDialogStatus(Player* pPlayer, GameObject* pGameObject) uint32 Eluna::GetDialogStatus(Player* pPlayer, GameObject* pGameObject)
{ {
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DIALOG_STATUS, pGameObject->GetEntry())) START_HOOK_WITH_RETVAL(GAMEOBJECT_EVENT_ON_DIALOG_STATUS, pGameObject->GetEntry(), false);
return DIALOG_STATUS_SCRIPTED_NO_STATUS;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pGameObject); Push(pGameObject);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DIALOG_STATUS, pGameObject->GetEntry()); CallAllFunctions(GameObjectEventBindings, key);
return DIALOG_STATUS_SCRIPTED_NO_STATUS; // DIALOG_STATUS_UNDEFINED return DIALOG_STATUS_SCRIPTED_NO_STATUS; // DIALOG_STATUS_UNDEFINED
} }
@@ -124,89 +81,63 @@ uint32 Eluna::GetDialogStatus(Player* pPlayer, GameObject* pGameObject)
#ifndef TBC #ifndef TBC
void Eluna::OnDestroyed(GameObject* pGameObject, Player* pPlayer) void Eluna::OnDestroyed(GameObject* pGameObject, Player* pPlayer)
{ {
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry())) START_HOOK(GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry());
return;
LOCK_ELUNA;
Push(pGameObject); Push(pGameObject);
Push(pPlayer); Push(pPlayer);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry()); CallAllFunctions(GameObjectEventBindings, key);
} }
void Eluna::OnDamaged(GameObject* pGameObject, Player* pPlayer) void Eluna::OnDamaged(GameObject* pGameObject, Player* pPlayer)
{ {
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry())) START_HOOK(GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry());
return;
LOCK_ELUNA;
Push(pGameObject); Push(pGameObject);
Push(pPlayer); Push(pPlayer);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry()); CallAllFunctions(GameObjectEventBindings, key);
} }
#endif #endif
#endif #endif
void Eluna::OnLootStateChanged(GameObject* pGameObject, uint32 state) void Eluna::OnLootStateChanged(GameObject* pGameObject, uint32 state)
{ {
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry())) START_HOOK(GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry());
return;
LOCK_ELUNA;
Push(pGameObject); Push(pGameObject);
Push(state); Push(state);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry()); CallAllFunctions(GameObjectEventBindings, key);
} }
void Eluna::OnGameObjectStateChanged(GameObject* pGameObject, uint32 state) void Eluna::OnGameObjectStateChanged(GameObject* pGameObject, uint32 state)
{ {
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, pGameObject->GetEntry())) START_HOOK(GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, pGameObject->GetEntry());
return;
LOCK_ELUNA;
Push(pGameObject); Push(pGameObject);
Push(state); 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())) START_HOOK(GAMEOBJECT_EVENT_ON_SPAWN, pGameObject->GetEntry());
return; Push(pGameObject);
CallAllFunctions(GameObjectEventBindings, key);
LOCK_ELUNA;
Push(gameobject);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_SPAWN, gameobject->GetEntry());
} }
void Eluna::OnAddToWorld(GameObject* gameobject) void Eluna::OnAddToWorld(GameObject* pGameObject)
{ {
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_ADD, gameobject->GetEntry())) START_HOOK(GAMEOBJECT_EVENT_ON_ADD, pGameObject->GetEntry());
return; Push(pGameObject);
CallAllFunctions(GameObjectEventBindings, key);
LOCK_ELUNA;
Push(gameobject);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_ADD, gameobject->GetEntry());
} }
void Eluna::OnRemoveFromWorld(GameObject* gameobject) void Eluna::OnRemoveFromWorld(GameObject* pGameObject)
{ {
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_REMOVE, gameobject->GetEntry())) START_HOOK(GAMEOBJECT_EVENT_ON_REMOVE, pGameObject->GetEntry());
return; Push(pGameObject);
CallAllFunctions(GameObjectEventBindings, key);
LOCK_ELUNA;
Push(gameobject);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_REMOVE, gameobject->GetEntry());
} }
bool Eluna::OnGameObjectUse(Player* pPlayer, GameObject* pGameObject) bool Eluna::OnGameObjectUse(Player* pPlayer, GameObject* pGameObject)
{ {
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_USE, pGameObject->GetEntry())) START_HOOK_WITH_RETVAL(GAMEOBJECT_EVENT_ON_USE, pGameObject->GetEntry(), false);
return false;
LOCK_ELUNA;
Push(pGameObject); Push(pGameObject);
Push(pPlayer); Push(pPlayer);
return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_USE, pGameObject->GetEntry()); return CallAllFunctionsBool(GameObjectEventBindings, key);
} }
#endif // _GAMEOBJECT_HOOKS_H

View File

@@ -7,7 +7,7 @@
#ifndef GLOBALMETHODS_H #ifndef GLOBALMETHODS_H
#define GLOBALMETHODS_H #define GLOBALMETHODS_H
#include "ElunaBinding.h" #include "BindingMap.h"
/*** /***
* These functions can be used anywhere at any time, including at start-up. * These functions can be used anywhere at any time, including at start-up.
@@ -503,18 +503,11 @@ namespace LuaGlobalFunctions
uint32 ev = Eluna::CHECKVAL<uint32>(L, 2); uint32 ev = Eluna::CHECKVAL<uint32>(L, 2);
luaL_checktype(L, 3, LUA_TFUNCTION); luaL_checktype(L, 3, LUA_TFUNCTION);
uint32 shots = Eluna::CHECKVAL<uint32>(L, 4, 0); uint32 shots = Eluna::CHECKVAL<uint32>(L, 4, 0);
bool returnCallback = Eluna::CHECKVAL<bool>(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); lua_pushvalue(L, 3);
int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); int functionRef = luaL_ref(L, LUA_REGISTRYINDEX);
if (functionRef >= 0) 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 else
luaL_argerror(L, 3, "unable to make a ref to function"); luaL_argerror(L, 3, "unable to make a ref to function");
return 0; return 0;
@@ -525,18 +518,11 @@ namespace LuaGlobalFunctions
uint32 ev = Eluna::CHECKVAL<uint32>(L, 1); uint32 ev = Eluna::CHECKVAL<uint32>(L, 1);
luaL_checktype(L, 2, LUA_TFUNCTION); luaL_checktype(L, 2, LUA_TFUNCTION);
uint32 shots = Eluna::CHECKVAL<uint32>(L, 3, 0); uint32 shots = Eluna::CHECKVAL<uint32>(L, 3, 0);
bool returnCallback = Eluna::CHECKVAL<bool>(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); lua_pushvalue(L, 2);
int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); int functionRef = luaL_ref(L, LUA_REGISTRYINDEX);
if (functionRef >= 0) 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 else
luaL_argerror(L, 2, "unable to make a ref to function"); luaL_argerror(L, 2, "unable to make a ref to function");
return 0; return 0;
@@ -549,18 +535,11 @@ namespace LuaGlobalFunctions
uint32 ev = Eluna::CHECKVAL<uint32>(L, 3); uint32 ev = Eluna::CHECKVAL<uint32>(L, 3);
luaL_checktype(L, 4, LUA_TFUNCTION); luaL_checktype(L, 4, LUA_TFUNCTION);
uint32 shots = Eluna::CHECKVAL<uint32>(L, 5, 0); uint32 shots = Eluna::CHECKVAL<uint32>(L, 5, 0);
bool returnCallback = Eluna::CHECKVAL<bool>(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); lua_pushvalue(L, 4);
int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); int functionRef = luaL_ref(L, LUA_REGISTRYINDEX);
if (functionRef >= 0) 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 else
luaL_argerror(L, 4, "unable to make a ref to function"); luaL_argerror(L, 4, "unable to make a ref to function");
return 0; return 0;
@@ -569,16 +548,6 @@ namespace LuaGlobalFunctions
/** /**
* Registers a server event handler. * 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 * enum ServerEvents
* { * {
* // Server * // Server
@@ -634,14 +603,12 @@ namespace LuaGlobalFunctions
* SERVER_EVENT_COUNT * SERVER_EVENT_COUNT
* }; * };
* *
* @proto (event, function) * @proto cancel = (event, function)
* @proto (event, function, shots) * @proto cancel = (event, function, shots)
* @proto cancel = (event, function, 0, true)
* *
* @param uint32 event : server event ID, refer to ServerEvents above * @param uint32 event : server event ID, refer to ServerEvents above
* @param function function : function that will be called when the event occurs * @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 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 * @return function cancel : a function that cancels the binding when called
*/ */
@@ -653,16 +620,6 @@ namespace LuaGlobalFunctions
/** /**
* Registers a [Player] event handler. * 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.
*
* <pre> * <pre>
* enum PlayerEvents * enum PlayerEvents
* { * {
@@ -715,14 +672,12 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @proto (event, function) * @proto cancel = (event, function)
* @proto (event, function, shots) * @proto cancel = (event, function, shots)
* @proto cancel = (event, function, 0, true)
* *
* @param uint32 event : [Player] event Id, refer to PlayerEvents above * @param uint32 event : [Player] event Id, refer to PlayerEvents above
* @param function function : function to register * @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 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 * @return function cancel : a function that cancels the binding when called
*/ */
@@ -734,16 +689,6 @@ namespace LuaGlobalFunctions
/** /**
* Registers a [Guild] event handler. * 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.
*
* <pre> * <pre>
* enum GuildEvents * enum GuildEvents
* { * {
@@ -764,14 +709,12 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @proto (event, function) * @proto cancel = (event, function)
* @proto (event, function, shots) * @proto cancel = (event, function, shots)
* @proto cancel = (event, function, 0, true)
* *
* @param uint32 event : [Guild] event Id, refer to GuildEvents above * @param uint32 event : [Guild] event Id, refer to GuildEvents above
* @param function function : function to register * @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 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 * @return function cancel : a function that cancels the binding when called
*/ */
@@ -783,16 +726,6 @@ namespace LuaGlobalFunctions
/** /**
* Registers a [Group] event handler. * 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.
*
* <pre> * <pre>
* enum GroupEvents * enum GroupEvents
* { * {
@@ -808,14 +741,12 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @proto (event, function) * @proto cancel = (event, function)
* @proto (event, function, shots) * @proto cancel = (event, function, shots)
* @proto cancel = (event, function, 0, true)
* *
* @param uint32 event : [Group] event Id, refer to GroupEvents above * @param uint32 event : [Group] event Id, refer to GroupEvents above
* @param function function : function to register * @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 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 * @return function cancel : a function that cancels the binding when called
*/ */
@@ -828,16 +759,6 @@ namespace LuaGlobalFunctions
/** /**
* Registers a [BattleGround] event handler. * 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.
*
* <pre> * <pre>
* enum BGEvents * enum BGEvents
* { * {
@@ -849,14 +770,12 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @proto (event, function) * @proto cancel = (event, function)
* @proto (event, function, shots) * @proto cancel = (event, function, shots)
* @proto cancel = (event, function, 0, true)
* *
* @param uint32 event : [BattleGround] event Id, refer to BGEvents above * @param uint32 event : [BattleGround] event Id, refer to BGEvents above
* @param function function : function to register * @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 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 * @return function cancel : a function that cancels the binding when called
*/ */
@@ -868,16 +787,6 @@ namespace LuaGlobalFunctions
/** /**
* Registers a [WorldPacket] event handler. * 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.
*
* <pre> * <pre>
* enum PacketEvents * enum PacketEvents
* { * {
@@ -889,15 +798,13 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @proto (entry, event, function) * @proto cancel = (entry, event, function)
* @proto (entry, event, function, shots) * @proto cancel = (entry, event, function, shots)
* @proto cancel = (entry, event, function, 0, true)
* *
* @param uint32 entry : opcode * @param uint32 entry : opcode
* @param uint32 event : packet event Id, refer to PacketEvents above * @param uint32 event : packet event Id, refer to PacketEvents above
* @param function function : function to register * @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 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 * @return function cancel : a function that cancels the binding when called
*/ */
@@ -909,16 +816,6 @@ namespace LuaGlobalFunctions
/** /**
* Registers a [Creature] gossip event handler. * 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.
*
* <pre> * <pre>
* enum GossipEvents * enum GossipEvents
* { * {
@@ -928,15 +825,13 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @proto (menu_id, event, function) * @proto cancel = (menu_id, event, function)
* @proto (menu_id, event, function, shots) * @proto cancel = (menu_id, event, function, shots)
* @proto cancel = (menu_id, event, function, 0, true)
* *
* @param uint32 menu_id : [Creature] entry Id * @param uint32 menu_id : [Creature] entry Id
* @param uint32 event : [Creature] gossip event Id, refer to GossipEvents above * @param uint32 event : [Creature] gossip event Id, refer to GossipEvents above
* @param function function : function to register * @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 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 * @return function cancel : a function that cancels the binding when called
*/ */
@@ -948,16 +843,6 @@ namespace LuaGlobalFunctions
/** /**
* Registers a [GameObject] gossip event handler. * 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.
*
* <pre> * <pre>
* enum GossipEvents * enum GossipEvents
* { * {
@@ -967,15 +852,13 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @proto (menu_id, event, function) * @proto cancel = (menu_id, event, function)
* @proto (menu_id, event, function, shots) * @proto cancel = (menu_id, event, function, shots)
* @proto cancel = (menu_id, event, function, 0, true)
* *
* @param uint32 menu_id : [GameObject] entry Id * @param uint32 menu_id : [GameObject] entry Id
* @param uint32 event : [GameObject] gossip event Id, refer to GossipEvents above * @param uint32 event : [GameObject] gossip event Id, refer to GossipEvents above
* @param function function : function to register * @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 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 * @return function cancel : a function that cancels the binding when called
*/ */
@@ -987,16 +870,6 @@ namespace LuaGlobalFunctions
/** /**
* Registers an [Item] event handler. * 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.
*
* <pre> * <pre>
* enum ItemEvents * enum ItemEvents
* { * {
@@ -1009,15 +882,13 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @proto (entry, event, function) * @proto cancel = (entry, event, function)
* @proto (entry, event, function, shots) * @proto cancel = (entry, event, function, shots)
* @proto cancel = (entry, event, function, 0, true)
* *
* @param uint32 entry : [Item] entry Id * @param uint32 entry : [Item] entry Id
* @param uint32 event : [Item] event Id, refer to ItemEvents above * @param uint32 event : [Item] event Id, refer to ItemEvents above
* @param function function : function to register * @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 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 * @return function cancel : a function that cancels the binding when called
*/ */
@@ -1029,16 +900,6 @@ namespace LuaGlobalFunctions
/** /**
* Registers an [Item] gossip event handler. * 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.
*
* <pre> * <pre>
* enum GossipEvents * enum GossipEvents
* { * {
@@ -1048,15 +909,13 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @proto (entry, event, function) * @proto cancel = (entry, event, function)
* @proto (entry, event, function, shots) * @proto cancel = (entry, event, function, shots)
* @proto cancel = (entry, event, function, 0, true)
* *
* @param uint32 entry : [Item] entry Id * @param uint32 entry : [Item] entry Id
* @param uint32 event : [Item] gossip event Id, refer to GossipEvents above * @param uint32 event : [Item] gossip event Id, refer to GossipEvents above
* @param function function : function to register * @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 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 * @return function cancel : a function that cancels the binding when called
*/ */
@@ -1068,16 +927,6 @@ namespace LuaGlobalFunctions
/** /**
* Registers a [Player] gossip event handler. * 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.
*
* <pre> * <pre>
* enum GossipEvents * enum GossipEvents
* { * {
@@ -1087,15 +936,13 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @proto (menu_id, event, function) * @proto cancel = (menu_id, event, function)
* @proto (menu_id, event, function, shots) * @proto cancel = (menu_id, event, function, shots)
* @proto cancel = (menu_id, event, function, 0, true)
* *
* @param uint32 menu_id : [Player] gossip menu Id * @param uint32 menu_id : [Player] gossip menu Id
* @param uint32 event : [Player] gossip event Id, refer to GossipEvents above * @param uint32 event : [Player] gossip event Id, refer to GossipEvents above
* @param function function : function to register * @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 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 * @return function cancel : a function that cancels the binding when called
*/ */
@@ -1107,16 +954,6 @@ namespace LuaGlobalFunctions
/** /**
* Registers a [Creature] event handler. * 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.
*
* <pre> * <pre>
* enum CreatureEvents * enum CreatureEvents
* { * {
@@ -1161,15 +998,13 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @proto (entry, event, function) * @proto cancel = (entry, event, function)
* @proto (entry, event, function, shots) * @proto cancel = (entry, event, function, shots)
* @proto cancel = (entry, event, function, 0, true)
* *
* @param uint32 entry : the ID of one or more [Creature]s * @param uint32 entry : the ID of one or more [Creature]s
* @param uint32 event : refer to CreatureEvents above * @param uint32 event : refer to CreatureEvents above
* @param function function : function that will be called when the event occurs * @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 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 * @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]. * 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.
*
* <pre> * <pre>
* enum CreatureEvents * enum CreatureEvents
* { * {
@@ -1235,16 +1060,14 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @proto (guid, instance_id, event, function) * @proto cancel = (guid, instance_id, event, function)
* @proto (guid, instance_id, event, function, shots) * @proto cancel = (guid, instance_id, event, function, shots)
* @proto cancel = (guid, instance_id, event, function, 0, true)
* *
* @param uint64 guid : the GUID of a single [Creature] * @param uint64 guid : the GUID of a single [Creature]
* @param uint32 instance_id : the instance ID of a single [Creature] * @param uint32 instance_id : the instance ID of a single [Creature]
* @param uint32 event : refer to CreatureEvents above * @param uint32 event : refer to CreatureEvents above
* @param function function : function that will be called when the event occurs * @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 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 * @return function cancel : a function that cancels the binding when called
*/ */
@@ -1256,16 +1079,6 @@ namespace LuaGlobalFunctions
/** /**
* Registers a [GameObject] event handler. * 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.
*
* <pre> * <pre>
* enum GameObjectEvents * enum GameObjectEvents
* { * {
@@ -1286,15 +1099,13 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @proto (entry, event, function) * @proto cancel = (entry, event, function)
* @proto (entry, event, function, shots) * @proto cancel = (entry, event, function, shots)
* @proto cancel = (entry, event, function, 0, true)
* *
* @param uint32 entry : [GameObject] entry Id * @param uint32 entry : [GameObject] entry Id
* @param uint32 event : [GameObject] event Id, refer to GameObjectEvents above * @param uint32 event : [GameObject] event Id, refer to GameObjectEvents above
* @param function function : function to register * @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 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 * @return function cancel : a function that cancels the binding when called
*/ */
@@ -2632,15 +2443,16 @@ namespace LuaGlobalFunctions
*/ */
int ClearBattleGroundEvents(Eluna* E, lua_State* L) int ClearBattleGroundEvents(Eluna* E, lua_State* L)
{ {
typedef EventKey<Hooks::BGEvents> Key;
if (lua_isnoneornil(L, 1)) if (lua_isnoneornil(L, 1))
{ {
for (uint32 i = Hooks::BG_EVENT_ON_START; i < Hooks::BG_EVENT_COUNT; ++i) E->BGEventBindings->Clear();
E->BGEventBindings->Clear(i);
} }
else else
{ {
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 1); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 1);
E->BGEventBindings->Clear(event_type); E->BGEventBindings->Clear(Key((Hooks::BGEvents)event_type));
} }
return 0; return 0;
} }
@@ -2662,18 +2474,20 @@ namespace LuaGlobalFunctions
*/ */
int ClearCreatureEvents(Eluna* E, lua_State* L) int ClearCreatureEvents(Eluna* E, lua_State* L)
{ {
typedef EntryKey<Hooks::CreatureEvents> Key;
if (lua_isnoneornil(L, 2)) if (lua_isnoneornil(L, 2))
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
for (uint32 i = Hooks::CREATURE_EVENT_ON_ENTER_COMBAT; i < Hooks::CREATURE_EVENT_COUNT; ++i) for (uint32 i = 1; i < Hooks::CREATURE_EVENT_COUNT; ++i)
E->CreatureEventBindings->Clear(entry, i); E->CreatureEventBindings->Clear(Key((Hooks::CreatureEvents)i, entry));
} }
else else
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2);
E->CreatureEventBindings->Clear(entry, event_type); E->CreatureEventBindings->Clear(Key((Hooks::CreatureEvents)event_type, entry));
} }
return 0; return 0;
} }
@@ -2696,20 +2510,22 @@ namespace LuaGlobalFunctions
*/ */
int ClearUniqueCreatureEvents(Eluna* E, lua_State* L) int ClearUniqueCreatureEvents(Eluna* E, lua_State* L)
{ {
typedef UniqueObjectKey<Hooks::CreatureEvents> Key;
if (lua_isnoneornil(L, 3)) if (lua_isnoneornil(L, 3))
{ {
uint64 guid = Eluna::CHECKVAL<uint64>(L, 1); uint64 guid = Eluna::CHECKVAL<uint64>(L, 1);
uint32 instanceId = Eluna::CHECKVAL<uint32>(L, 2); uint32 instanceId = Eluna::CHECKVAL<uint32>(L, 2);
for (uint32 i = Hooks::CREATURE_EVENT_ON_ENTER_COMBAT; i < Hooks::CREATURE_EVENT_COUNT; ++i) for (uint32 i = 1; i < Hooks::CREATURE_EVENT_COUNT; ++i)
E->CreatureUniqueBindings->Clear(guid, instanceId, i); E->CreatureUniqueBindings->Clear(Key((Hooks::CreatureEvents)i, guid, instanceId));
} }
else else
{ {
uint64 guid = Eluna::CHECKVAL<uint64>(L, 1); uint64 guid = Eluna::CHECKVAL<uint64>(L, 1);
uint32 instanceId = Eluna::CHECKVAL<uint32>(L, 2); uint32 instanceId = Eluna::CHECKVAL<uint32>(L, 2);
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 3); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 3);
E->CreatureUniqueBindings->Clear(guid, instanceId, event_type); E->CreatureUniqueBindings->Clear(Key((Hooks::CreatureEvents)event_type, guid, instanceId));
} }
return 0; return 0;
} }
@@ -2731,18 +2547,20 @@ namespace LuaGlobalFunctions
*/ */
int ClearCreatureGossipEvents(Eluna* E, lua_State* L) int ClearCreatureGossipEvents(Eluna* E, lua_State* L)
{ {
typedef EntryKey<Hooks::GossipEvents> Key;
if (lua_isnoneornil(L, 2)) if (lua_isnoneornil(L, 2))
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
for (uint32 i = Hooks::GOSSIP_EVENT_ON_HELLO; i < Hooks::GOSSIP_EVENT_COUNT; ++i) for (uint32 i = 1; i < Hooks::GOSSIP_EVENT_COUNT; ++i)
E->CreatureGossipBindings->Clear(entry, i); E->CreatureGossipBindings->Clear(Key((Hooks::GossipEvents)i, entry));
} }
else else
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2);
E->CreatureGossipBindings->Clear(entry, event_type); E->CreatureGossipBindings->Clear(Key((Hooks::GossipEvents)event_type, entry));
} }
return 0; return 0;
} }
@@ -2764,18 +2582,20 @@ namespace LuaGlobalFunctions
*/ */
int ClearGameObjectEvents(Eluna* E, lua_State* L) int ClearGameObjectEvents(Eluna* E, lua_State* L)
{ {
typedef EntryKey<Hooks::GameObjectEvents> Key;
if (lua_isnoneornil(L, 2)) if (lua_isnoneornil(L, 2))
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
for (uint32 i = Hooks::GAMEOBJECT_EVENT_ON_AIUPDATE; i < Hooks::GAMEOBJECT_EVENT_COUNT; ++i) for (uint32 i = 1; i < Hooks::GAMEOBJECT_EVENT_COUNT; ++i)
E->GameObjectEventBindings->Clear(entry, i); E->GameObjectEventBindings->Clear(Key((Hooks::GameObjectEvents)i, entry));
} }
else else
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2);
E->GameObjectEventBindings->Clear(entry, event_type); E->GameObjectEventBindings->Clear(Key((Hooks::GameObjectEvents)event_type, entry));
} }
return 0; return 0;
} }
@@ -2797,18 +2617,20 @@ namespace LuaGlobalFunctions
*/ */
int ClearGameObjectGossipEvents(Eluna* E, lua_State* L) int ClearGameObjectGossipEvents(Eluna* E, lua_State* L)
{ {
typedef EntryKey<Hooks::GossipEvents> Key;
if (lua_isnoneornil(L, 2)) if (lua_isnoneornil(L, 2))
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
for (uint32 i = Hooks::GOSSIP_EVENT_ON_HELLO; i < Hooks::GOSSIP_EVENT_COUNT; ++i) for (uint32 i = 1; i < Hooks::GOSSIP_EVENT_COUNT; ++i)
E->GameObjectGossipBindings->Clear(entry, i); E->GameObjectGossipBindings->Clear(Key((Hooks::GossipEvents)i, entry));
} }
else else
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2);
E->GameObjectGossipBindings->Clear(entry, event_type); E->GameObjectGossipBindings->Clear(Key((Hooks::GossipEvents)event_type, entry));
} }
return 0; return 0;
} }
@@ -2826,15 +2648,16 @@ namespace LuaGlobalFunctions
*/ */
int ClearGroupEvents(Eluna* E, lua_State* L) int ClearGroupEvents(Eluna* E, lua_State* L)
{ {
typedef EventKey<Hooks::GroupEvents> Key;
if (lua_isnoneornil(L, 1)) if (lua_isnoneornil(L, 1))
{ {
for (uint32 i = Hooks::GROUP_EVENT_ON_MEMBER_ADD; i < Hooks::GROUP_EVENT_COUNT; ++i) E->GroupEventBindings->Clear();
E->GroupEventBindings->Clear(i);
} }
else else
{ {
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 1); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 1);
E->GroupEventBindings->Clear(event_type); E->GroupEventBindings->Clear(Key((Hooks::GroupEvents)event_type));
} }
return 0; return 0;
} }
@@ -2852,15 +2675,16 @@ namespace LuaGlobalFunctions
*/ */
int ClearGuildEvents(Eluna* E, lua_State* L) int ClearGuildEvents(Eluna* E, lua_State* L)
{ {
typedef EventKey<Hooks::GuildEvents> Key;
if (lua_isnoneornil(L, 1)) if (lua_isnoneornil(L, 1))
{ {
for (uint32 i = Hooks::GUILD_EVENT_ON_ADD_MEMBER; i < Hooks::GUILD_EVENT_COUNT; ++i) E->GuildEventBindings->Clear();
E->GuildEventBindings->Clear(i);
} }
else else
{ {
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 1); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 1);
E->GuildEventBindings->Clear(event_type); E->GuildEventBindings->Clear(Key((Hooks::GuildEvents)event_type));
} }
return 0; return 0;
} }
@@ -2882,18 +2706,20 @@ namespace LuaGlobalFunctions
*/ */
int ClearItemEvents(Eluna* E, lua_State* L) int ClearItemEvents(Eluna* E, lua_State* L)
{ {
typedef EntryKey<Hooks::ItemEvents> Key;
if (lua_isnoneornil(L, 2)) if (lua_isnoneornil(L, 2))
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
for (uint32 i = Hooks::ITEM_EVENT_ON_DUMMY_EFFECT; i < Hooks::ITEM_EVENT_COUNT; ++i) for (uint32 i = 1; i < Hooks::ITEM_EVENT_COUNT; ++i)
E->ItemEventBindings->Clear(entry, i); E->ItemEventBindings->Clear(Key((Hooks::ItemEvents)i, entry));
} }
else else
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2);
E->ItemEventBindings->Clear(entry, event_type); E->ItemEventBindings->Clear(Key((Hooks::ItemEvents)event_type, entry));
} }
return 0; return 0;
} }
@@ -2915,18 +2741,20 @@ namespace LuaGlobalFunctions
*/ */
int ClearItemGossipEvents(Eluna* E, lua_State* L) int ClearItemGossipEvents(Eluna* E, lua_State* L)
{ {
typedef EntryKey<Hooks::GossipEvents> Key;
if (lua_isnoneornil(L, 2)) if (lua_isnoneornil(L, 2))
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
for (uint32 i = Hooks::GOSSIP_EVENT_ON_HELLO; i < Hooks::GOSSIP_EVENT_COUNT; ++i) for (uint32 i = 1; i < Hooks::GOSSIP_EVENT_COUNT; ++i)
E->ItemGossipBindings->Clear(entry, i); E->ItemGossipBindings->Clear(Key((Hooks::GossipEvents)i, entry));
} }
else else
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2);
E->ItemGossipBindings->Clear(entry, event_type); E->ItemGossipBindings->Clear(Key((Hooks::GossipEvents)event_type, entry));
} }
return 0; return 0;
} }
@@ -2945,18 +2773,20 @@ namespace LuaGlobalFunctions
*/ */
int ClearPacketEvents(Eluna* E, lua_State* L) int ClearPacketEvents(Eluna* E, lua_State* L)
{ {
typedef EntryKey<Hooks::PacketEvents> Key;
if (lua_isnoneornil(L, 2)) if (lua_isnoneornil(L, 2))
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
for (uint32 i = Hooks::PACKET_EVENT_ON_PACKET_RECEIVE; i < Hooks::PACKET_EVENT_COUNT; ++i) for (uint32 i = 1; i < Hooks::PACKET_EVENT_COUNT; ++i)
E->PacketEventBindings->Clear(entry, i); E->PacketEventBindings->Clear(Key((Hooks::PacketEvents)i, entry));
} }
else else
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2);
E->PacketEventBindings->Clear(entry, event_type); E->PacketEventBindings->Clear(Key((Hooks::PacketEvents)event_type, entry));
} }
return 0; return 0;
} }
@@ -2974,15 +2804,16 @@ namespace LuaGlobalFunctions
*/ */
int ClearPlayerEvents(Eluna* E, lua_State* L) int ClearPlayerEvents(Eluna* E, lua_State* L)
{ {
typedef EventKey<Hooks::PlayerEvents> Key;
if (lua_isnoneornil(L, 1)) if (lua_isnoneornil(L, 1))
{ {
for (uint32 i = Hooks::PLAYER_EVENT_ON_CHARACTER_CREATE; i < Hooks::PLAYER_EVENT_COUNT; ++i) E->PlayerEventBindings->Clear();
E->PlayerEventBindings->Clear(i);
} }
else else
{ {
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 1); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 1);
E->PlayerEventBindings->Clear(event_type); E->PlayerEventBindings->Clear(Key((Hooks::PlayerEvents)event_type));
} }
return 0; return 0;
} }
@@ -3001,18 +2832,20 @@ namespace LuaGlobalFunctions
*/ */
int ClearPlayerGossipEvents(Eluna* E, lua_State* L) int ClearPlayerGossipEvents(Eluna* E, lua_State* L)
{ {
typedef EntryKey<Hooks::GossipEvents> Key;
if (lua_isnoneornil(L, 2)) if (lua_isnoneornil(L, 2))
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
for (uint32 i = Hooks::GOSSIP_EVENT_ON_HELLO; i < Hooks::GOSSIP_EVENT_COUNT; ++i) for (uint32 i = 1; i < Hooks::GOSSIP_EVENT_COUNT; ++i)
E->playerGossipBindings->Clear(entry, i); E->PlayerGossipBindings->Clear(Key((Hooks::GossipEvents)i, entry));
} }
else else
{ {
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1); uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2);
E->playerGossipBindings->Clear(entry, event_type); E->PlayerGossipBindings->Clear(Key((Hooks::GossipEvents)event_type, entry));
} }
return 0; return 0;
} }
@@ -3030,15 +2863,16 @@ namespace LuaGlobalFunctions
*/ */
int ClearServerEvents(Eluna* E, lua_State* L) int ClearServerEvents(Eluna* E, lua_State* L)
{ {
typedef EventKey<Hooks::ServerEvents> Key;
if (lua_isnoneornil(L, 1)) if (lua_isnoneornil(L, 1))
{ {
for (uint32 i = Hooks::SERVER_EVENT_ON_NETWORK_START; i < Hooks::SERVER_EVENT_COUNT; ++i) E->ServerEventBindings->Clear();
E->ServerEventBindings->Clear(i);
} }
else else
{ {
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 1); uint32 event_type = Eluna::CHECKVAL<uint32>(L, 1);
E->ServerEventBindings->Clear(event_type); E->ServerEventBindings->Clear(Key((Hooks::ServerEvents)event_type));
} }
return 0; return 0;
} }

137
GossipHooks.cpp Normal file
View File

@@ -0,0 +1,137 @@
/*
* Copyright (C) 2010 - 2015 Eluna Lua Engine <http://emudevs.com/>
* 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<GossipEvents>(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<GossipEvents>(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);
}

View File

@@ -4,83 +4,68 @@
* Please see the included DOCS/LICENSE.md for more information * Please see the included DOCS/LICENSE.md for more information
*/ */
#ifndef _GROUP_HOOKS_H
#define _GROUP_HOOKS_H
#include "Hooks.h" #include "Hooks.h"
#include "HookHelpers.h" #include "HookHelpers.h"
#include "LuaEngine.h" #include "LuaEngine.h"
#include "ElunaBinding.h" #include "BindingMap.h"
#include "ElunaTemplate.h" #include "ElunaTemplate.h"
using namespace Hooks; using namespace Hooks;
#define START_HOOK(EVENT) \
if (!IsEnabled())\
return;\
auto key = EventKey<GroupEvents>(EVENT);\
if (!GroupEventBindings->HasBindingsFor(key))\
return;\
LOCK_ELUNA
void Eluna::OnAddMember(Group* group, uint64 guid) void Eluna::OnAddMember(Group* group, uint64 guid)
{ {
if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_ADD)) START_HOOK(GROUP_EVENT_ON_MEMBER_ADD);
return;
LOCK_ELUNA;
Push(group); Push(group);
Push(guid); Push(guid);
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_ADD); CallAllFunctions(GroupEventBindings, key);
} }
void Eluna::OnInviteMember(Group* group, uint64 guid) void Eluna::OnInviteMember(Group* group, uint64 guid)
{ {
if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_INVITE)) START_HOOK(GROUP_EVENT_ON_MEMBER_INVITE);
return;
LOCK_ELUNA;
Push(group); Push(group);
Push(guid); Push(guid);
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_INVITE); CallAllFunctions(GroupEventBindings, key);
} }
void Eluna::OnRemoveMember(Group* group, uint64 guid, uint8 method) void Eluna::OnRemoveMember(Group* group, uint64 guid, uint8 method)
{ {
if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_REMOVE)) START_HOOK(GROUP_EVENT_ON_MEMBER_REMOVE);
return;
LOCK_ELUNA;
Push(group); Push(group);
Push(guid); Push(guid);
Push(method); Push(method);
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_REMOVE); CallAllFunctions(GroupEventBindings, key);
} }
void Eluna::OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid) void Eluna::OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid)
{ {
if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_LEADER_CHANGE)) START_HOOK(GROUP_EVENT_ON_LEADER_CHANGE);
return;
LOCK_ELUNA;
Push(group); Push(group);
Push(newLeaderGuid); Push(newLeaderGuid);
Push(oldLeaderGuid); Push(oldLeaderGuid);
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_LEADER_CHANGE); CallAllFunctions(GroupEventBindings, key);
} }
void Eluna::OnDisband(Group* group) void Eluna::OnDisband(Group* group)
{ {
if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_DISBAND)) START_HOOK(GROUP_EVENT_ON_DISBAND);
return;
LOCK_ELUNA;
Push(group); Push(group);
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_DISBAND); CallAllFunctions(GroupEventBindings, key);
} }
void Eluna::OnCreate(Group* group, uint64 leaderGuid, GroupType groupType) void Eluna::OnCreate(Group* group, uint64 leaderGuid, GroupType groupType)
{ {
if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_CREATE)) START_HOOK(GROUP_EVENT_ON_CREATE);
return;
LOCK_ELUNA;
Push(group); Push(group);
Push(leaderGuid); Push(leaderGuid);
Push(groupType); Push(groupType);
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_CREATE); CallAllFunctions(GroupEventBindings, key);
} }
#endif // _GROUP_HOOKS_H

View File

@@ -4,97 +4,81 @@
* Please see the included DOCS/LICENSE.md for more information * Please see the included DOCS/LICENSE.md for more information
*/ */
#ifndef _GUILD_HOOKS_H
#define _GUILD_HOOKS_H
#include "Hooks.h" #include "Hooks.h"
#include "HookHelpers.h" #include "HookHelpers.h"
#include "LuaEngine.h" #include "LuaEngine.h"
#include "ElunaBinding.h" #include "BindingMap.h"
#include "ElunaTemplate.h" #include "ElunaTemplate.h"
using namespace Hooks; using namespace Hooks;
#define START_HOOK(EVENT) \
if (!IsEnabled())\
return;\
auto key = EventKey<GuildEvents>(EVENT);\
if (!GuildEventBindings->HasBindingsFor(key))\
return;\
LOCK_ELUNA
void Eluna::OnAddMember(Guild* guild, Player* player, uint32 plRank) void Eluna::OnAddMember(Guild* guild, Player* player, uint32 plRank)
{ {
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_ADD_MEMBER)) START_HOOK(GUILD_EVENT_ON_ADD_MEMBER);
return;
LOCK_ELUNA;
Push(guild); Push(guild);
Push(player); Push(player);
Push(plRank); Push(plRank);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_ADD_MEMBER); CallAllFunctions(GuildEventBindings, key);
} }
void Eluna::OnRemoveMember(Guild* guild, Player* player, bool isDisbanding) void Eluna::OnRemoveMember(Guild* guild, Player* player, bool isDisbanding)
{ {
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_REMOVE_MEMBER)) START_HOOK(GUILD_EVENT_ON_REMOVE_MEMBER);
return;
LOCK_ELUNA;
Push(guild); Push(guild);
Push(player); Push(player);
Push(isDisbanding); Push(isDisbanding);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_REMOVE_MEMBER); CallAllFunctions(GuildEventBindings, key);
} }
void Eluna::OnMOTDChanged(Guild* guild, const std::string& newMotd) void Eluna::OnMOTDChanged(Guild* guild, const std::string& newMotd)
{ {
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MOTD_CHANGE)) START_HOOK(GUILD_EVENT_ON_MOTD_CHANGE);
return;
LOCK_ELUNA;
Push(guild); Push(guild);
Push(newMotd); Push(newMotd);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_MOTD_CHANGE); CallAllFunctions(GuildEventBindings, key);
} }
void Eluna::OnInfoChanged(Guild* guild, const std::string& newInfo) void Eluna::OnInfoChanged(Guild* guild, const std::string& newInfo)
{ {
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_INFO_CHANGE)) START_HOOK(GUILD_EVENT_ON_INFO_CHANGE);
return;
LOCK_ELUNA;
Push(guild); Push(guild);
Push(newInfo); Push(newInfo);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_INFO_CHANGE); CallAllFunctions(GuildEventBindings, key);
} }
void Eluna::OnCreate(Guild* guild, Player* leader, const std::string& name) void Eluna::OnCreate(Guild* guild, Player* leader, const std::string& name)
{ {
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_CREATE)) START_HOOK(GUILD_EVENT_ON_CREATE);
return;
LOCK_ELUNA;
Push(guild); Push(guild);
Push(leader); Push(leader);
Push(name); Push(name);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_CREATE); CallAllFunctions(GuildEventBindings, key);
} }
void Eluna::OnDisband(Guild* guild) void Eluna::OnDisband(Guild* guild)
{ {
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_DISBAND)) START_HOOK(GUILD_EVENT_ON_DISBAND);
return;
LOCK_ELUNA;
Push(guild); 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? 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)) START_HOOK(GUILD_EVENT_ON_MONEY_WITHDRAW);
return;
LOCK_ELUNA;
Push(guild); Push(guild);
Push(player); Push(player);
Push(amount); Push(amount);
Push(isRepair); // isRepair not a part of Mangos, implement? Push(isRepair); // isRepair not a part of Mangos, implement?
int amountIndex = lua_gettop(L) - 1; 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) 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) void Eluna::OnMemberDepositMoney(Guild* guild, Player* player, uint32& amount)
{ {
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MONEY_DEPOSIT)) START_HOOK(GUILD_EVENT_ON_MONEY_DEPOSIT);
return;
LOCK_ELUNA;
Push(guild); Push(guild);
Push(player); Push(player);
Push(amount); Push(amount);
int amountIndex = lua_gettop(L); int amountIndex = lua_gettop(L);
int n = SetupStack(GuildEventBindings, GUILD_EVENT_ON_MONEY_DEPOSIT, 3); int n = SetupStack(GuildEventBindings, key, 3);
while (n > 0) 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, void Eluna::OnItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId,
bool isDestBank, uint8 destContainer, uint8 destSlotId) bool isDestBank, uint8 destContainer, uint8 destSlotId)
{ {
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_ITEM_MOVE)) START_HOOK(GUILD_EVENT_ON_ITEM_MOVE);
return;
LOCK_ELUNA;
Push(guild); Push(guild);
Push(player); Push(player);
Push(pItem); Push(pItem);
@@ -158,29 +136,23 @@ void Eluna::OnItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank
Push(isDestBank); Push(isDestBank);
Push(destContainer); Push(destContainer);
Push(destSlotId); 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) void Eluna::OnEvent(Guild* guild, uint8 eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank)
{ {
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_EVENT)) START_HOOK(GUILD_EVENT_ON_EVENT);
return;
LOCK_ELUNA;
Push(guild); Push(guild);
Push(eventType); Push(eventType);
Push(playerGuid1); Push(playerGuid1);
Push(playerGuid2); Push(playerGuid2);
Push(newRank); 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) 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)) START_HOOK(GUILD_EVENT_ON_BANK_EVENT);
return;
LOCK_ELUNA;
Push(guild); Push(guild);
Push(eventType); Push(eventType);
Push(tabId); Push(tabId);
@@ -188,7 +160,5 @@ void Eluna::OnBankEvent(Guild* guild, uint8 eventType, uint8 tabId, uint32 playe
Push(itemOrMoney); Push(itemOrMoney);
Push(itemStackCount); Push(itemStackCount);
Push(destTabId); Push(destTabId);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_BANK_EVENT); CallAllFunctions(GuildEventBindings, key);
} }
#endif // _GUILD_HOOKS_H

View File

@@ -14,18 +14,15 @@
* Sets up the stack so that event handlers can be called. * Sets up the stack so that event handlers can be called.
* *
* Returns the number of functions that were pushed onto the stack. * 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<typename T> template<typename K1, typename K2>
int Eluna::SetupStack(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, int number_of_arguments) int Eluna::SetupStack(BindingMap<K1>* bindings1, BindingMap<K2>* 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(number_of_arguments == this->push_counter);
ASSERT(key1.event_id == key2.event_id);
// Stack: [arguments] // Stack: [arguments]
Push(event_id); Push(key1.event_id);
this->push_counter = 0; this->push_counter = 0;
++number_of_arguments; ++number_of_arguments;
// Stack: [arguments], event_id // Stack: [arguments], event_id
@@ -37,14 +34,9 @@ int Eluna::SetupStack(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings
lua_insert(L, first_argument_index); lua_insert(L, first_argument_index);
// Stack: event_id, [arguments] // Stack: event_id, [arguments]
if (event_bindings) bindings1->PushRefsFor(key1);
event_bindings->PushFuncRefs(L, (int)event_id); if (bindings2)
bindings2->PushRefsFor(key2);
if (entry_bindings)
entry_bindings->PushFuncRefs(L, (int)event_id, entry);
if (guid_bindings)
guid_bindings->PushFuncRefs(L, (int)event_id, guid, instanceId);
// Stack: event_id, [arguments], [functions] // Stack: event_id, [arguments], [functions]
int number_of_functions = lua_gettop(L) - arguments_top; 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. * Call all event handlers registered to the event ID/entry combination and ignore any results.
*/ */
template<typename T> template<typename K1, typename K2>
void Eluna::CallAllFunctions(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId) void Eluna::CallAllFunctions(BindingMap<K1>* bindings1, BindingMap<K2>* bindings2, const K1& key1, const K2& key2)
{ {
int number_of_arguments = this->push_counter; int number_of_arguments = this->push_counter;
// Stack: [arguments] // 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] // Stack: event_id, [arguments], [functions]
while (number_of_functions > 0) while (number_of_functions > 0)
@@ -96,15 +88,15 @@ void Eluna::CallAllFunctions(EventBind<T>* event_bindings, EntryBind<T>* entry_b
* and returns `default_value` if ALL event handlers returned `default_value`, * and returns `default_value` if ALL event handlers returned `default_value`,
* otherwise returns the opposite of `default_value`. * otherwise returns the opposite of `default_value`.
*/ */
template<typename T> template<typename K1, typename K2>
bool Eluna::CallAllFunctionsBool(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value) bool Eluna::CallAllFunctionsBool(BindingMap<K1>* bindings1, BindingMap<K2>* bindings2, const K1& key1, const K2& key2, bool default_value/* = false*/)
{ {
bool result = default_value; bool result = default_value;
// Note: number_of_arguments here does not count in eventID, which is pushed in SetupStack // Note: number_of_arguments here does not count in eventID, which is pushed in SetupStack
int number_of_arguments = this->push_counter; int number_of_arguments = this->push_counter;
// Stack: [arguments] // 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] // Stack: event_id, [arguments], [functions]
while (number_of_functions > 0) while (number_of_functions > 0)

View File

@@ -13,7 +13,7 @@
* A. If results will be IGNORED: * A. If results will be IGNORED:
* *
* // Return early if there are no bindings. * // Return early if there are no bindings.
* if (!WhateverBindings->HasEvents(SOME_EVENT_TYPE)) * if (!WhateverBindings->HasBindingsFor(SOME_EVENT_TYPE))
* return; * return;
* *
* // Lock out any other threads. * // Lock out any other threads.
@@ -31,7 +31,7 @@
* B. If results will be USED: * B. If results will be USED:
* *
* // Return early if there are no bindings. * // Return early if there are no bindings.
* if (!WhateverBindings->HasEvents(SOME_EVENT_TYPE)) * if (!WhateverBindings->HasBindingsFor(SOME_EVENT_TYPE))
* return; * return;
* *
* // Lock out any other threads. * // Lock out any other threads.

View File

@@ -4,41 +4,40 @@
* Please see the included DOCS/LICENSE.md for more information * Please see the included DOCS/LICENSE.md for more information
*/ */
#ifndef _ITEM_HOOKS_H
#define _ITEM_HOOKS_H
#include "Hooks.h" #include "Hooks.h"
#include "HookHelpers.h" #include "HookHelpers.h"
#include "LuaEngine.h" #include "LuaEngine.h"
#include "ElunaBinding.h" #include "BindingMap.h"
#include "ElunaIncludes.h" #include "ElunaIncludes.h"
#include "ElunaTemplate.h" #include "ElunaTemplate.h"
using namespace Hooks; using namespace Hooks;
#define START_HOOK_WITH_RETVAL(EVENT, ENTRY, RETVAL) \
if (!IsEnabled())\
return RETVAL;\
auto key = EntryKey<ItemEvents>(EVENT, ENTRY);\
if (!ItemEventBindings->HasBindingsFor(key))\
return RETVAL;\
LOCK_ELUNA
bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Item* pTarget) bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Item* pTarget)
{ {
if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry())) START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry(), false);
return false;
LOCK_ELUNA;
Push(pCaster); Push(pCaster);
Push(spellId); Push(spellId);
Push(effIndex); Push(effIndex);
Push(pTarget); 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) bool Eluna::OnQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest)
{ {
if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_QUEST_ACCEPT, pItem->GetEntry())) START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_QUEST_ACCEPT, pItem->GetEntry(), false);
return false;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pItem); Push(pItem);
Push(pQuest); 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) 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) bool Eluna::OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets)
{ {
if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_USE, pItem->GetEntry())) START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_USE, pItem->GetEntry(), true);
return true;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pItem); Push(pItem);
#ifndef TRINITY #ifndef TRINITY
@@ -105,41 +101,21 @@ bool Eluna::OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targ
Push(); Push();
#endif #endif
return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_USE, pItem->GetEntry(), true); return CallAllFunctionsBool(ItemEventBindings, key, 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);
} }
bool Eluna::OnExpire(Player* pPlayer, ItemTemplate const* pProto) bool Eluna::OnExpire(Player* pPlayer, ItemTemplate const* pProto)
{ {
if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_EXPIRE, pProto->ItemId)) START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_EXPIRE, pProto->ItemId, false);
return false;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pProto->ItemId); 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())) START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_REMOVE, pItem->GetEntry(), false);
return false;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(item); Push(pItem);
return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_REMOVE, item->GetEntry()); return CallAllFunctionsBool(ItemEventBindings, key);
} }
#endif // _ITEM_HOOKS_H

View File

@@ -6,7 +6,7 @@
#include "Hooks.h" #include "Hooks.h"
#include "LuaEngine.h" #include "LuaEngine.h"
#include "ElunaBinding.h" #include "BindingMap.h"
#include "ElunaEventMgr.h" #include "ElunaEventMgr.h"
#include "ElunaIncludes.h" #include "ElunaIncludes.h"
#include "ElunaTemplate.h" #include "ElunaTemplate.h"
@@ -151,7 +151,7 @@ GameObjectEventBindings(NULL),
GameObjectGossipBindings(NULL), GameObjectGossipBindings(NULL),
ItemEventBindings(NULL), ItemEventBindings(NULL),
ItemGossipBindings(NULL), ItemGossipBindings(NULL),
playerGossipBindings(NULL), PlayerGossipBindings(NULL),
CreatureUniqueBindings(NULL) CreatureUniqueBindings(NULL)
{ {
@@ -189,8 +189,6 @@ void Eluna::CloseLua()
void Eluna::OpenLua() void Eluna::OpenLua()
{ {
CreateBindStores();
enabled = eConfigMgr->GetBoolDefault("Eluna.Enabled", true); enabled = eConfigMgr->GetBoolDefault("Eluna.Enabled", true);
if (!IsEnabled()) if (!IsEnabled())
{ {
@@ -199,6 +197,7 @@ void Eluna::OpenLua()
} }
L = luaL_newstate(); L = luaL_newstate();
CreateBindStores();
// open base lua libraries // open base lua libraries
luaL_openlibs(L); luaL_openlibs(L);
@@ -229,23 +228,23 @@ void Eluna::CreateBindStores()
{ {
DestroyBindStores(); DestroyBindStores();
ServerEventBindings = new EventBind<Hooks::ServerEvents>("ServerEvents", *this); ServerEventBindings = new BindingMap< EventKey<Hooks::ServerEvents> >(L);
PlayerEventBindings = new EventBind<Hooks::PlayerEvents>("PlayerEvents", *this); PlayerEventBindings = new BindingMap< EventKey<Hooks::PlayerEvents> >(L);
GuildEventBindings = new EventBind<Hooks::GuildEvents>("GuildEvents", *this); GuildEventBindings = new BindingMap< EventKey<Hooks::GuildEvents> >(L);
GroupEventBindings = new EventBind<Hooks::GroupEvents>("GroupEvents", *this); GroupEventBindings = new BindingMap< EventKey<Hooks::GroupEvents> >(L);
VehicleEventBindings = new EventBind<Hooks::VehicleEvents>("VehicleEvents", *this); VehicleEventBindings = new BindingMap< EventKey<Hooks::VehicleEvents> >(L);
BGEventBindings = new EventBind<Hooks::BGEvents>("BGEvents", *this); BGEventBindings = new BindingMap< EventKey<Hooks::BGEvents> >(L);
PacketEventBindings = new EntryBind<Hooks::PacketEvents>("PacketEvents", *this); PacketEventBindings = new BindingMap< EntryKey<Hooks::PacketEvents> >(L);
CreatureEventBindings = new EntryBind<Hooks::CreatureEvents>("CreatureEvents", *this); CreatureEventBindings = new BindingMap< EntryKey<Hooks::CreatureEvents> >(L);
CreatureGossipBindings = new EntryBind<Hooks::GossipEvents>("GossipEvents (creature)", *this); CreatureGossipBindings = new BindingMap< EntryKey<Hooks::GossipEvents> >(L);
GameObjectEventBindings = new EntryBind<Hooks::GameObjectEvents>("GameObjectEvents", *this); GameObjectEventBindings = new BindingMap< EntryKey<Hooks::GameObjectEvents> >(L);
GameObjectGossipBindings = new EntryBind<Hooks::GossipEvents>("GossipEvents (gameobject)", *this); GameObjectGossipBindings = new BindingMap< EntryKey<Hooks::GossipEvents> >(L);
ItemEventBindings = new EntryBind<Hooks::ItemEvents>("ItemEvents", *this); ItemEventBindings = new BindingMap< EntryKey<Hooks::ItemEvents> >(L);
ItemGossipBindings = new EntryBind<Hooks::GossipEvents>("GossipEvents (item)", *this); ItemGossipBindings = new BindingMap< EntryKey<Hooks::GossipEvents> >(L);
playerGossipBindings = new EntryBind<Hooks::GossipEvents>("GossipEvents (player)", *this); PlayerGossipBindings = new BindingMap< EntryKey<Hooks::GossipEvents> >(L);
CreatureUniqueBindings = new UniqueBind<Hooks::CreatureEvents>("CreatureEvents (unique)", *this); CreatureUniqueBindings = new BindingMap< UniqueObjectKey<Hooks::CreatureEvents> >(L);
} }
void Eluna::DestroyBindStores() void Eluna::DestroyBindStores()
@@ -263,7 +262,7 @@ void Eluna::DestroyBindStores()
delete GameObjectGossipBindings; delete GameObjectGossipBindings;
delete ItemEventBindings; delete ItemEventBindings;
delete ItemGossipBindings; delete ItemGossipBindings;
delete playerGossipBindings; delete PlayerGossipBindings;
delete BGEventBindings; delete BGEventBindings;
delete CreatureUniqueBindings; delete CreatureUniqueBindings;
@@ -281,7 +280,7 @@ void Eluna::DestroyBindStores()
GameObjectGossipBindings = NULL; GameObjectGossipBindings = NULL;
ItemEventBindings = NULL; ItemEventBindings = NULL;
ItemGossipBindings = NULL; ItemGossipBindings = NULL;
playerGossipBindings = NULL; PlayerGossipBindings = NULL;
BGEventBindings = NULL; BGEventBindings = NULL;
CreatureUniqueBindings = 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_extensions.begin(), lua_extensions.end());
scripts.insert(scripts.end(), lua_scripts.begin(), lua_scripts.end()); scripts.insert(scripts.end(), lua_scripts.begin(), lua_scripts.end());
UNORDERED_MAP<std::string, std::string> loaded; // filename, path std::unordered_map<std::string, std::string> loaded; // filename, path
lua_getglobal(L, "package"); lua_getglobal(L, "package");
// Stack: package // Stack: package
@@ -907,333 +906,239 @@ ElunaObject* Eluna::CHECKTYPE(lua_State* luastate, int narg, const char* tname,
return *ptrHold; return *ptrHold;
} }
template<typename K>
static int cancelBinding(lua_State *L) static int cancelBinding(lua_State *L)
{ {
int ref = lua_tointeger(L, lua_upvalueindex(1)); uint64 bindingID = Eluna::CHECKVAL<uint64>(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<uint64>(L, lua_upvalueindex(4));
// This marker (initially `false`) is used to protect against calling this callback twice. BindingMap<K>* bindings = (BindingMap<K>*)lua_touserdata(L, lua_upvalueindex(2));
// After the first call, `alreadyCalled` will be `true`, so we know not to proceed. ASSERT(bindings != NULL);
bool alreadyCalled = lua_toboolean(L, lua_upvalueindex(5));
if (alreadyCalled) bindings->Remove(bindingID);
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);
return 0; return 0;
} }
static int createCancelCallback(lua_State* L, int ref, ElunaBind* bindings1, uint32 event_id, uint32 entry_id = 0, uint64 guid = 0) template<typename K>
static void createCancelCallback(lua_State* L, uint64 bindingID, BindingMap<K>* bindings)
{ {
lua_pushinteger(L, ref); Eluna::Push(L, bindingID);
lua_pushunsigned(L, event_id); lua_pushlightuserdata(L, bindings);
lua_pushunsigned(L, entry_id); // Stack: bindingID, bindings
Eluna::Push(L, guid);
lua_pushboolean(L, false);
lua_pushlightuserdata(L, bindings1);
// Stack: ref, event_id, entry_id, guid, false, bindings1
lua_pushcclosure(L, &cancelBinding, 6); lua_pushcclosure(L, &cancelBinding<K>, 2);
// Stack: cancel_callback
lua_pushvalue(L, -1);
return luaL_ref(L, LUA_REGISTRYINDEX);
// Stack: cancel_callback // Stack: cancel_callback
} }
// Saves the function reference ID given to the register type's store for given entry under the given event // 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) switch (regtype)
{ {
case Hooks::REGTYPE_SERVER: case Hooks::REGTYPE_SERVER:
if (evt < Hooks::SERVER_EVENT_COUNT) if (event_id < Hooks::SERVER_EVENT_COUNT)
{ {
if (returnCallback) auto key = EventKey<Hooks::ServerEvents>((Hooks::ServerEvents)event_id);
{ bindingID = ServerEventBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, ServerEventBindings, evt); createCancelCallback(L, bindingID, ServerEventBindings);
ServerEventBindings->Insert(evt, functionRef, shots, callbackRef); return 1; // Stack: callback
return 1; // Stack: callback
}
ServerEventBindings->Insert(evt, functionRef, shots);
return 0; // Stack: (empty)
} }
break; break;
case Hooks::REGTYPE_PLAYER: case Hooks::REGTYPE_PLAYER:
if (evt < Hooks::PLAYER_EVENT_COUNT) if (event_id < Hooks::PLAYER_EVENT_COUNT)
{ {
if (returnCallback) auto key = EventKey<Hooks::PlayerEvents>((Hooks::PlayerEvents)event_id);
{ bindingID = PlayerEventBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, PlayerEventBindings, evt); createCancelCallback(L, bindingID, PlayerEventBindings);
PlayerEventBindings->Insert(evt, functionRef, shots, callbackRef); return 1; // Stack: callback
return 1; // Stack: callback
}
PlayerEventBindings->Insert(evt, functionRef, shots);
return 0; // Stack: (empty)
} }
break; break;
case Hooks::REGTYPE_GUILD: case Hooks::REGTYPE_GUILD:
if (evt < Hooks::GUILD_EVENT_COUNT) if (event_id < Hooks::GUILD_EVENT_COUNT)
{ {
if (returnCallback) auto key = EventKey<Hooks::GuildEvents>((Hooks::GuildEvents)event_id);
{ bindingID = GuildEventBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, GuildEventBindings, evt); createCancelCallback(L, bindingID, GuildEventBindings);
GuildEventBindings->Insert(evt, functionRef, shots, callbackRef); return 1; // Stack: callback
return 1; // Stack: callback
}
GuildEventBindings->Insert(evt, functionRef, shots);
return 0; // Stack: (empty)
} }
break; break;
case Hooks::REGTYPE_GROUP: case Hooks::REGTYPE_GROUP:
if (evt < Hooks::GROUP_EVENT_COUNT) if (event_id < Hooks::GROUP_EVENT_COUNT)
{ {
if (returnCallback) auto key = EventKey<Hooks::GroupEvents>((Hooks::GroupEvents)event_id);
{ bindingID = GroupEventBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, GroupEventBindings, evt); createCancelCallback(L, bindingID, GroupEventBindings);
GroupEventBindings->Insert(evt, functionRef, shots, callbackRef); return 1; // Stack: callback
return 1; // Stack: callback
}
GroupEventBindings->Insert(evt, functionRef, shots);
return 0; // Stack: (empty)
} }
break; break;
case Hooks::REGTYPE_VEHICLE: case Hooks::REGTYPE_VEHICLE:
if (evt < Hooks::VEHICLE_EVENT_COUNT) if (event_id < Hooks::VEHICLE_EVENT_COUNT)
{ {
if (returnCallback) auto key = EventKey<Hooks::VehicleEvents>((Hooks::VehicleEvents)event_id);
{ bindingID = VehicleEventBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, VehicleEventBindings, evt); createCancelCallback(L, bindingID, VehicleEventBindings);
VehicleEventBindings->Insert(evt, functionRef, shots, callbackRef); return 1; // Stack: callback
return 1; // Stack: callback
}
VehicleEventBindings->Insert(evt, functionRef, shots);
return 0; // Stack: (empty)
} }
break; break;
case Hooks::REGTYPE_BG: case Hooks::REGTYPE_BG:
if (evt < Hooks::BG_EVENT_COUNT) if (event_id < Hooks::BG_EVENT_COUNT)
{ {
if (returnCallback) auto key = EventKey<Hooks::BGEvents>((Hooks::BGEvents)event_id);
{ bindingID = BGEventBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, BGEventBindings, evt); createCancelCallback(L, bindingID, BGEventBindings);
BGEventBindings->Insert(evt, functionRef, shots, callbackRef); return 1; // Stack: callback
return 1; // Stack: callback
}
BGEventBindings->Insert(evt, functionRef, shots);
return 0; // Stack: (empty)
} }
break; break;
case Hooks::REGTYPE_PACKET: 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_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) return 0; // Stack: (empty)
} }
if (returnCallback) auto key = EntryKey<Hooks::PacketEvents>((Hooks::PacketEvents)event_id, entry);
{ bindingID = PacketEventBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, PacketEventBindings, evt, id); createCancelCallback(L, bindingID, PacketEventBindings);
PacketEventBindings->Insert(id, evt, functionRef, shots, callbackRef); return 1; // Stack: callback
return 1; // Stack: callback
}
PacketEventBindings->Insert(id, evt, functionRef, shots);
return 0; // Stack: (empty)
} }
break; break;
case Hooks::REGTYPE_CREATURE: 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_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) return 0; // Stack: (empty)
} }
if (returnCallback) auto key = EntryKey<Hooks::CreatureEvents>((Hooks::CreatureEvents)event_id, entry);
{ bindingID = CreatureEventBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, CreatureEventBindings, evt, id); createCancelCallback(L, bindingID, CreatureEventBindings);
CreatureEventBindings->Insert(id, evt, functionRef, shots, callbackRef);
return 1; // Stack: callback
}
CreatureEventBindings->Insert(id, evt, functionRef, shots);
} }
else else
{ {
ASSERT(guid != 0); ASSERT(guid != 0);
if (returnCallback) auto key = UniqueObjectKey<Hooks::CreatureEvents>((Hooks::CreatureEvents)event_id, guid, instanceId);
{ bindingID = CreatureUniqueBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, CreatureUniqueBindings, evt, instanceId, guid); createCancelCallback(L, bindingID, CreatureUniqueBindings);
CreatureUniqueBindings->Insert(guid, instanceId, evt, functionRef, shots, callbackRef);
return 1; // Stack: callback
}
CreatureUniqueBindings->Insert(guid, instanceId, evt, functionRef, shots);
} }
return 1; // Stack: callback
return 0; // Stack: (empty)
} }
break; break;
case Hooks::REGTYPE_CREATURE_GOSSIP: 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_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) return 0; // Stack: (empty)
} }
if (returnCallback) auto key = EntryKey<Hooks::GossipEvents>((Hooks::GossipEvents)event_id, entry);
{ bindingID = CreatureGossipBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, CreatureGossipBindings, evt, id); createCancelCallback(L, bindingID, CreatureGossipBindings);
CreatureGossipBindings->Insert(id, evt, functionRef, shots, callbackRef); return 1; // Stack: callback
return 1; // Stack: callback
}
CreatureGossipBindings->Insert(id, evt, functionRef, shots);
return 0; // Stack: (empty)
} }
break; break;
case Hooks::REGTYPE_GAMEOBJECT: 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_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) return 0; // Stack: (empty)
} }
if (returnCallback) auto key = EntryKey<Hooks::GameObjectEvents>((Hooks::GameObjectEvents)event_id, entry);
{ bindingID = GameObjectEventBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, GameObjectEventBindings, evt, id); createCancelCallback(L, bindingID, GameObjectEventBindings);
GameObjectEventBindings->Insert(id, evt, functionRef, shots, callbackRef); return 1; // Stack: callback
return 1; // Stack: callback
}
GameObjectEventBindings->Insert(id, evt, functionRef, shots);
return 0; // Stack: (empty)
} }
break; break;
case Hooks::REGTYPE_GAMEOBJECT_GOSSIP: 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_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) return 0; // Stack: (empty)
} }
if (returnCallback) auto key = EntryKey<Hooks::GossipEvents>((Hooks::GossipEvents)event_id, entry);
{ bindingID = GameObjectGossipBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, GameObjectGossipBindings, evt, id); createCancelCallback(L, bindingID, GameObjectGossipBindings);
GameObjectGossipBindings->Insert(id, evt, functionRef, shots, callbackRef); return 1; // Stack: callback
return 1; // Stack: callback
}
GameObjectGossipBindings->Insert(id, evt, functionRef, shots);
return 0; // Stack: (empty)
} }
break; break;
case Hooks::REGTYPE_ITEM: 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_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) return 0; // Stack: (empty)
} }
if (returnCallback) auto key = EntryKey<Hooks::ItemEvents>((Hooks::ItemEvents)event_id, entry);
{ bindingID = ItemEventBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, ItemEventBindings, evt, id); createCancelCallback(L, bindingID, ItemEventBindings);
ItemEventBindings->Insert(id, evt, functionRef, shots, callbackRef); return 1; // Stack: callback
return 1; // Stack: callback
}
ItemEventBindings->Insert(id, evt, functionRef, shots);
return 0; // Stack: (empty)
} }
break; break;
case Hooks::REGTYPE_ITEM_GOSSIP: 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_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) return 0; // Stack: (empty)
} }
if (returnCallback) auto key = EntryKey<Hooks::GossipEvents>((Hooks::GossipEvents)event_id, entry);
{ bindingID = ItemGossipBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, ItemGossipBindings, evt, id); createCancelCallback(L, bindingID, ItemGossipBindings);
ItemGossipBindings->Insert(id, evt, functionRef, shots, callbackRef); return 1; // Stack: callback
return 1; // Stack: callback
}
ItemGossipBindings->Insert(id, evt, functionRef, shots);
return 0; // Stack: (empty)
} }
break; break;
case Hooks::REGTYPE_PLAYER_GOSSIP: case Hooks::REGTYPE_PLAYER_GOSSIP:
if (evt < Hooks::GOSSIP_EVENT_COUNT) if (event_id < Hooks::GOSSIP_EVENT_COUNT)
{ {
if (returnCallback) auto key = EntryKey<Hooks::GossipEvents>((Hooks::GossipEvents)event_id, entry);
{ bindingID = PlayerGossipBindings->Insert(key, functionRef, shots);
int callbackRef = createCancelCallback(L, functionRef, playerGossipBindings, evt, id); createCancelCallback(L, bindingID, PlayerGossipBindings);
playerGossipBindings->Insert(id, evt, functionRef, shots, callbackRef); return 1; // Stack: callback
return 1; // Stack: callback
}
playerGossipBindings->Insert(id, evt, functionRef, shots);
return 0; // Stack: (empty)
} }
break; break;
} }
luaL_unref(L, LUA_REGISTRYINDEX, functionRef); 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; return 0;
} }
@@ -1283,9 +1188,20 @@ int Eluna::CallOneFunction(int number_of_functions, int number_of_arguments, int
CreatureAI* Eluna::GetAI(Creature* creature) CreatureAI* Eluna::GetAI(Creature* creature)
{ {
if (CreatureEventBindings->HasEvents(creature->GetEntry()) || if (!IsEnabled())
CreatureUniqueBindings->HasEvents(creature->GET_GUID(), creature->GetInstanceId())) return NULL;
return new ElunaCreatureAI(creature);
for (int i = 1; i < Hooks::CREATURE_EVENT_COUNT; ++i)
{
Hooks::CreatureEvents event_id = (Hooks::CreatureEvents)i;
auto entryKey = EntryKey<Hooks::CreatureEvents>(event_id, creature->GetEntry());
auto uniqueKey = UniqueObjectKey<Hooks::CreatureEvents>(event_id, creature->GET_GUID(), creature->GetInstanceId());
if (CreatureEventBindings->HasBindingsFor(entryKey) ||
CreatureUniqueBindings->HasBindingsFor(uniqueKey))
return new ElunaCreatureAI(creature);
}
return NULL; return NULL;
} }

View File

@@ -86,14 +86,12 @@ typedef VehicleInfo Vehicle;
struct lua_State; struct lua_State;
class EventMgr; class EventMgr;
class ElunaObject; class ElunaObject;
template<typename T> template<typename T> class ElunaTemplate;
class ElunaTemplate;
template<typename T> template<typename K> class BindingMap;
class EventBind; template<typename T> struct EventKey;
template<typename T> template<typename T> struct EntryKey;
class EntryBind; template<typename T> struct UniqueObjectKey;
template<typename T>
class UniqueBind;
struct LuaScript struct LuaScript
{ {
@@ -164,53 +162,26 @@ private:
// Some helpers for hooks to call event handlers. // 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". // The bodies of the templates are in HookHelpers.h, so if you want to use them you need to #include "HookHelpers.h".
template<typename T> int SetupStack(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, int number_of_arguments); template<typename K1, typename K2> int SetupStack(BindingMap<K1>* bindings1, BindingMap<K2>* 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); int CallOneFunction(int number_of_functions, int number_of_arguments, int number_of_results);
void CleanUpStack(int number_of_arguments); void CleanUpStack(int number_of_arguments);
template<typename T> void ReplaceArgument(T value, uint8 index); template<typename T> void ReplaceArgument(T value, uint8 index);
template<typename T> void CallAllFunctions(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId); template<typename K1, typename K2> void CallAllFunctions(BindingMap<K1>* bindings1, BindingMap<K2>* bindings2, const K1& key1, const K2& key2);
template<typename T> bool CallAllFunctionsBool(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value); template<typename K1, typename K2> bool CallAllFunctionsBool(BindingMap<K1>* bindings1, BindingMap<K2>* bindings2, const K1& key1, const K2& key2, bool default_value = false);
// Convenient overloads for Setup. Use these in hooks instead of original. // Same as above but for only one binding instead of two.
template<typename T> int SetupStack(EventBind<T>* event_bindings, T event_id, int number_of_arguments) // `key` is passed twice because there's no NULL for references, but it's not actually used if `bindings2` is NULL.
template<typename K> int SetupStack(BindingMap<K>* bindings, const K& key, int number_of_arguments)
{ {
return SetupStack(event_bindings, (EntryBind<T>*)NULL, (UniqueBind<T>*)NULL, event_id, 0, 0, 0, number_of_arguments); return SetupStack<K, K>(bindings, NULL, key, key, number_of_arguments);
} }
template<typename T> int SetupStack(EntryBind<T>* entry_bindings, T event_id, uint32 entry, int number_of_arguments) template<typename K> void CallAllFunctions(BindingMap<K>* bindings, const K& key)
{ {
return SetupStack((EventBind<T>*)NULL, entry_bindings, (UniqueBind<T>*)NULL, event_id, entry, 0, 0, number_of_arguments); CallAllFunctions<K, K>(bindings, NULL, key, key);
} }
template<typename T> int SetupStack(EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, int number_of_arguments) template<typename K> bool CallAllFunctionsBool(BindingMap<K>* bindings, const K& key, bool default_value = false)
{ {
return SetupStack((EventBind<T>*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments); return CallAllFunctionsBool<K, K>(bindings, NULL, key, key, default_value);
}
// Convenient overloads for CallAllFunctions. Use these in hooks instead of original.
template<typename T> void CallAllFunctions(EventBind<T>* event_bindings, T event_id)
{
CallAllFunctions(event_bindings, (EntryBind<T>*)NULL, (UniqueBind<T>*)NULL, event_id, 0, 0, 0);
}
template<typename T> void CallAllFunctions(EntryBind<T>* entry_bindings, T event_id, uint32 entry)
{
CallAllFunctions((EventBind<T>*)NULL, entry_bindings, (UniqueBind<T>*)NULL, event_id, entry, 0, 0);
}
template<typename T> void CallAllFunctions(EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId)
{
CallAllFunctions((EventBind<T>*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId);
}
// Convenient overloads for CallAllFunctionsBool. Use these in hooks instead of original.
template<typename T> bool CallAllFunctionsBool(EventBind<T>* event_bindings, T event_id, bool default_value = false)
{
return CallAllFunctionsBool(event_bindings, (EntryBind<T>*)NULL, (UniqueBind<T>*)NULL, event_id, 0, 0, 0, default_value);
}
template<typename T> bool CallAllFunctionsBool(EntryBind<T>* entry_bindings, T event_id, uint32 entry, bool default_value = false)
{
return CallAllFunctionsBool((EventBind<T>*)NULL, entry_bindings, (UniqueBind<T>*)NULL, event_id, entry, 0, 0, default_value);
}
template<typename T> bool CallAllFunctionsBool(EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value = false)
{
return CallAllFunctionsBool((EventBind<T>*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, default_value);
} }
public: public:
@@ -219,23 +190,23 @@ public:
lua_State* L; lua_State* L;
EventMgr* eventMgr; EventMgr* eventMgr;
EventBind<Hooks::ServerEvents>* ServerEventBindings; BindingMap< EventKey<Hooks::ServerEvents> >* ServerEventBindings;
EventBind<Hooks::PlayerEvents>* PlayerEventBindings; BindingMap< EventKey<Hooks::PlayerEvents> >* PlayerEventBindings;
EventBind<Hooks::GuildEvents>* GuildEventBindings; BindingMap< EventKey<Hooks::GuildEvents> >* GuildEventBindings;
EventBind<Hooks::GroupEvents>* GroupEventBindings; BindingMap< EventKey<Hooks::GroupEvents> >* GroupEventBindings;
EventBind<Hooks::VehicleEvents>* VehicleEventBindings; BindingMap< EventKey<Hooks::VehicleEvents> >* VehicleEventBindings;
EventBind<Hooks::BGEvents>* BGEventBindings; BindingMap< EventKey<Hooks::BGEvents> >* BGEventBindings;
EntryBind<Hooks::PacketEvents>* PacketEventBindings; BindingMap< EntryKey<Hooks::PacketEvents> >* PacketEventBindings;
EntryBind<Hooks::CreatureEvents>* CreatureEventBindings; BindingMap< EntryKey<Hooks::CreatureEvents> >* CreatureEventBindings;
EntryBind<Hooks::GossipEvents>* CreatureGossipBindings; BindingMap< EntryKey<Hooks::GossipEvents> >* CreatureGossipBindings;
EntryBind<Hooks::GameObjectEvents>* GameObjectEventBindings; BindingMap< EntryKey<Hooks::GameObjectEvents> >* GameObjectEventBindings;
EntryBind<Hooks::GossipEvents>* GameObjectGossipBindings; BindingMap< EntryKey<Hooks::GossipEvents> >* GameObjectGossipBindings;
EntryBind<Hooks::ItemEvents>* ItemEventBindings; BindingMap< EntryKey<Hooks::ItemEvents> >* ItemEventBindings;
EntryBind<Hooks::GossipEvents>* ItemGossipBindings; BindingMap< EntryKey<Hooks::GossipEvents> >* ItemGossipBindings;
EntryBind<Hooks::GossipEvents>* playerGossipBindings; BindingMap< EntryKey<Hooks::GossipEvents> >* PlayerGossipBindings;
UniqueBind<Hooks::CreatureEvents>* CreatureUniqueBindings; BindingMap< UniqueObjectKey<Hooks::CreatureEvents> >* CreatureUniqueBindings;
static void Initialize(); static void Initialize();
static void Uninitialize(); static void Uninitialize();
@@ -272,7 +243,7 @@ public:
bool ShouldReload() const { return reload; } bool ShouldReload() const { return reload; }
bool IsEnabled() const { return enabled && IsInitialized(); } bool IsEnabled() const { return enabled && IsInitialized(); }
bool HasLuaState() const { return L != NULL; } 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. // Non-static pushes, to be used in hooks.
// These just call the correct static version with the main thread's Lua state. // These just call the correct static version with the main thread's Lua state.

147
PacketHooks.cpp Normal file
View File

@@ -0,0 +1,147 @@
/*
* Copyright (C) 2010 - 2015 Eluna Lua Engine <http://emudevs.com/>
* 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<ServerEvents>(EVENT);\
if (!ServerEventBindings->HasBindingsFor(key))\
return;\
LOCK_ELUNA
#define START_HOOK_PACKET(EVENT, OPCODE) \
if (!IsEnabled())\
return;\
auto key = EntryKey<PacketEvents>(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<WorldPacket>(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<WorldPacket>(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<WorldPacket>(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<WorldPacket>(L, r + 1, false))
packet = *data;
lua_pop(L, 2);
}
CleanUpStack(2);
}

View File

@@ -4,69 +4,39 @@
* Please see the included DOCS/LICENSE.md for more information * Please see the included DOCS/LICENSE.md for more information
*/ */
#ifndef _PLAYER_HOOKS_H
#define _PLAYER_HOOKS_H
#include "Hooks.h" #include "Hooks.h"
#include "HookHelpers.h" #include "HookHelpers.h"
#include "LuaEngine.h" #include "LuaEngine.h"
#include "ElunaBinding.h" #include "BindingMap.h"
#include "ElunaIncludes.h" #include "ElunaIncludes.h"
#include "ElunaTemplate.h" #include "ElunaTemplate.h"
using namespace Hooks; using namespace Hooks;
#define START_HOOK(EVENT) \
if (!IsEnabled())\
return;\
auto key = EventKey<PlayerEvents>(EVENT);\
if (!PlayerEventBindings->HasBindingsFor(key))\
return;\
LOCK_ELUNA
#define START_HOOK_WITH_RETVAL(EVENT, RETVAL) \
if (!IsEnabled())\
return RETVAL;\
auto key = EventKey<PlayerEvents>(EVENT);\
if (!PlayerEventBindings->HasBindingsFor(key))\
return RETVAL;\
LOCK_ELUNA
void Eluna::OnLearnTalents(Player* pPlayer, uint32 talentId, uint32 talentRank, uint32 spellid) void Eluna::OnLearnTalents(Player* pPlayer, uint32 talentId, uint32 talentRank, uint32 spellid)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LEARN_TALENTS)) START_HOOK(PLAYER_EVENT_ON_LEARN_TALENTS);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(talentId); Push(talentId);
Push(talentRank); Push(talentRank);
Push(spellid); Push(spellid);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEARN_TALENTS); CallAllFunctions(PlayerEventBindings, key);
}
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);
} }
// Player // Player
@@ -95,103 +65,76 @@ bool Eluna::OnCommand(Player* player, const char* text)
} }
} }
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_COMMAND)) START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_COMMAND, true);
return true;
LOCK_ELUNA;
Push(player); Push(player);
Push(fullcmd); 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) void Eluna::OnLootItem(Player* pPlayer, Item* pItem, uint32 count, uint64 guid)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOOT_ITEM)) START_HOOK(PLAYER_EVENT_ON_LOOT_ITEM);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pItem); Push(pItem);
Push(count); Push(count);
Push(guid); Push(guid);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_ITEM); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnLootMoney(Player* pPlayer, uint32 amount) void Eluna::OnLootMoney(Player* pPlayer, uint32 amount)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOOT_MONEY)) START_HOOK(PLAYER_EVENT_ON_LOOT_MONEY);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(amount); Push(amount);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_MONEY); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnFirstLogin(Player* pPlayer) void Eluna::OnFirstLogin(Player* pPlayer)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_FIRST_LOGIN)) START_HOOK(PLAYER_EVENT_ON_FIRST_LOGIN);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_FIRST_LOGIN); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnRepop(Player* pPlayer) void Eluna::OnRepop(Player* pPlayer)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_REPOP)) START_HOOK(PLAYER_EVENT_ON_REPOP);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_REPOP); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnResurrect(Player* pPlayer) void Eluna::OnResurrect(Player* pPlayer)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_RESURRECT)) START_HOOK(PLAYER_EVENT_ON_RESURRECT);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_RESURRECT); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnQuestAbandon(Player* pPlayer, uint32 questId) void Eluna::OnQuestAbandon(Player* pPlayer, uint32 questId)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_QUEST_ABANDON)) START_HOOK(PLAYER_EVENT_ON_QUEST_ABANDON);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(questId); Push(questId);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_QUEST_ABANDON); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnEquip(Player* pPlayer, Item* pItem, uint8 bag, uint8 slot) void Eluna::OnEquip(Player* pPlayer, Item* pItem, uint8 bag, uint8 slot)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_EQUIP)) START_HOOK(PLAYER_EVENT_ON_EQUIP);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pItem); Push(pItem);
Push(bag); Push(bag);
Push(slot); Push(slot);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_EQUIP); CallAllFunctions(PlayerEventBindings, key);
} }
InventoryResult Eluna::OnCanUseItem(const Player* pPlayer, uint32 itemEntry) InventoryResult Eluna::OnCanUseItem(const Player* pPlayer, uint32 itemEntry)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CAN_USE_ITEM)) START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_CAN_USE_ITEM, EQUIP_ERR_OK);
return EQUIP_ERR_OK;
LOCK_ELUNA;
InventoryResult result = EQUIP_ERR_OK; InventoryResult result = EQUIP_ERR_OK;
Push(pPlayer); Push(pPlayer);
Push(itemEntry); Push(itemEntry);
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CAN_USE_ITEM, 2); int n = SetupStack(PlayerEventBindings, key, 2);
while (n > 0) while (n > 0)
{ {
@@ -208,101 +151,74 @@ InventoryResult Eluna::OnCanUseItem(const Player* pPlayer, uint32 itemEntry)
} }
void Eluna::OnPlayerEnterCombat(Player* pPlayer, Unit* pEnemy) void Eluna::OnPlayerEnterCombat(Player* pPlayer, Unit* pEnemy)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_ENTER_COMBAT)) START_HOOK(PLAYER_EVENT_ON_ENTER_COMBAT);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pEnemy); Push(pEnemy);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_ENTER_COMBAT); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnPlayerLeaveCombat(Player* pPlayer) void Eluna::OnPlayerLeaveCombat(Player* pPlayer)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LEAVE_COMBAT)) START_HOOK(PLAYER_EVENT_ON_LEAVE_COMBAT);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEAVE_COMBAT); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnPVPKill(Player* pKiller, Player* pKilled) void Eluna::OnPVPKill(Player* pKiller, Player* pKilled)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILL_PLAYER)) START_HOOK(PLAYER_EVENT_ON_KILL_PLAYER);
return;
LOCK_ELUNA;
Push(pKiller); Push(pKiller);
Push(pKilled); Push(pKilled);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILL_PLAYER); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnCreatureKill(Player* pKiller, Creature* pKilled) void Eluna::OnCreatureKill(Player* pKiller, Creature* pKilled)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILL_CREATURE)) START_HOOK(PLAYER_EVENT_ON_KILL_CREATURE);
return;
LOCK_ELUNA;
Push(pKiller); Push(pKiller);
Push(pKilled); Push(pKilled);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILL_CREATURE); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnPlayerKilledByCreature(Creature* pKiller, Player* pKilled) void Eluna::OnPlayerKilledByCreature(Creature* pKiller, Player* pKilled)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILLED_BY_CREATURE)) START_HOOK(PLAYER_EVENT_ON_KILLED_BY_CREATURE);
return;
LOCK_ELUNA;
Push(pKiller); Push(pKiller);
Push(pKilled); Push(pKilled);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILLED_BY_CREATURE); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnLevelChanged(Player* pPlayer, uint8 oldLevel) void Eluna::OnLevelChanged(Player* pPlayer, uint8 oldLevel)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LEVEL_CHANGE)) START_HOOK(PLAYER_EVENT_ON_LEVEL_CHANGE);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(oldLevel); Push(oldLevel);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEVEL_CHANGE); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnFreeTalentPointsChanged(Player* pPlayer, uint32 newPoints) void Eluna::OnFreeTalentPointsChanged(Player* pPlayer, uint32 newPoints)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TALENTS_CHANGE)) START_HOOK(PLAYER_EVENT_ON_TALENTS_CHANGE);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(newPoints); Push(newPoints);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_CHANGE); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnTalentsReset(Player* pPlayer, bool noCost) void Eluna::OnTalentsReset(Player* pPlayer, bool noCost)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TALENTS_RESET)) START_HOOK(PLAYER_EVENT_ON_TALENTS_RESET);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(noCost); Push(noCost);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_RESET); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnMoneyChanged(Player* pPlayer, int32& amount) void Eluna::OnMoneyChanged(Player* pPlayer, int32& amount)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_MONEY_CHANGE)) START_HOOK(PLAYER_EVENT_ON_MONEY_CHANGE);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(amount); Push(amount);
int amountIndex = lua_gettop(L); int amountIndex = lua_gettop(L);
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_MONEY_CHANGE, 2); int n = SetupStack(PlayerEventBindings, key, 2);
while (n > 0) while (n > 0)
{ {
@@ -323,15 +239,12 @@ void Eluna::OnMoneyChanged(Player* pPlayer, int32& amount)
void Eluna::OnGiveXP(Player* pPlayer, uint32& amount, Unit* pVictim) void Eluna::OnGiveXP(Player* pPlayer, uint32& amount, Unit* pVictim)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GIVE_XP)) START_HOOK(PLAYER_EVENT_ON_GIVE_XP);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(amount); Push(amount);
Push(pVictim); Push(pVictim);
int amountIndex = lua_gettop(L) - 1; 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) 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) void Eluna::OnReputationChange(Player* pPlayer, uint32 factionID, int32& standing, bool incremental)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_REPUTATION_CHANGE)) START_HOOK(PLAYER_EVENT_ON_REPUTATION_CHANGE);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(factionID); Push(factionID);
Push(standing); Push(standing);
Push(incremental); Push(incremental);
int standingIndex = lua_gettop(L) - 1; 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) while (n > 0)
{ {
@@ -382,183 +292,115 @@ void Eluna::OnReputationChange(Player* pPlayer, uint32 factionID, int32& standin
void Eluna::OnDuelRequest(Player* pTarget, Player* pChallenger) void Eluna::OnDuelRequest(Player* pTarget, Player* pChallenger)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_REQUEST)) START_HOOK(PLAYER_EVENT_ON_DUEL_REQUEST);
return;
LOCK_ELUNA;
Push(pTarget); Push(pTarget);
Push(pChallenger); Push(pChallenger);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_REQUEST); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnDuelStart(Player* pStarter, Player* pChallenger) void Eluna::OnDuelStart(Player* pStarter, Player* pChallenger)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_START)) START_HOOK(PLAYER_EVENT_ON_DUEL_START);
return;
LOCK_ELUNA;
Push(pStarter); Push(pStarter);
Push(pChallenger); Push(pChallenger);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_START); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnDuelEnd(Player* pWinner, Player* pLoser, DuelCompleteType type) void Eluna::OnDuelEnd(Player* pWinner, Player* pLoser, DuelCompleteType type)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_END)) START_HOOK(PLAYER_EVENT_ON_DUEL_END);
return;
LOCK_ELUNA;
Push(pWinner); Push(pWinner);
Push(pLoser); Push(pLoser);
Push(type); Push(type);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_END); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnEmote(Player* pPlayer, uint32 emote) void Eluna::OnEmote(Player* pPlayer, uint32 emote)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_EMOTE)) START_HOOK(PLAYER_EVENT_ON_EMOTE);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(emote); Push(emote);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_EMOTE); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnTextEmote(Player* pPlayer, uint32 textEmote, uint32 emoteNum, uint64 guid) void Eluna::OnTextEmote(Player* pPlayer, uint32 textEmote, uint32 emoteNum, uint64 guid)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TEXT_EMOTE)) START_HOOK(PLAYER_EVENT_ON_TEXT_EMOTE);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(textEmote); Push(textEmote);
Push(emoteNum); Push(emoteNum);
Push(guid); Push(guid);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TEXT_EMOTE); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnSpellCast(Player* pPlayer, Spell* pSpell, bool skipCheck) void Eluna::OnSpellCast(Player* pPlayer, Spell* pSpell, bool skipCheck)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_SPELL_CAST)) START_HOOK(PLAYER_EVENT_ON_SPELL_CAST);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pSpell); Push(pSpell);
Push(skipCheck); Push(skipCheck);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_SPELL_CAST); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnLogin(Player* pPlayer) void Eluna::OnLogin(Player* pPlayer)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOGIN)) START_HOOK(PLAYER_EVENT_ON_LOGIN);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOGIN); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnLogout(Player* pPlayer) void Eluna::OnLogout(Player* pPlayer)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOGOUT)) START_HOOK(PLAYER_EVENT_ON_LOGOUT);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOGOUT); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnCreate(Player* pPlayer) void Eluna::OnCreate(Player* pPlayer)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHARACTER_CREATE)) START_HOOK(PLAYER_EVENT_ON_CHARACTER_CREATE);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_CREATE); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnDelete(uint32 guidlow) void Eluna::OnDelete(uint32 guidlow)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHARACTER_DELETE)) START_HOOK(PLAYER_EVENT_ON_CHARACTER_DELETE);
return;
LOCK_ELUNA;
Push(guidlow); Push(guidlow);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_DELETE); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnSave(Player* pPlayer) void Eluna::OnSave(Player* pPlayer)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_SAVE)) START_HOOK(PLAYER_EVENT_ON_SAVE);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_SAVE); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnBindToInstance(Player* pPlayer, Difficulty difficulty, uint32 mapid, bool permanent) void Eluna::OnBindToInstance(Player* pPlayer, Difficulty difficulty, uint32 mapid, bool permanent)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_BIND_TO_INSTANCE)) START_HOOK(PLAYER_EVENT_ON_BIND_TO_INSTANCE);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(difficulty); Push(difficulty);
Push(mapid); Push(mapid);
Push(permanent); Push(permanent);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_BIND_TO_INSTANCE); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnUpdateZone(Player* pPlayer, uint32 newZone, uint32 newArea) void Eluna::OnUpdateZone(Player* pPlayer, uint32 newZone, uint32 newArea)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_UPDATE_ZONE)) START_HOOK(PLAYER_EVENT_ON_UPDATE_ZONE);
return;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(newZone); Push(newZone);
Push(newArea); Push(newArea);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_UPDATE_ZONE); CallAllFunctions(PlayerEventBindings, key);
} }
void Eluna::OnMapChanged(Player* player) void Eluna::OnMapChanged(Player* player)
{ {
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_MAP_CHANGE)) START_HOOK(PLAYER_EVENT_ON_MAP_CHANGE);
return;
LOCK_ELUNA;
Push(player); Push(player);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_MAP_CHANGE); CallAllFunctions(PlayerEventBindings, key);
}
// 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);
} }
bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg) 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) if (lang == LANG_ADDON)
return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, NULL); return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, NULL);
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHAT)) START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_CHAT, true);
return true;
LOCK_ELUNA;
bool result = true; bool result = true;
Push(pPlayer); Push(pPlayer);
Push(msg); Push(msg);
Push(type); Push(type);
Push(lang); Push(lang);
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CHAT, 4); int n = SetupStack(PlayerEventBindings, key, 4);
while (n > 0) while (n > 0)
{ {
@@ -599,17 +438,14 @@ bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg,
if (lang == LANG_ADDON) if (lang == LANG_ADDON)
return OnAddonMessage(pPlayer, type, msg, NULL, NULL, pGroup, NULL); return OnAddonMessage(pPlayer, type, msg, NULL, NULL, pGroup, NULL);
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GROUP_CHAT)) START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_GROUP_CHAT, true);
return true;
LOCK_ELUNA;
bool result = true; bool result = true;
Push(pPlayer); Push(pPlayer);
Push(msg); Push(msg);
Push(type); Push(type);
Push(lang); Push(lang);
Push(pGroup); Push(pGroup);
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GROUP_CHAT, 5); int n = SetupStack(PlayerEventBindings, key, 5);
while (n > 0) while (n > 0)
{ {
@@ -633,17 +469,14 @@ bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg,
if (lang == LANG_ADDON) if (lang == LANG_ADDON)
return OnAddonMessage(pPlayer, type, msg, NULL, pGuild, NULL, NULL); return OnAddonMessage(pPlayer, type, msg, NULL, pGuild, NULL, NULL);
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GUILD_CHAT)) START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_GUILD_CHAT, true);
return true;
LOCK_ELUNA;
bool result = true; bool result = true;
Push(pPlayer); Push(pPlayer);
Push(msg); Push(msg);
Push(type); Push(type);
Push(lang); Push(lang);
Push(pGuild); Push(pGuild);
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GUILD_CHAT, 5); int n = SetupStack(PlayerEventBindings, key, 5);
while (n > 0) while (n > 0)
{ {
@@ -667,17 +500,14 @@ bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg,
if (lang == LANG_ADDON) if (lang == LANG_ADDON)
return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, pChannel); return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, pChannel);
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHANNEL_CHAT)) START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_CHANNEL_CHAT, true);
return true;
LOCK_ELUNA;
bool result = true; bool result = true;
Push(pPlayer); Push(pPlayer);
Push(msg); Push(msg);
Push(type); Push(type);
Push(lang); Push(lang);
Push(pChannel->GetChannelId()); Push(pChannel->GetChannelId());
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CHANNEL_CHAT, 5); int n = SetupStack(PlayerEventBindings, key, 5);
while (n > 0) while (n > 0)
{ {
@@ -701,17 +531,14 @@ bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg,
if (lang == LANG_ADDON) if (lang == LANG_ADDON)
return OnAddonMessage(pPlayer, type, msg, pReceiver, NULL, NULL, NULL); return OnAddonMessage(pPlayer, type, msg, pReceiver, NULL, NULL, NULL);
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_WHISPER)) START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_WHISPER, true);
return true;
LOCK_ELUNA;
bool result = true; bool result = true;
Push(pPlayer); Push(pPlayer);
Push(msg); Push(msg);
Push(type); Push(type);
Push(lang); Push(lang);
Push(pReceiver); Push(pReceiver);
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_WHISPER, 5); int n = SetupStack(PlayerEventBindings, key, 5);
while (n > 0) while (n > 0)
{ {
@@ -729,5 +556,3 @@ bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg,
CleanUpStack(5); CleanUpStack(5);
return result; return result;
} }
#endif // _PLAYER_HOOKS_H

View File

@@ -4,19 +4,54 @@
* Please see the included DOCS/LICENSE.md for more information * Please see the included DOCS/LICENSE.md for more information
*/ */
#ifndef _SERVER_HOOKS_H
#define _SERVER_HOOKS_H
#include "Hooks.h" #include "Hooks.h"
#include "HookHelpers.h" #include "HookHelpers.h"
#include "LuaEngine.h" #include "LuaEngine.h"
#include "ElunaBinding.h" #include "BindingMap.h"
#include "ElunaEventMgr.h" #include "ElunaEventMgr.h"
#include "ElunaIncludes.h" #include "ElunaIncludes.h"
#include "ElunaTemplate.h" #include "ElunaTemplate.h"
using namespace Hooks; using namespace Hooks;
#define START_HOOK(EVENT) \
if (!IsEnabled())\
return;\
auto key = EventKey<ServerEvents>(EVENT);\
if (!ServerEventBindings->HasBindingsFor(key))\
return;\
LOCK_ELUNA
#define START_HOOK_WITH_RETVAL(EVENT, RETVAL) \
if (!IsEnabled())\
return RETVAL;\
auto key = EventKey<ServerEvents>(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) void Eluna::OnTimedEvent(int funcRef, uint32 delay, uint32 calls, WorldObject* obj)
{ {
LOCK_ELUNA; LOCK_ELUNA;
@@ -40,53 +75,38 @@ void Eluna::OnTimedEvent(int funcRef, uint32 delay, uint32 calls, WorldObject* o
void Eluna::OnLuaStateClose() void Eluna::OnLuaStateClose()
{ {
if (!ServerEventBindings->HasEvents(ELUNA_EVENT_ON_LUA_STATE_CLOSE)) START_HOOK(ELUNA_EVENT_ON_LUA_STATE_CLOSE);
return; CallAllFunctions(ServerEventBindings, key);
LOCK_ELUNA;
CallAllFunctions(ServerEventBindings, ELUNA_EVENT_ON_LUA_STATE_CLOSE);
} }
void Eluna::OnLuaStateOpen() void Eluna::OnLuaStateOpen()
{ {
if (!ServerEventBindings->HasEvents(ELUNA_EVENT_ON_LUA_STATE_OPEN)) START_HOOK(ELUNA_EVENT_ON_LUA_STATE_OPEN);
return; CallAllFunctions(ServerEventBindings, key);
LOCK_ELUNA;
CallAllFunctions(ServerEventBindings, ELUNA_EVENT_ON_LUA_STATE_OPEN);
} }
// areatrigger // areatrigger
bool Eluna::OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* pTrigger) bool Eluna::OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* pTrigger)
{ {
if (!ServerEventBindings->HasEvents(TRIGGER_EVENT_ON_TRIGGER)) START_HOOK_WITH_RETVAL(TRIGGER_EVENT_ON_TRIGGER, false);
return false;
LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pTrigger->id); Push(pTrigger->id);
return CallAllFunctionsBool(ServerEventBindings, TRIGGER_EVENT_ON_TRIGGER); return CallAllFunctionsBool(ServerEventBindings, key);
} }
// weather // weather
void Eluna::OnChange(Weather* weather, uint32 zone, WeatherState state, float grade) void Eluna::OnChange(Weather* weather, uint32 zone, WeatherState state, float grade)
{ {
if (!ServerEventBindings->HasEvents(WEATHER_EVENT_ON_CHANGE)) START_HOOK(WEATHER_EVENT_ON_CHANGE);
return;
LOCK_ELUNA;
Push(zone); Push(zone);
Push(state); Push(state);
Push(grade); Push(grade);
CallAllFunctions(ServerEventBindings, WEATHER_EVENT_ON_CHANGE); CallAllFunctions(ServerEventBindings, key);
} }
// Auction House // Auction House
void Eluna::OnAdd(AuctionHouseObject* /*ah*/, AuctionEntry* entry) 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)); Player* owner = eObjectAccessor->FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER));
#ifdef TRINITY #ifdef TRINITY
Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow); Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow);
@@ -100,7 +120,7 @@ void Eluna::OnAdd(AuctionHouseObject* /*ah*/, AuctionEntry* entry)
if (!owner || !item) if (!owner || !item)
return; return;
LOCK_ELUNA; START_HOOK(AUCTION_EVENT_ON_ADD);
Push(entry->Id); Push(entry->Id);
Push(owner); Push(owner);
Push(item); Push(item);
@@ -109,14 +129,11 @@ void Eluna::OnAdd(AuctionHouseObject* /*ah*/, AuctionEntry* entry)
Push(entry->startbid); Push(entry->startbid);
Push(entry->bid); Push(entry->bid);
Push(entry->bidder); Push(entry->bidder);
CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_ADD); CallAllFunctions(ServerEventBindings, key);
} }
void Eluna::OnRemove(AuctionHouseObject* /*ah*/, AuctionEntry* entry) 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)); Player* owner = eObjectAccessor->FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER));
#ifdef TRINITY #ifdef TRINITY
Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow); Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow);
@@ -130,7 +147,7 @@ void Eluna::OnRemove(AuctionHouseObject* /*ah*/, AuctionEntry* entry)
if (!owner || !item) if (!owner || !item)
return; return;
LOCK_ELUNA; START_HOOK(AUCTION_EVENT_ON_REMOVE);
Push(entry->Id); Push(entry->Id);
Push(owner); Push(owner);
Push(item); Push(item);
@@ -139,14 +156,11 @@ void Eluna::OnRemove(AuctionHouseObject* /*ah*/, AuctionEntry* entry)
Push(entry->startbid); Push(entry->startbid);
Push(entry->bid); Push(entry->bid);
Push(entry->bidder); Push(entry->bidder);
CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_REMOVE); CallAllFunctions(ServerEventBindings, key);
} }
void Eluna::OnSuccessful(AuctionHouseObject* /*ah*/, AuctionEntry* entry) 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)); Player* owner = eObjectAccessor->FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER));
#ifdef TRINITY #ifdef TRINITY
Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow); Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow);
@@ -160,7 +174,7 @@ void Eluna::OnSuccessful(AuctionHouseObject* /*ah*/, AuctionEntry* entry)
if (!owner || !item) if (!owner || !item)
return; return;
LOCK_ELUNA; START_HOOK(AUCTION_EVENT_ON_SUCCESSFUL);
Push(entry->Id); Push(entry->Id);
Push(owner); Push(owner);
Push(item); Push(item);
@@ -169,14 +183,11 @@ void Eluna::OnSuccessful(AuctionHouseObject* /*ah*/, AuctionEntry* entry)
Push(entry->startbid); Push(entry->startbid);
Push(entry->bid); Push(entry->bid);
Push(entry->bidder); Push(entry->bidder);
CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_SUCCESSFUL); CallAllFunctions(ServerEventBindings, key);
} }
void Eluna::OnExpire(AuctionHouseObject* /*ah*/, AuctionEntry* entry) 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)); Player* owner = eObjectAccessor->FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER));
#ifdef TRINITY #ifdef TRINITY
Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow); Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow);
@@ -190,7 +201,7 @@ void Eluna::OnExpire(AuctionHouseObject* /*ah*/, AuctionEntry* entry)
if (!owner || !item) if (!owner || !item)
return; return;
LOCK_ELUNA; START_HOOK(AUCTION_EVENT_ON_EXPIRE);
Push(entry->Id); Push(entry->Id);
Push(owner); Push(owner);
Push(item); Push(item);
@@ -199,177 +210,35 @@ void Eluna::OnExpire(AuctionHouseObject* /*ah*/, AuctionEntry* entry)
Push(entry->startbid); Push(entry->startbid);
Push(entry->bid); Push(entry->bid);
Push(entry->bidder); Push(entry->bidder);
CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_EXPIRE); CallAllFunctions(ServerEventBindings, key);
}
// 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<WorldPacket>(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<WorldPacket>(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<WorldPacket>(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<WorldPacket>(L, r + 1, false))
packet = *data;
lua_pop(L, 2);
}
CleanUpStack(2);
} }
void Eluna::OnOpenStateChange(bool open) void Eluna::OnOpenStateChange(bool open)
{ {
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_OPEN_STATE_CHANGE)) START_HOOK(WORLD_EVENT_ON_OPEN_STATE_CHANGE);
return;
LOCK_ELUNA;
Push(open); Push(open);
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_OPEN_STATE_CHANGE); CallAllFunctions(ServerEventBindings, key);
} }
void Eluna::OnConfigLoad(bool reload) void Eluna::OnConfigLoad(bool reload)
{ {
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_CONFIG_LOAD)) START_HOOK(WORLD_EVENT_ON_CONFIG_LOAD);
return;
LOCK_ELUNA;
Push(reload); Push(reload);
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_CONFIG_LOAD); CallAllFunctions(ServerEventBindings, key);
} }
void Eluna::OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask) void Eluna::OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask)
{ {
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN_INIT)) START_HOOK(WORLD_EVENT_ON_SHUTDOWN_INIT);
return;
LOCK_ELUNA;
Push(code); Push(code);
Push(mask); Push(mask);
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_INIT); CallAllFunctions(ServerEventBindings, key);
} }
void Eluna::OnShutdownCancel() void Eluna::OnShutdownCancel()
{ {
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN_CANCEL)) START_HOOK(WORLD_EVENT_ON_SHUTDOWN_CANCEL);
return; CallAllFunctions(ServerEventBindings, key);
LOCK_ELUNA;
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_CANCEL);
} }
void Eluna::OnWorldUpdate(uint32 diff) void Eluna::OnWorldUpdate(uint32 diff)
@@ -382,106 +251,74 @@ void Eluna::OnWorldUpdate(uint32 diff)
eventMgr->globalProcessor->Update(diff); eventMgr->globalProcessor->Update(diff);
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_UPDATE)) START_HOOK(WORLD_EVENT_ON_UPDATE);
return;
LOCK_ELUNA;
Push(diff); Push(diff);
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_UPDATE); CallAllFunctions(ServerEventBindings, key);
} }
void Eluna::OnStartup() void Eluna::OnStartup()
{ {
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_STARTUP)) START_HOOK(WORLD_EVENT_ON_STARTUP);
return; CallAllFunctions(ServerEventBindings, key);
LOCK_ELUNA;
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_STARTUP);
} }
void Eluna::OnShutdown() void Eluna::OnShutdown()
{ {
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN)) START_HOOK(WORLD_EVENT_ON_SHUTDOWN);
return; CallAllFunctions(ServerEventBindings, key);
LOCK_ELUNA;
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN);
} }
/* Map */ /* Map */
void Eluna::OnCreate(Map* map) void Eluna::OnCreate(Map* map)
{ {
if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_CREATE)) START_HOOK(MAP_EVENT_ON_CREATE);
return;
LOCK_ELUNA;
Push(map); Push(map);
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_CREATE); CallAllFunctions(ServerEventBindings, key);
} }
void Eluna::OnDestroy(Map* map) void Eluna::OnDestroy(Map* map)
{ {
if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_DESTROY)) START_HOOK(MAP_EVENT_ON_DESTROY);
return;
LOCK_ELUNA;
Push(map); Push(map);
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_DESTROY); CallAllFunctions(ServerEventBindings, key);
} }
void Eluna::OnPlayerEnter(Map* map, Player* player) void Eluna::OnPlayerEnter(Map* map, Player* player)
{ {
if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_PLAYER_ENTER)) START_HOOK(MAP_EVENT_ON_PLAYER_ENTER);
return;
LOCK_ELUNA;
Push(map); Push(map);
Push(player); Push(player);
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_PLAYER_ENTER); CallAllFunctions(ServerEventBindings, key);
} }
void Eluna::OnPlayerLeave(Map* map, Player* player) void Eluna::OnPlayerLeave(Map* map, Player* player)
{ {
if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_PLAYER_LEAVE)) START_HOOK(MAP_EVENT_ON_PLAYER_LEAVE);
return;
LOCK_ELUNA;
Push(map); Push(map);
Push(player); Push(player);
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_PLAYER_LEAVE); CallAllFunctions(ServerEventBindings, key);
} }
void Eluna::OnUpdate(Map* map, uint32 diff) void Eluna::OnUpdate(Map* map, uint32 diff)
{ {
if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_UPDATE)) START_HOOK(MAP_EVENT_ON_UPDATE);
return;
LOCK_ELUNA;
// enable this for multithread // enable this for multithread
// eventMgr->globalProcessor->Update(diff); // eventMgr->globalProcessor->Update(diff);
Push(map); Push(map);
Push(diff); Push(diff);
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_UPDATE); CallAllFunctions(ServerEventBindings, key);
} }
void Eluna::OnRemove(GameObject* gameobject) void Eluna::OnRemove(GameObject* gameobject)
{ {
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_DELETE_GAMEOBJECT)) START_HOOK(WORLD_EVENT_ON_DELETE_GAMEOBJECT);
return;
LOCK_ELUNA;
Push(gameobject); Push(gameobject);
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_DELETE_GAMEOBJECT); CallAllFunctions(ServerEventBindings, key);
} }
void Eluna::OnRemove(Creature* creature) void Eluna::OnRemove(Creature* creature)
{ {
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_DELETE_CREATURE)) START_HOOK(WORLD_EVENT_ON_DELETE_CREATURE);
return;
LOCK_ELUNA;
Push(creature); Push(creature);
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_DELETE_CREATURE); CallAllFunctions(ServerEventBindings, key);
} }
#endif // _SERVER_HOOKS_H

View File

@@ -4,13 +4,10 @@
* Please see the included DOCS/LICENSE.md for more information * Please see the included DOCS/LICENSE.md for more information
*/ */
#ifndef _VEHICLE_HOOKS_H
#define _VEHICLE_HOOKS_H
#include "Hooks.h" #include "Hooks.h"
#include "HookHelpers.h" #include "HookHelpers.h"
#include "LuaEngine.h" #include "LuaEngine.h"
#include "ElunaBinding.h" #include "BindingMap.h"
#include "ElunaTemplate.h" #include "ElunaTemplate.h"
#ifndef CLASSIC #ifndef CLASSIC
@@ -18,61 +15,53 @@
using namespace Hooks; using namespace Hooks;
#define START_HOOK(EVENT) \
if (!IsEnabled())\
return;\
auto key = EventKey<VehicleEvents>(EVENT);\
if (!VehicleEventBindings->HasBindingsFor(key))\
return;\
LOCK_ELUNA
// Vehicle // Vehicle
void Eluna::OnInstall(Vehicle* vehicle) void Eluna::OnInstall(Vehicle* vehicle)
{ {
if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_INSTALL)) START_HOOK(VEHICLE_EVENT_ON_INSTALL);
return;
LOCK_ELUNA;
Push(vehicle); Push(vehicle);
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL); CallAllFunctions(VehicleEventBindings, key);
} }
void Eluna::OnUninstall(Vehicle* vehicle) void Eluna::OnUninstall(Vehicle* vehicle)
{ {
if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_UNINSTALL)) START_HOOK(VEHICLE_EVENT_ON_UNINSTALL);
return;
LOCK_ELUNA;
Push(vehicle); Push(vehicle);
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_UNINSTALL); CallAllFunctions(VehicleEventBindings, key);
} }
void Eluna::OnInstallAccessory(Vehicle* vehicle, Creature* accessory) void Eluna::OnInstallAccessory(Vehicle* vehicle, Creature* accessory)
{ {
if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_INSTALL_ACCESSORY)) START_HOOK(VEHICLE_EVENT_ON_INSTALL_ACCESSORY);
return;
LOCK_ELUNA;
Push(vehicle); Push(vehicle);
Push(accessory); Push(accessory);
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL_ACCESSORY); CallAllFunctions(VehicleEventBindings, key);
} }
void Eluna::OnAddPassenger(Vehicle* vehicle, Unit* passenger, int8 seatId) void Eluna::OnAddPassenger(Vehicle* vehicle, Unit* passenger, int8 seatId)
{ {
if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_ADD_PASSENGER)) START_HOOK(VEHICLE_EVENT_ON_ADD_PASSENGER);
return;
LOCK_ELUNA;
Push(vehicle); Push(vehicle);
Push(passenger); Push(passenger);
Push(seatId); Push(seatId);
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_ADD_PASSENGER); CallAllFunctions(VehicleEventBindings, key);
} }
void Eluna::OnRemovePassenger(Vehicle* vehicle, Unit* passenger) void Eluna::OnRemovePassenger(Vehicle* vehicle, Unit* passenger)
{ {
if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_REMOVE_PASSENGER)) START_HOOK(VEHICLE_EVENT_ON_REMOVE_PASSENGER);
return;
LOCK_ELUNA;
Push(vehicle); Push(vehicle);
Push(passenger); Push(passenger);
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_REMOVE_PASSENGER); CallAllFunctions(VehicleEventBindings, key);
} }
#endif // CLASSIC #endif // CLASSIC
#endif // TBC #endif // TBC
#endif // _VEHICLE_HOOKS_H