Feat(AllCreatureEvent): Add RegisterAllCreatureEvent and support for CreatureTemplate object. (#312)

This commit is contained in:
iThorgrim
2025-09-17 11:54:52 +02:00
committed by GitHub
parent 1153fcaef7
commit 313596f86e
7 changed files with 207 additions and 20 deletions

View File

@@ -57,6 +57,7 @@ public:
void OnCreatureAddWorld(Creature* creature) override
{
sEluna->OnAddToWorld(creature);
sEluna->OnAllCreatureAddToWorld(creature);
if (creature->IsGuardian() && creature->ToTempSummon() && creature->ToTempSummon()->GetSummonerGUID().IsPlayer())
sEluna->OnPetAddedToWorld(creature->ToTempSummon()->GetSummonerUnit()->ToPlayer(), creature);
@@ -65,6 +66,7 @@ public:
void OnCreatureRemoveWorld(Creature* creature) override
{
sEluna->OnRemoveFromWorld(creature);
sEluna->OnAllCreatureRemoveFromWorld(creature);
}
bool CanCreatureQuestAccept(Player* player, Creature* creature, Quest const* quest) override
@@ -92,6 +94,16 @@ public:
return nullptr;
}
void OnCreatureSelectLevel(const CreatureTemplate* cinfo, Creature* creature) override
{
sEluna->OnAllCreatureSelectLevel(cinfo, creature);
}
void OnBeforeCreatureSelectLevel(const CreatureTemplate* cinfo, Creature* creature, uint8& level) override
{
sEluna->OnAllCreatureBeforeSelectLevel(cinfo, creature, level);
}
};
class Eluna_AllGameObjectScript : public AllGameObjectScript

View File

@@ -88,6 +88,7 @@ namespace Hooks
REGTYPE_INSTANCE,
REGTYPE_TICKET,
REGTYPE_SPELL,
REGTYPE_ALL_CREATURE,
REGTYPE_COUNT
};
@@ -398,6 +399,15 @@ namespace Hooks
SPELL_EVENT_ON_CAST_CANCEL = 3, // (event, caster, spell, bySelf)
SPELL_EVENT_COUNT
};
enum AllCreatureEvents
{
ALL_CREATURE_EVENT_ON_ADD = 1, // (event, creature)
ALL_CREATURE_EVENT_ON_REMOVE = 2, // (event, creature)
ALL_CREATURE_EVENT_ON_SELECT_LEVEL = 3, // (event, creature_template, creature)
ALL_CREATURE_EVENT_ON_BEFORE_SELECT_LEVEL = 4, // (event, creature_template, creature, level) - Can return the new level
ALL_CREATURE_EVENT_COUNT
};
};
#endif // _HOOKS_H

View File

