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
*/
#ifndef _BATTLEGROUND_HOOKS_H
#define _BATTLEGROUND_HOOKS_H
#include "Hooks.h"
#include "HookHelpers.h"
#include "LuaEngine.h"
#include "ElunaBinding.h"
#include "BindingMap.h"
#include "ElunaTemplate.h"
using namespace Hooks;
#define START_HOOK(EVENT) \
if (!IsEnabled())\
return;\
auto key = EventKey<BGEvents>(EVENT);\
if (!BGEventBindings->HasBindingsFor(key))\
return;\
LOCK_ELUNA
void Eluna::OnBGStart(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId)
{
if (!BGEventBindings->HasEvents(BG_EVENT_ON_START))
return;
LOCK_ELUNA;
START_HOOK(BG_EVENT_ON_START);
Push(bg);
Push(bgId);
Push(instanceId);
CallAllFunctions(BGEventBindings, BG_EVENT_ON_START);
CallAllFunctions(BGEventBindings, key);
}
void Eluna::OnBGEnd(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId, Team winner)
{
if (!BGEventBindings->HasEvents(BG_EVENT_ON_END))
return;
LOCK_ELUNA;
START_HOOK(BG_EVENT_ON_END);
Push(bg);
Push(bgId);
Push(instanceId);
Push(winner);
CallAllFunctions(BGEventBindings, BG_EVENT_ON_END);
CallAllFunctions(BGEventBindings, key);
}
void Eluna::OnBGCreate(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId)
{
if (!BGEventBindings->HasEvents(BG_EVENT_ON_CREATE))
return;
LOCK_ELUNA;
START_HOOK(BG_EVENT_ON_CREATE);
Push(bg);
Push(bgId);
Push(instanceId);
CallAllFunctions(BGEventBindings, BG_EVENT_ON_CREATE);
CallAllFunctions(BGEventBindings, key);
}
void Eluna::OnBGDestroy(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId)
{
if (!BGEventBindings->HasEvents(BG_EVENT_ON_PRE_DESTROY))
return;
LOCK_ELUNA;
START_HOOK(BG_EVENT_ON_PRE_DESTROY);
Push(bg);
Push(bgId);
Push(instanceId);
CallAllFunctions(BGEventBindings, BG_EVENT_ON_PRE_DESTROY);
CallAllFunctions(BGEventBindings, key);
}
#endif // _BATTLEGROUND_HOOKS_H

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

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:
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();
@@ -80,7 +80,7 @@ private:
class EventMgr : public ElunaUtil::RWLockable
{
public:
typedef UNORDERED_SET<ElunaEventProcessor*> ProcessorSet;
typedef std::unordered_set<ElunaEventProcessor*> ProcessorSet;
ProcessorSet processors;
ElunaEventProcessor* globalProcessor;
Eluna** E;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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