mirror of
https://github.com/azerothcore/mod-ale
synced 2025-11-29 15:38:17 +08:00
Eluna add new system for userdata management. single userdata with GC.
Note that this will still need the core side destructors to have the ref remove function used in order to have invalid pointer errors.
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
*.bak
|
||||||
|
*.patch
|
||||||
|
*.diff
|
||||||
26
HookMgr.cpp
26
HookMgr.cpp
@@ -7,6 +7,20 @@
|
|||||||
#include "LuaEngine.h"
|
#include "LuaEngine.h"
|
||||||
#include "HookMgr.h"
|
#include "HookMgr.h"
|
||||||
|
|
||||||
|
void HookMgr::RemoveRef(const void* obj) const
|
||||||
|
{
|
||||||
|
lua_rawgeti(sEluna->L, LUA_REGISTRYINDEX, sHookMgr->userdata_table);
|
||||||
|
lua_pushfstring(sEluna->L, "%p", obj);
|
||||||
|
lua_gettable(sEluna->L, -2);
|
||||||
|
if (!lua_isnoneornil(sEluna->L, -1))
|
||||||
|
{
|
||||||
|
lua_pushfstring(sEluna->L, "%p", obj);
|
||||||
|
lua_pushnil(sEluna->L);
|
||||||
|
lua_settable(sEluna->L, -4);
|
||||||
|
}
|
||||||
|
lua_pop(sEluna->L, 2);
|
||||||
|
}
|
||||||
|
|
||||||
void HookMgr::OnEngineRestart()
|
void HookMgr::OnEngineRestart()
|
||||||
{
|
{
|
||||||
if (!sEluna->ServerEventBindings.HasEvents(ELUNA_EVENT_ON_RESTART))
|
if (!sEluna->ServerEventBindings.HasEvents(ELUNA_EVENT_ON_RESTART))
|
||||||
@@ -205,8 +219,8 @@ bool HookMgr::OnPacketReceive(WorldSession* session, WorldPacket& packet)
|
|||||||
bool HookMgr::OnAddonMessage(Player* sender, uint32 type, std::string& msg, Player* receiver, Guild* guild, Group* group, Channel* channel)
|
bool HookMgr::OnAddonMessage(Player* sender, uint32 type, std::string& msg, Player* receiver, Guild* guild, Group* group, Channel* channel)
|
||||||
{
|
{
|
||||||
if (!sEluna->ServerEventBindings.HasEvents(ADDON_EVENT_ON_MESSAGE))
|
if (!sEluna->ServerEventBindings.HasEvents(ADDON_EVENT_ON_MESSAGE))
|
||||||
return false;
|
return false;
|
||||||
ELUNA_GUARD();
|
ELUNA_GUARD();
|
||||||
sEluna->ServerEventBindings.BeginCall(ADDON_EVENT_ON_MESSAGE);
|
sEluna->ServerEventBindings.BeginCall(ADDON_EVENT_ON_MESSAGE);
|
||||||
sEluna->Push(sEluna->L, sender);
|
sEluna->Push(sEluna->L, sender);
|
||||||
sEluna->Push(sEluna->L, type);
|
sEluna->Push(sEluna->L, type);
|
||||||
@@ -223,8 +237,8 @@ bool HookMgr::OnAddonMessage(Player* sender, uint32 type, std::string& msg, Play
|
|||||||
sEluna->Push(sEluna->L, channel->GetChannelId());
|
sEluna->Push(sEluna->L, channel->GetChannelId());
|
||||||
else
|
else
|
||||||
sEluna->Push(sEluna->L);
|
sEluna->Push(sEluna->L);
|
||||||
sEluna->ServerEventBindings.ExecuteCall();
|
sEluna->ServerEventBindings.ExecuteCall();
|
||||||
sEluna->ServerEventBindings.EndCall();
|
sEluna->ServerEventBindings.EndCall();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +246,7 @@ bool HookMgr::OnAddonMessage(Player* sender, uint32 type, std::string& msg, Play
|
|||||||
class ElunaWorldAI : public WorldScript
|
class ElunaWorldAI : public WorldScript
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ElunaWorldAI() : WorldScript("ElunaWorldAI") {}
|
ElunaWorldAI(): WorldScript("ElunaWorldAI") {}
|
||||||
~ElunaWorldAI() {}
|
~ElunaWorldAI() {}
|
||||||
|
|
||||||
void OnOpenStateChange(bool open) override
|
void OnOpenStateChange(bool open) override
|
||||||
@@ -1582,7 +1596,7 @@ struct ElunaCreatureAI : ScriptedAI
|
|||||||
#define me m_creature
|
#define me m_creature
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ElunaCreatureAI(Creature* creature) : ScriptedAI(creature)
|
ElunaCreatureAI(Creature* creature): ScriptedAI(creature)
|
||||||
{
|
{
|
||||||
JustRespawned();
|
JustRespawned();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ struct AreaTriggerEntry;
|
|||||||
class ReactorAI;
|
class ReactorAI;
|
||||||
typedef ReactorAI ScriptedAI;
|
typedef ReactorAI ScriptedAI;
|
||||||
#else
|
#else
|
||||||
|
#undef UNORDERED_MAP
|
||||||
|
#define UNORDERED_MAP std::unordered_map
|
||||||
struct ScriptedAI;
|
struct ScriptedAI;
|
||||||
#endif
|
#endif
|
||||||
class AuctionHouseObject;
|
class AuctionHouseObject;
|
||||||
@@ -321,7 +323,8 @@ enum GossipEvents
|
|||||||
class HookMgr
|
class HookMgr
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class ACE_Singleton<HookMgr, ACE_Thread_Mutex>;
|
int userdata_table;
|
||||||
|
void RemoveRef(const void* obj) const;
|
||||||
|
|
||||||
CreatureAI* GetAI(Creature* creature);
|
CreatureAI* GetAI(Creature* creature);
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,14 @@ bool StartEluna()
|
|||||||
luaL_openlibs(sEluna->L);
|
luaL_openlibs(sEluna->L);
|
||||||
RegisterFunctions(sEluna->L);
|
RegisterFunctions(sEluna->L);
|
||||||
|
|
||||||
|
// Create hidden table with weak values
|
||||||
|
lua_newtable(sEluna->L);
|
||||||
|
lua_newtable(sEluna->L);
|
||||||
|
lua_pushstring(sEluna->L, "v");
|
||||||
|
lua_setfield(sEluna->L, -2, "__mode");
|
||||||
|
lua_setmetatable(sEluna->L, -2);
|
||||||
|
sHookMgr->userdata_table = luaL_ref(sEluna->L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
ScriptPaths scripts;
|
ScriptPaths scripts;
|
||||||
std::string folderpath = sConfigMgr->GetStringDefault("Eluna.ScriptPath", "lua_scripts");
|
std::string folderpath = sConfigMgr->GetStringDefault("Eluna.ScriptPath", "lua_scripts");
|
||||||
#if PLATFORM == PLATFORM_UNIX || PLATFORM == PLATFORM_APPLE
|
#if PLATFORM == PLATFORM_UNIX || PLATFORM == PLATFORM_APPLE
|
||||||
@@ -83,7 +91,7 @@ bool StartEluna()
|
|||||||
#endif
|
#endif
|
||||||
ELUNA_LOG_INFO("[Eluna]: Searching scripts from `%s`", folderpath.c_str());
|
ELUNA_LOG_INFO("[Eluna]: Searching scripts from `%s`", folderpath.c_str());
|
||||||
sEluna->GetScripts(folderpath, scripts);
|
sEluna->GetScripts(folderpath, scripts);
|
||||||
sEluna->GetScripts(folderpath+"/extensions", scripts);
|
sEluna->GetScripts(folderpath + "/extensions", scripts);
|
||||||
sEluna->RunScripts(scripts);
|
sEluna->RunScripts(scripts);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -187,7 +195,7 @@ void Eluna::report(lua_State* L)
|
|||||||
const char* msg = lua_tostring(L, -1);
|
const char* msg = lua_tostring(L, -1);
|
||||||
while (msg)
|
while (msg)
|
||||||
{
|
{
|
||||||
lua_pop(L, -1);
|
lua_pop(L, 1);
|
||||||
ELUNA_LOG_ERROR("%s", msg);
|
ELUNA_LOG_ERROR("%s", msg);
|
||||||
msg = lua_tostring(L, -1);
|
msg = lua_tostring(L, -1);
|
||||||
}
|
}
|
||||||
@@ -504,15 +512,15 @@ template<> int64 Eluna::CHECKVAL<int64>(lua_State* L, int narg, int64 def)
|
|||||||
#define TEST_OBJ(T, O, E, F)\
|
#define TEST_OBJ(T, O, E, F)\
|
||||||
{\
|
{\
|
||||||
if (!O || !O->F())\
|
if (!O || !O->F())\
|
||||||
{\
|
{\
|
||||||
if (E)\
|
if (E)\
|
||||||
{\
|
{\
|
||||||
std::string errmsg(ElunaTemplate<T>::tname);\
|
std::string errmsg(ElunaTemplate<T>::tname);\
|
||||||
errmsg += " expected";\
|
errmsg += " expected";\
|
||||||
luaL_argerror(L, narg, errmsg.c_str());\
|
luaL_argerror(L, narg, errmsg.c_str());\
|
||||||
}\
|
}\
|
||||||
return NULL;\
|
return NULL;\
|
||||||
}\
|
}\
|
||||||
return O->F();\
|
return O->F();\
|
||||||
}
|
}
|
||||||
template<> Unit* Eluna::CHECKOBJ<Unit>(lua_State* L, int narg, bool error)
|
template<> Unit* Eluna::CHECKOBJ<Unit>(lua_State* L, int narg, bool error)
|
||||||
@@ -772,7 +780,7 @@ void Eluna::EntryBind::Insert(uint32 entryId, int eventId, int funcRef)
|
|||||||
Bindings[entryId][eventId] = funcRef;
|
Bindings[entryId][eventId] = funcRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventMgr::LuaEvent::LuaEvent(EventProcessor* _events, int _funcRef, uint32 _delay, uint32 _calls, Object* _obj) :
|
EventMgr::LuaEvent::LuaEvent(EventProcessor* _events, int _funcRef, uint32 _delay, uint32 _calls, Object* _obj):
|
||||||
events(_events), funcRef(_funcRef), delay(_delay), calls(_calls), obj(_obj)
|
events(_events), funcRef(_funcRef), delay(_delay), calls(_calls), obj(_obj)
|
||||||
{
|
{
|
||||||
if (_events)
|
if (_events)
|
||||||
|
|||||||
388
LuaEngine.h
388
LuaEngine.h
@@ -122,8 +122,6 @@ enum SelectAggroTarget
|
|||||||
#define Opcodes OpcodesList
|
#define Opcodes OpcodesList
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#undef UNORDERED_MAP
|
|
||||||
#define UNORDERED_MAP std::unordered_map
|
|
||||||
#ifndef CATA
|
#ifndef CATA
|
||||||
typedef uint64 ObjectGuid;
|
typedef uint64 ObjectGuid;
|
||||||
#endif
|
#endif
|
||||||
@@ -147,149 +145,6 @@ struct ElunaRegister
|
|||||||
int(*mfunc)(lua_State*, T*);
|
int(*mfunc)(lua_State*, T*);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class ElunaTemplate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const char* tname;
|
|
||||||
static bool manageMemory;
|
|
||||||
|
|
||||||
static int type(lua_State* L)
|
|
||||||
{
|
|
||||||
lua_pushstring(L, tname);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gcT(lua_State* L)
|
|
||||||
{
|
|
||||||
if (!manageMemory)
|
|
||||||
return 0;
|
|
||||||
T* obj = check(L, 1);
|
|
||||||
delete obj; // Deleting NULL should be safe
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// name will be used as type name
|
|
||||||
// If gc is true, lua will handle the memory management for object pushed
|
|
||||||
// gc should be used if pushing for example WorldPacket,
|
|
||||||
// that will only be needed on lua side and will not be managed by TC/mangos/<core>
|
|
||||||
static void Register(lua_State* L, const char* name, bool gc = false)
|
|
||||||
{
|
|
||||||
tname = name;
|
|
||||||
manageMemory = gc;
|
|
||||||
|
|
||||||
lua_settop(L, 0); // clean stack
|
|
||||||
|
|
||||||
lua_newtable(L);
|
|
||||||
int methods = lua_gettop(L);
|
|
||||||
|
|
||||||
luaL_newmetatable(L, tname);
|
|
||||||
int metatable = lua_gettop(L);
|
|
||||||
|
|
||||||
// store method table in globals so that
|
|
||||||
// scripts can add functions in Lua
|
|
||||||
lua_pushvalue(L, methods);
|
|
||||||
lua_setglobal(L, tname);
|
|
||||||
|
|
||||||
// hide metatable
|
|
||||||
lua_pushvalue(L, methods);
|
|
||||||
lua_setfield(L, metatable, "__metatable");
|
|
||||||
|
|
||||||
lua_pushvalue(L, methods);
|
|
||||||
lua_setfield(L, metatable, "__index");
|
|
||||||
|
|
||||||
lua_pushcfunction(L, tostringT);
|
|
||||||
lua_setfield(L, metatable, "__tostring");
|
|
||||||
|
|
||||||
lua_pushcfunction(L, gcT);
|
|
||||||
lua_setfield(L, metatable, "__gc");
|
|
||||||
|
|
||||||
lua_newtable(L);
|
|
||||||
lua_setmetatable(L, methods);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename C>
|
|
||||||
static void SetMethods(lua_State* L, ElunaRegister<C>* methodTable)
|
|
||||||
{
|
|
||||||
if (!methodTable)
|
|
||||||
return;
|
|
||||||
if (!lua_istable(L, 1))
|
|
||||||
return;
|
|
||||||
lua_pushstring(L, "GetObjectType");
|
|
||||||
lua_pushcclosure(L, type, 0);
|
|
||||||
lua_settable(L, 1);
|
|
||||||
for (; methodTable->name; ++methodTable)
|
|
||||||
{
|
|
||||||
lua_pushstring(L, methodTable->name);
|
|
||||||
lua_pushlightuserdata(L, (void*)methodTable);
|
|
||||||
lua_pushcclosure(L, thunk, 1);
|
|
||||||
lua_settable(L, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int push(lua_State* L, T const* obj)
|
|
||||||
{
|
|
||||||
if (!obj)
|
|
||||||
{
|
|
||||||
lua_pushnil(L);
|
|
||||||
return lua_gettop(L);
|
|
||||||
}
|
|
||||||
luaL_getmetatable(L, tname);
|
|
||||||
if (lua_isnoneornil(L, -1))
|
|
||||||
return luaL_error(L, "%s missing metatable", tname);
|
|
||||||
T const** ptrHold = (T const**)lua_newuserdata(L, sizeof(T**));
|
|
||||||
if (ptrHold)
|
|
||||||
{
|
|
||||||
*ptrHold = obj;
|
|
||||||
lua_pushvalue(L, -2);
|
|
||||||
lua_setmetatable(L, -2);
|
|
||||||
}
|
|
||||||
lua_replace(L, -2);
|
|
||||||
return lua_gettop(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
static T* check(lua_State* L, int narg, bool error = true)
|
|
||||||
{
|
|
||||||
T** ptrHold = static_cast<T**>(lua_touserdata(L, narg));
|
|
||||||
if (!ptrHold)
|
|
||||||
{
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
std::string errmsg(ElunaTemplate<T>::tname);
|
|
||||||
errmsg += " expected";
|
|
||||||
luaL_argerror(L, narg, errmsg.c_str());
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return *ptrHold;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int thunk(lua_State* L)
|
|
||||||
{
|
|
||||||
T* obj = check(L, 1); // get self
|
|
||||||
ElunaRegister<T>* l = static_cast<ElunaRegister<T>*>(lua_touserdata(L, lua_upvalueindex(1)));
|
|
||||||
if (!obj)
|
|
||||||
return 0;
|
|
||||||
int args = lua_gettop(L);
|
|
||||||
int expected = l->mfunc(L, obj);
|
|
||||||
args = lua_gettop(L) - args;
|
|
||||||
if (args < 0 || args > expected) // Assert instead?
|
|
||||||
ELUNA_LOG_ERROR("[Eluna]: %s returned unexpected amount of arguments %i out of %i. Report to devs", l->name, args, expected);
|
|
||||||
for (; args < expected; ++args)
|
|
||||||
lua_pushnil(L);
|
|
||||||
return expected;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tostringT(lua_State* L)
|
|
||||||
{
|
|
||||||
char buff[32];
|
|
||||||
T** ptrHold = (T**)lua_touserdata(L, 1);
|
|
||||||
sprintf(buff, "%p", *ptrHold);
|
|
||||||
lua_pushfstring(L, "%s (%s)", tname, buff);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EventMgr
|
struct EventMgr
|
||||||
{
|
{
|
||||||
struct LuaEvent;
|
struct LuaEvent;
|
||||||
@@ -622,7 +477,7 @@ public:
|
|||||||
|
|
||||||
struct ObjectGUIDCheck
|
struct ObjectGUIDCheck
|
||||||
{
|
{
|
||||||
ObjectGUIDCheck(ObjectGuid guid) : _guid(guid) { }
|
ObjectGUIDCheck(ObjectGuid guid): _guid(guid) {}
|
||||||
bool operator()(WorldObject* object)
|
bool operator()(WorldObject* object)
|
||||||
{
|
{
|
||||||
return object->GET_GUID() == _guid;
|
return object->GET_GUID() == _guid;
|
||||||
@@ -634,7 +489,7 @@ public:
|
|||||||
// Binary predicate to sort WorldObjects based on the distance to a reference WorldObject
|
// Binary predicate to sort WorldObjects based on the distance to a reference WorldObject
|
||||||
struct ObjectDistanceOrderPred
|
struct ObjectDistanceOrderPred
|
||||||
{
|
{
|
||||||
ObjectDistanceOrderPred(WorldObject const* pRefObj, bool ascending = true) : m_refObj(pRefObj), m_ascending(ascending) { }
|
ObjectDistanceOrderPred(WorldObject const* pRefObj, bool ascending = true): m_refObj(pRefObj), m_ascending(ascending) {}
|
||||||
bool operator()(WorldObject const* pLeft, WorldObject const* pRight) const
|
bool operator()(WorldObject const* pLeft, WorldObject const* pRight) const
|
||||||
{
|
{
|
||||||
return m_ascending ? m_refObj->GetDistanceOrder(pLeft, pRight) : !m_refObj->GetDistanceOrder(pLeft, pRight);
|
return m_ascending ? m_refObj->GetDistanceOrder(pLeft, pRight) : !m_refObj->GetDistanceOrder(pLeft, pRight);
|
||||||
@@ -648,8 +503,10 @@ public:
|
|||||||
struct WorldObjectInRangeCheck
|
struct WorldObjectInRangeCheck
|
||||||
{
|
{
|
||||||
WorldObjectInRangeCheck(bool nearest, WorldObject const* obj, float range,
|
WorldObjectInRangeCheck(bool nearest, WorldObject const* obj, float range,
|
||||||
uint16 typeMask = 0, uint32 entry = 0, uint32 hostile = 0) : i_nearest(nearest),
|
uint16 typeMask = 0, uint32 entry = 0, uint32 hostile = 0): i_nearest(nearest),
|
||||||
i_obj(obj), i_range(range), i_typeMask(typeMask), i_entry(entry), i_hostile(hostile) {}
|
i_obj(obj), i_range(range), i_typeMask(typeMask), i_entry(entry), i_hostile(hostile)
|
||||||
|
{
|
||||||
|
}
|
||||||
WorldObject const& GetFocusObject() const { return *i_obj; }
|
WorldObject const& GetFocusObject() const { return *i_obj; }
|
||||||
bool operator()(WorldObject* u)
|
bool operator()(WorldObject* u)
|
||||||
{
|
{
|
||||||
@@ -708,6 +565,239 @@ template<> Corpse* Eluna::CHECKOBJ<Corpse>(lua_State* L, int narg, bool error);
|
|||||||
|
|
||||||
#define ELUNA_GUARD() // ACE_Guard< ACE_Recursive_Thread_Mutex > ELUNA_GUARD_OBJECT(sEluna->lock);
|
#define ELUNA_GUARD() // ACE_Guard< ACE_Recursive_Thread_Mutex > ELUNA_GUARD_OBJECT(sEluna->lock);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class ElunaTemplate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const char* tname;
|
||||||
|
static bool manageMemory;
|
||||||
|
|
||||||
|
static int typeT(lua_State* L)
|
||||||
|
{
|
||||||
|
lua_pushstring(L, tname);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// name will be used as type name
|
||||||
|
// If gc is true, lua will handle the memory management for object pushed
|
||||||
|
// gc should be used if pushing for example WorldPacket,
|
||||||
|
// that will only be needed on lua side and will not be managed by TC/mangos/<core>
|
||||||
|
static void Register(lua_State* L, const char* name, bool gc = false)
|
||||||
|
{
|
||||||
|
tname = name;
|
||||||
|
manageMemory = gc;
|
||||||
|
|
||||||
|
lua_newtable(L);
|
||||||
|
int methods = lua_gettop(L);
|
||||||
|
|
||||||
|
// store method table in globals so that
|
||||||
|
// scripts can add functions in Lua
|
||||||
|
lua_pushvalue(L, methods);
|
||||||
|
lua_setglobal(L, tname);
|
||||||
|
|
||||||
|
luaL_newmetatable(L, tname);
|
||||||
|
int metatable = lua_gettop(L);
|
||||||
|
|
||||||
|
// hide metatable
|
||||||
|
lua_pushvalue(L, methods);
|
||||||
|
lua_setfield(L, metatable, "__metatable");
|
||||||
|
|
||||||
|
// required to access methods
|
||||||
|
lua_pushvalue(L, methods);
|
||||||
|
lua_setfield(L, metatable, "__index");
|
||||||
|
|
||||||
|
// metamethods
|
||||||
|
lua_pushcfunction(L, tostringT);
|
||||||
|
lua_setfield(L, metatable, "__tostring");
|
||||||
|
|
||||||
|
lua_pushcfunction(L, gcT);
|
||||||
|
lua_setfield(L, metatable, "__gc");
|
||||||
|
|
||||||
|
// special method to get the object type
|
||||||
|
lua_pushcfunction(L, typeT);
|
||||||
|
lua_setfield(L, methods, "GetObjectType");
|
||||||
|
|
||||||
|
lua_setmetatable(L, methods);
|
||||||
|
|
||||||
|
lua_remove(L, methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename C>
|
||||||
|
static void SetMethods(lua_State* L, ElunaRegister<C>* methodTable)
|
||||||
|
{
|
||||||
|
if (!methodTable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
luaL_getmetatable(L, tname);
|
||||||
|
if (!lua_istable(L, -1))
|
||||||
|
{
|
||||||
|
lua_remove(L, -1);
|
||||||
|
ELUNA_LOG_ERROR("%s missing metatable", tname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(L, -1, "__metatable");
|
||||||
|
lua_remove(L, -2);
|
||||||
|
if (!lua_istable(L, -1))
|
||||||
|
{
|
||||||
|
lua_remove(L, -1);
|
||||||
|
ELUNA_LOG_ERROR("%s missing method table from metatable", tname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; methodTable && methodTable->name && methodTable->mfunc; ++methodTable)
|
||||||
|
{
|
||||||
|
lua_pushstring(L, methodTable->name);
|
||||||
|
lua_pushlightuserdata(L, (void*)methodTable);
|
||||||
|
lua_pushcclosure(L, thunk, 1);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_remove(L, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember special case ElunaTemplate<Vehicle>::gcT
|
||||||
|
static int gcT(lua_State* L)
|
||||||
|
{
|
||||||
|
if (!manageMemory)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Get object pointer (and check type, no error)
|
||||||
|
T** ptrHold = static_cast<T**>(luaL_testudata(L, -1, tname));
|
||||||
|
if (ptrHold)
|
||||||
|
delete *ptrHold;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int push(lua_State* L, T const* obj)
|
||||||
|
{
|
||||||
|
if (!obj)
|
||||||
|
{
|
||||||
|
lua_pushnil(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!manageMemory)
|
||||||
|
{
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, sHookMgr->userdata_table);
|
||||||
|
lua_pushfstring(L, "%p", obj);
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
if (!lua_isnoneornil(L, -1) && luaL_checkudata(L, -1, tname))
|
||||||
|
{
|
||||||
|
lua_remove(L, -2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
lua_remove(L, -1);
|
||||||
|
// left userdata_table in stack
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new userdata
|
||||||
|
T const** ptrHold = (T const**)lua_newuserdata(L, sizeof(T const**));
|
||||||
|
if (!ptrHold)
|
||||||
|
{
|
||||||
|
ELUNA_LOG_ERROR("%s could not create new userdata", tname);
|
||||||
|
lua_remove(L, -1);
|
||||||
|
lua_pushnil(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
*ptrHold = obj;
|
||||||
|
|
||||||
|
// Set metatable for it
|
||||||
|
luaL_getmetatable(L, tname);
|
||||||
|
if (!lua_istable(L, -1))
|
||||||
|
{
|
||||||
|
ELUNA_LOG_ERROR("%s missing metatable", tname);
|
||||||
|
lua_pop(L, 2);
|
||||||
|
lua_pushnil(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
|
||||||
|
|
||||||
|
if (!manageMemory)
|
||||||
|
{
|
||||||
|
lua_pushfstring(L, "%p", obj);
|
||||||
|
lua_pushvalue(L, -2);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_remove(L, -2);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static T* check(lua_State* L, int narg, bool error = true)
|
||||||
|
{
|
||||||
|
T** ptrHold = static_cast<T**>(error ? luaL_checkudata(L, narg, tname) : lua_touserdata(L, narg));
|
||||||
|
if (!ptrHold)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
char buff[256];
|
||||||
|
snprintf(buff, 256, "%s expected, got %s", tname, luaL_typename(L, narg));
|
||||||
|
luaL_argerror(L, narg, buff);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!manageMemory)
|
||||||
|
{
|
||||||
|
// Check pointer validity
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, sHookMgr->userdata_table);
|
||||||
|
lua_pushfstring(L, "%p", *ptrHold);
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
lua_remove(L, -2);
|
||||||
|
bool valid = lua_isuserdata(L, -1);
|
||||||
|
lua_remove(L, -1);
|
||||||
|
if (!valid)
|
||||||
|
{
|
||||||
|
char buff[256];
|
||||||
|
snprintf(buff, 256, "%s expected, got pointer to nonexisting object (%s). This should never happen", tname, luaL_typename(L, narg));
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
luaL_argerror(L, narg, buff);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ELUNA_LOG_ERROR("%s", buff);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *ptrHold;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int thunk(lua_State* L)
|
||||||
|
{
|
||||||
|
T* obj = sEluna->CHECKOBJ<T>(L, 1); // get self
|
||||||
|
if (!obj)
|
||||||
|
return 0;
|
||||||
|
ElunaRegister<T>* l = static_cast<ElunaRegister<T>*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||||
|
int args = lua_gettop(L);
|
||||||
|
int expected = l->mfunc(L, obj);
|
||||||
|
args = lua_gettop(L) - args;
|
||||||
|
if (args < 0 || args > expected) // Assert instead?
|
||||||
|
{
|
||||||
|
ELUNA_LOG_ERROR("[Eluna]: %s returned unexpected amount of arguments %i out of %i. Report to devs", l->name, args, expected);
|
||||||
|
}
|
||||||
|
for (; args < expected; ++args)
|
||||||
|
lua_pushnil(L);
|
||||||
|
return expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tostringT(lua_State* L)
|
||||||
|
{
|
||||||
|
T* obj = sEluna->CHECKOBJ<T>(L, 1); // get self
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
lua_pushfstring(L, "%s: (%p)", tname, obj);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_replace(L, 1);
|
||||||
|
luaL_tolstring(L, 1, NULL);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class LuaTaxiMgr
|
class LuaTaxiMgr
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -455,9 +455,9 @@ ElunaRegister<Player> PlayerMethods[] =
|
|||||||
{ "GetShieldBlockValue", &LuaPlayer::GetShieldBlockValue }, // :GetShieldBlockValue() - Returns block value
|
{ "GetShieldBlockValue", &LuaPlayer::GetShieldBlockValue }, // :GetShieldBlockValue() - Returns block value
|
||||||
#endif
|
#endif
|
||||||
#ifdef CLASSIC
|
#ifdef CLASSIC
|
||||||
{"GetHonorStoredKills", &LuaPlayer::GetHonorStoredKills}, // :GetHonorStoredKills(on/off)
|
{ "GetHonorStoredKills", &LuaPlayer::GetHonorStoredKills }, // :GetHonorStoredKills(on/off)
|
||||||
{"GetRankPoints", &LuaPlayer::GetRankPoints}, // :GetRankPoints()
|
{ "GetRankPoints", &LuaPlayer::GetRankPoints }, // :GetRankPoints()
|
||||||
{"GetHonorLastWeekStandingPos", &LuaPlayer::GetHonorLastWeekStandingPos}, // :GetHonorLastWeekStandingPos()
|
{ "GetHonorLastWeekStandingPos", &LuaPlayer::GetHonorLastWeekStandingPos }, // :GetHonorLastWeekStandingPos()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Setters
|
// Setters
|
||||||
@@ -478,9 +478,9 @@ ElunaRegister<Player> PlayerMethods[] =
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef CLASSIC
|
#ifdef CLASSIC
|
||||||
{"SetHonorStoredKills", &LuaPlayer::SetHonorStoredKills}, // :SetHonorStoredKills(kills, [on/off])
|
{ "SetHonorStoredKills", &LuaPlayer::SetHonorStoredKills }, // :SetHonorStoredKills(kills, [on/off])
|
||||||
{"SetRankPoints", &LuaPlayer::SetRankPoints}, // :SetRankPoints(rankPoints)
|
{ "SetRankPoints", &LuaPlayer::SetRankPoints }, // :SetRankPoints(rankPoints)
|
||||||
{"SetHonorLastWeekStandingPos", &LuaPlayer::SetHonorLastWeekStandingPos}, // :SetHonorLastWeekStandingPos(standingPos)
|
{ "SetHonorLastWeekStandingPos", &LuaPlayer::SetHonorLastWeekStandingPos }, // :SetHonorLastWeekStandingPos(standingPos)
|
||||||
#endif
|
#endif
|
||||||
{ "SetLifetimeKills", &LuaPlayer::SetLifetimeKills }, // :SetLifetimeKills(val) - Sets the overall lifetime (honorable) kills of the player
|
{ "SetLifetimeKills", &LuaPlayer::SetLifetimeKills }, // :SetLifetimeKills(val) - Sets the overall lifetime (honorable) kills of the player
|
||||||
{ "SetGameMaster", &LuaPlayer::SetGameMaster }, // :SetGameMaster([on]) - Sets GM mode on or off
|
{ "SetGameMaster", &LuaPlayer::SetGameMaster }, // :SetGameMaster([on]) - Sets GM mode on or off
|
||||||
@@ -682,9 +682,9 @@ ElunaRegister<Player> PlayerMethods[] =
|
|||||||
{ "SummonPlayer", &LuaPlayer::SummonPlayer }, // :SummonPlayer(player, map, x, y, z, zoneId[, delay]) - Sends a popup to the player asking if he wants to be summoned if yes, teleported to coords. ZoneID defines the location name shown in the popup Delay is the time until the popup closes automatically.
|
{ "SummonPlayer", &LuaPlayer::SummonPlayer }, // :SummonPlayer(player, map, x, y, z, zoneId[, delay]) - Sends a popup to the player asking if he wants to be summoned if yes, teleported to coords. ZoneID defines the location name shown in the popup Delay is the time until the popup closes automatically.
|
||||||
{ "SaveToDB", &LuaPlayer::SaveToDB }, // :SaveToDB() - Saves to database
|
{ "SaveToDB", &LuaPlayer::SaveToDB }, // :SaveToDB() - Saves to database
|
||||||
#ifdef CLASSIC
|
#ifdef CLASSIC
|
||||||
{"UpdateHonor", &LuaPlayer::UpdateHonor}, // :UpdateHonor() - Updates Player Honor
|
{ "UpdateHonor", &LuaPlayer::UpdateHonor }, // :UpdateHonor() - Updates Player Honor
|
||||||
{"ResetHonor", &LuaPlayer::ResetHonor}, // :ResetHonor() - Resets Player Honor
|
{ "ResetHonor", &LuaPlayer::ResetHonor }, // :ResetHonor() - Resets Player Honor
|
||||||
{"ClearHonorInfo", &LuaPlayer::ClearHonorInfo}, // :ClearHonorInfo() - Clear Player Honor Info
|
{ "ClearHonorInfo", &LuaPlayer::ClearHonorInfo }, // :ClearHonorInfo() - Clear Player Honor Info
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
@@ -1181,13 +1181,20 @@ template<typename T> const char* ElunaTemplate<T>::tname = NULL;
|
|||||||
template<typename T> bool ElunaTemplate<T>::manageMemory = false;
|
template<typename T> bool ElunaTemplate<T>::manageMemory = false;
|
||||||
#if (!defined(TBC) && !defined(CLASSIC))
|
#if (!defined(TBC) && !defined(CLASSIC))
|
||||||
// fix compile error about accessing vehicle destructor
|
// fix compile error about accessing vehicle destructor
|
||||||
template<> int ElunaTemplate<Vehicle>::gcT(lua_State* L) { return 0; }
|
template<> int ElunaTemplate<Vehicle>::gcT(lua_State* L)
|
||||||
|
{
|
||||||
|
// If assert fails, should code mem management here or flag Vehicles not mem managed
|
||||||
|
ASSERT(!manageMemory);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void RegisterFunctions(lua_State* L)
|
void RegisterFunctions(lua_State* L)
|
||||||
{
|
{
|
||||||
RegisterGlobals(L);
|
RegisterGlobals(L);
|
||||||
lua_settop(L, 0); // clean stack
|
|
||||||
|
// You should add sHookMgr->RemoveRef(this); to all destructors for objects that are NOT mem managed (gc) by lua.
|
||||||
|
// Exceptions being Quest type static data structs that will never be destructed (during runtime), though they can have it as well.
|
||||||
|
|
||||||
ElunaTemplate<Object>::Register(L, "Object");
|
ElunaTemplate<Object>::Register(L, "Object");
|
||||||
ElunaTemplate<Object>::SetMethods(L, ObjectMethods);
|
ElunaTemplate<Object>::SetMethods(L, ObjectMethods);
|
||||||
@@ -1263,6 +1270,4 @@ void RegisterFunctions(lua_State* L)
|
|||||||
|
|
||||||
ElunaTemplate<QueryResult>::Register(L, "QueryResult", true);
|
ElunaTemplate<QueryResult>::Register(L, "QueryResult", true);
|
||||||
ElunaTemplate<QueryResult>::SetMethods(L, QueryMethods);
|
ElunaTemplate<QueryResult>::SetMethods(L, QueryMethods);
|
||||||
|
|
||||||
lua_settop(L, 0); // clean stack
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user