@@ -194,6 +194,7 @@ GuildEventBindings(NULL),
GroupEventBindings(NULL),
VehicleEventBindings(NULL),
BGEventBindings(NULL),
AllCreatureEventBindings(NULL),
PacketEventBindings(NULL),
CreatureEventBindings(NULL),
@@ -298,6 +299,7 @@ void Eluna::CreateBindStores()
VehicleEventBindings = new BindingMap< EventKey<Hooks::VehicleEvents> >(L);
BGEventBindings = new BindingMap< EventKey<Hooks::BGEvents> >(L);
TicketEventBindings = new BindingMap< EventKey<Hooks::TicketEvents> >(L);
AllCreatureEventBindings = new BindingMap< EventKey<Hooks::AllCreatureEvents> >(L);
PacketEventBindings = new BindingMap< EntryKey<Hooks::PacketEvents> >(L);
CreatureEventBindings = new BindingMap< EntryKey<Hooks::CreatureEvents> >(L);
@@ -321,6 +323,7 @@ void Eluna::DestroyBindStores()
delete GuildEventBindings;
delete GroupEventBindings;
delete VehicleEventBindings;
delete AllCreatureEventBindings;
delete PacketEventBindings;
delete CreatureEventBindings;
@@ -342,6 +345,7 @@ void Eluna::DestroyBindStores()
GuildEventBindings = NULL;
GroupEventBindings = NULL;
VehicleEventBindings = NULL;
AllCreatureEventBindings = NULL;
PacketEventBindings = NULL;
CreatureEventBindings = NULL;
@@ -1034,6 +1038,11 @@ void Eluna::Push(lua_State* luastate, SpellEntry const& spell)
Push(luastate, &spell);
}
void Eluna::Push(lua_State* luastate, CreatureTemplate const* creatureTemplate)
{
Push<CreatureTemplate>(luastate, creatureTemplate);
}
std::string Eluna::FormatQuery(lua_State* L, const char* query)
{
int numArgs = lua_gettop(L);
@@ -1476,6 +1485,7 @@ int Eluna::Register(lua_State* L, uint8 regtype, uint32 entry, ObjectGuid guid,
return 1; // Stack: callback
}
break;
case Hooks::REGTYPE_MAP:
if (event_id < Hooks::INSTANCE_EVENT_COUNT)
{
@@ -1485,6 +1495,7 @@ int Eluna::Register(lua_State* L, uint8 regtype, uint32 entry, ObjectGuid guid,
return 1; // Stack: callback
}
break;
case Hooks::REGTYPE_INSTANCE:
if (event_id < Hooks::INSTANCE_EVENT_COUNT)
{
@@ -1494,6 +1505,7 @@ int Eluna::Register(lua_State* L, uint8 regtype, uint32 entry, ObjectGuid guid,
return 1; // Stack: callback
}
break;
case Hooks::REGTYPE_TICKET:
if (event_id < Hooks::TICKET_EVENT_COUNT)
{
@@ -1503,6 +1515,7 @@ int Eluna::Register(lua_State* L, uint8 regtype, uint32 entry, ObjectGuid guid,
return 1; // Stack: callback
}
break;
case Hooks::REGTYPE_SPELL:
if (event_id < Hooks::SPELL_EVENT_COUNT)
{
@@ -1519,6 +1532,16 @@ int Eluna::Register(lua_State* L, uint8 regtype, uint32 entry, ObjectGuid guid,
return 1; // Stack: callback
}
break;
case Hooks::REGTYPE_ALL_CREATURE:
if (event_id < Hooks::ALL_CREATURE_EVENT_COUNT)
{
auto key = EventKey<Hooks::AllCreatureEvents>((Hooks::AllCreatureEvents)event_id);
bindingID = AllCreatureEventBindings->Insert(key, functionRef, shots);
createCancelCallback(L, bindingID, AllCreatureEventBindings);
return 1; // Stack: callback
}
break;
}
luaL_unref(L, LUA_REGISTRYINDEX, functionRef);
std::ostringstream oss;

View File

@@ -226,6 +226,7 @@ private:
void Push(const std::string& value) { Push(L, value); ++push_counter; }
void Push(const char* value) { Push(L, value); ++push_counter; }
void Push(ObjectGuid const value) { Push(L, value); ++push_counter; }
void Push(const CreatureTemplate* value) { Push(L, value); ++push_counter; }
template<typename T>
void Push(T const* ptr) { Push(L, ptr); ++push_counter; }
@@ -244,6 +245,7 @@ public:
BindingMap< EventKey<Hooks::GroupEvents> >* GroupEventBindings;
BindingMap< EventKey<Hooks::VehicleEvents> >* VehicleEventBindings;
BindingMap< EventKey<Hooks::BGEvents> >* BGEventBindings;
BindingMap< EventKey<Hooks::AllCreatureEvents> >* AllCreatureEventBindings;
BindingMap< EntryKey<Hooks::PacketEvents> >* PacketEventBindings;
BindingMap< EntryKey<Hooks::CreatureEvents> >* CreatureEventBindings;
@@ -299,6 +301,7 @@ public:
static void Push(lua_State* luastate, ObjectGuid const guid);
static void Push(lua_State* luastate, GemPropertiesEntry const& gemProperties);
static void Push(lua_State* luastate, SpellEntry const& spell);
static void Push(lua_State* luastate, CreatureTemplate const* creatureTemplate);
template<typename T>
static void Push(lua_State* luastate, T const* ptr)
{
@@ -588,6 +591,12 @@ public:
void OnSpellPrepare(Unit* caster, Spell* spell, SpellInfo const* spellInfo);
void OnSpellCast(Unit* caster, Spell* spell, SpellInfo const* spellInfo, bool skipCheck);
void OnSpellCastCancel(Unit* caster, Spell* spell, SpellInfo const* spellInfo, bool bySelf);
/* AllCreature */
void OnAllCreatureAddToWorld(Creature* creature);
void OnAllCreatureRemoveFromWorld(Creature* creature);
void OnAllCreatureSelectLevel(const CreatureTemplate* cinfo, Creature* creature);
void OnAllCreatureBeforeSelectLevel(const CreatureTemplate* cinfo, Creature* creature, uint8& level);
};
template<> Unit* Eluna::CHECKOBJ<Unit>(lua_State* L, int narg, bool error);
template<> Object* Eluna::CHECKOBJ<Object>(lua_State* L, int narg, bool error);

View File

@@ -70,6 +70,8 @@ luaL_Reg GlobalMethods[] =
{ "RegisterInstanceEvent", &LuaGlobalFunctions::RegisterInstanceEvent },
{ "RegisterTicketEvent", &LuaGlobalFunctions::RegisterTicketEvent },
{ "RegisterSpellEvent", &LuaGlobalFunctions::RegisterSpellEvent },
{ "RegisterAllCreatureEvent", &LuaGlobalFunctions::RegisterAllCreatureEvent },
{ "ClearBattleGroundEvents", &LuaGlobalFunctions::ClearBattleGroundEvents },
{ "ClearCreatureEvents", &LuaGlobalFunctions::ClearCreatureEvents },
@@ -89,6 +91,7 @@ luaL_Reg GlobalMethods[] =
{ "ClearInstanceEvents", &LuaGlobalFunctions::ClearInstanceEvents },
{ "ClearTicketEvents", &LuaGlobalFunctions::ClearTicketEvents },
{ "ClearSpellEvents", &LuaGlobalFunctions::ClearSpellEvents },
{ "ClearAllCreatureEvents", &LuaGlobalFunctions::ClearAllCreatureEvents },
// Getters
{ "GetLuaEngine", &LuaGlobalFunctions::GetLuaEngine },
@@ -1941,6 +1944,8 @@ void RegisterFunctions(Eluna* E)
ElunaTemplate<SpellEntry>::Register(E, "SpellEntry");
ElunaTemplate<SpellEntry>::SetMethods(E, SpellEntryMethods);
ElunaTemplate<CreatureTemplate>::Register(E, "CreatureTemplate");
ElunaTemplate<long long>::Register(E, "long long", true);
ElunaTemplate<unsigned long long>::Register(E, "unsigned long long", true);

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2010 - 2016 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(EVENT) \
if (!ElunaConfig::GetInstance().IsElunaEnabled())\
return;\
auto key = EventKey<AllCreatureEvents>(EVENT);\
if (!AllCreatureEventBindings->HasBindingsFor(key))\
return;\
LOCK_ELUNA
#define START_HOOK_WITH_RETVAL(EVENT, RETVAL) \
if (!ElunaConfig::GetInstance().IsElunaEnabled())\
return RETVAL;\
auto key = EventKey<AllCreatureEvents>(EVENT);\
if (!AllCreatureEventBindings->HasBindingsFor(key))\
return RETVAL;\
LOCK_ELUNA
void Eluna::OnAllCreatureAddToWorld(Creature* creature)
{
START_HOOK(ALL_CREATURE_EVENT_ON_ADD);
Push(creature);
CallAllFunctions(AllCreatureEventBindings, key);
}
void Eluna::OnAllCreatureRemoveFromWorld(Creature* creature)
{
START_HOOK(ALL_CREATURE_EVENT_ON_REMOVE);
Push(creature);
CallAllFunctions(AllCreatureEventBindings, key);
}
void Eluna::OnAllCreatureSelectLevel(const CreatureTemplate* cinfo, Creature* creature)
{
START_HOOK(ALL_CREATURE_EVENT_ON_SELECT_LEVEL);
Push(cinfo);
Push(creature);
CallAllFunctions(AllCreatureEventBindings, key);
}
void Eluna::OnAllCreatureBeforeSelectLevel(const CreatureTemplate* cinfo, Creature* creature, uint8& level)
{
START_HOOK(ALL_CREATURE_EVENT_ON_BEFORE_SELECT_LEVEL);
Push(cinfo);
Push(creature);
Push(level);
int levelIndex = lua_gettop(L);
int n = SetupStack(AllCreatureEventBindings, key, 3);
while (n > 0)
{
int r = CallOneFunction(n--, 3, 1);
if (lua_isnumber(L, r))
{
level = CHECKVAL<uint8>(L, r);
// Update the stack for subsequent calls.
ReplaceArgument(level, levelIndex);
}
lua_pop(L, 1);
}
CleanUpStack(3);
}

View File

@@ -1336,6 +1336,29 @@ namespace LuaGlobalFunctions
return RegisterEntryHelper(L, Hooks::REGTYPE_SPELL);
}
/**
* Registers a [Creature] event handler. It used AllCreatureScript so this don't need creature entry as a key.
*
* <pre>
* enum AllCreatureEvents
* {
* ALL_CREATURE_EVENT_ON_ADD = 1, // (event, creature)
* ALL_CREATURE_EVENT_ON_REMOVE = 2, // (event, creature)
* ALL_CREATURE_EVENT_ON_SELECT_LEVEL = 3, // (event, creature_template, creature)
* ALL_CREATURE_EVENT_ON_BEFORE_SELECT_LEVEL = 4, // (event, creature_template, creature, level) - Can return the new level
* ALL_CREATURE_EVENT_COUNT
* };
* </pre>
*
* @param uint32 event : event ID, refer to AllCreatureEvents 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"
*/
int RegisterAllCreatureEvent(lua_State* L)
{
return RegisterEventHelper(L, Hooks::REGTYPE_ALL_CREATURE);
}
/**
* Reloads the Lua engine.
*/
@@ -3302,6 +3325,33 @@ namespace LuaGlobalFunctions
return 0;
}
/**
* Unbinds event handlers for either all [Creature] events, or one type of [Creature] event.
*
* If `event_type` is `nil`, all [Creature] event handlers are cleared.
*
* Otherwise, only event handlers for `event_type` are cleared.
*
* @proto ()
* @proto (event_type)
* @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterAllCreatureEvent]
*/
int ClearAllCreatureEvents(lua_State* L)
{
typedef EventKey<Hooks::AllCreatureEvents> Key;
if (lua_isnoneornil(L, 1))
{
Eluna::GetEluna(L)->AllCreatureEventBindings->Clear();
}
else
{
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 1);
Eluna::GetEluna(L)->AllCreatureEventBindings->Clear(Key((Hooks::AllCreatureEvents)event_type));
}
return 0;
}
/**
* Gets the faction which is the current owner of Halaa in Nagrand
* 0 = Alliance