Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changed how data pushed to lua is validated to use weak_ptr #469

Merged
merged 8 commits into from
Jul 13, 2024
82 changes: 72 additions & 10 deletions ElunaTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ extern "C"
#include "Globals/SharedDefines.h"
#endif


#ifdef TRINITY
#include "UniqueTrackablePtr.h"

#define TRACKABLE_PTR_NAMESPACE ::Trinity::
#endif

class ElunaGlobal
{
public:
Expand Down Expand Up @@ -108,47 +115,101 @@ class ElunaObject
}

// Get wrapped object pointer
virtual void* GetObj() const = 0;
// Returns whether the object is valid or not
virtual bool IsValid() const = 0;
virtual void* GetObjIfValid() const = 0;
// Returns pointer to the wrapped object's type name
const char* GetTypeName() const { return type_name; }
#ifndef TRINITY
// Invalidates the pointer if it should be invalidated
virtual void Invalidate() = 0;
#endif

protected:
Eluna* E;
const char* type_name;
};

#ifdef TRINITY
template <typename T>
struct ElunaConstrainedObjectRef
{
TRACKABLE_PTR_NAMESPACE unique_weak_ptr<T> Obj;
Map const* BoundMap = nullptr;
};

ElunaConstrainedObjectRef<Aura> GetWeakPtrFor(Aura const* obj);
ElunaConstrainedObjectRef<Battleground> GetWeakPtrFor(Battleground const* obj);
ElunaConstrainedObjectRef<Group> GetWeakPtrFor(Group const* obj);
ElunaConstrainedObjectRef<Guild> GetWeakPtrFor(Guild const* obj);
ElunaConstrainedObjectRef<Map> GetWeakPtrFor(Map const* obj);
ElunaConstrainedObjectRef<Object> GetWeakPtrForObjectImpl(Object const* obj);
ElunaConstrainedObjectRef<Quest> GetWeakPtrFor(Quest const* obj);
ElunaConstrainedObjectRef<Spell> GetWeakPtrFor(Spell const* obj);
ElunaConstrainedObjectRef<Vehicle> GetWeakPtrFor(Vehicle const* obj);

template <typename T>
ElunaConstrainedObjectRef<T> GetWeakPtrFor(T const* obj)
{
ElunaConstrainedObjectRef<Object> ref = GetWeakPtrForObjectImpl(obj);
return { TRACKABLE_PTR_NAMESPACE static_pointer_cast<T>(ref.Obj), ref.BoundMap };
}

#endif

template <typename T>
class ElunaObjectImpl : public ElunaObject
{
public:
#ifdef TRINITY
ElunaObjectImpl(Eluna* E, T const* obj, char const* tname) : ElunaObject(E, tname), _obj(GetWeakPtrFor(obj))
{
}

void* GetObjIfValid() const override
{
if (TRACKABLE_PTR_NAMESPACE unique_strong_ref_ptr<T> obj = _obj.Obj.lock())
if (!E->GetBoundMap() || !_obj.BoundMap || E->GetBoundMap() == _obj.BoundMap)
return obj.get();

return nullptr;
}
#else
ElunaObjectImpl(Eluna* E, T* obj, char const* tname) : ElunaObject(E, tname), _obj(obj), callstackid(E->GetCallstackId())
{
}

void* GetObj() const override { return _obj; }
bool IsValid() const override { return callstackid == E->GetCallstackId(); }
void* GetObjIfValid() const override
{
if (callstackid == E->GetCallstackId())
return _obj;

return nullptr;
}

void Invalidate() override { callstackid = 1; }
#endif

private:
#ifdef TRINITY
ElunaConstrainedObjectRef<T> _obj;
#else
void* _obj;
uint64 callstackid;
#endif
};

template <typename T>
class ElunaObjectValueImpl : public ElunaObject
{
public:
ElunaObjectValueImpl(Eluna* E, T* obj, char const* tname) : ElunaObject(E, tname), _obj(*obj /*always a copy, what gets passed here might be pointing to something not owned by us*/)
ElunaObjectValueImpl(Eluna* E, T const* obj, char const* tname) : ElunaObject(E, tname), _obj(*obj /*always a copy, what gets passed here might be pointing to something not owned by us*/)
{
}

void* GetObj() const override { return const_cast<T*>(&_obj); }
bool IsValid() const override { return true; }
void* GetObjIfValid() const override { return const_cast<T*>(&_obj); }

#ifndef TRINITY
void Invalidate() override { }
#endif

private:
T _obj;
Expand Down Expand Up @@ -375,7 +436,8 @@ class ElunaTemplate
if (!elunaObj)
return NULL;

if (!elunaObj->IsValid())
void* obj = elunaObj->GetObjIfValid();
if (!obj)
{
char buff[256];
snprintf(buff, 256, "%s expected, got pointer to nonexisting (invalidated) object (%s). Check your code.", tname, luaL_typename(L, narg));
Expand All @@ -389,7 +451,7 @@ class ElunaTemplate
}
return NULL;
}
return static_cast<T*>(elunaObj->GetObj());
return static_cast<T*>(obj);
}

static int GetType(lua_State* L)
Expand Down
8 changes: 4 additions & 4 deletions LuaEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,15 +297,13 @@ void Eluna::RunScripts()
OnLuaStateOpen();
}

#ifndef TRINITY
void Eluna::InvalidateObjects()
{
++callstackid;
#ifdef TRINITY
ASSERT(callstackid, "Callstackid overflow");
#else
ASSERT(callstackid && "Callstackid overflow");
#endif
}
#endif

void Eluna::Report(lua_State* _L)
{
Expand Down Expand Up @@ -989,8 +987,10 @@ void Eluna::CleanUpStack(int number_of_arguments)
lua_pop(L, number_of_arguments + 1); // Add 1 because the caller doesn't know about `event_id`.
// Stack: (empty)

#ifndef TRINITY
if (event_level == 0)
InvalidateObjects();
#endif
}

/*
Expand Down
6 changes: 6 additions & 0 deletions LuaEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,13 @@ class ELUNA_GAME_API Eluna
// Indicates that the lua state should be reloaded
bool reload = false;

#ifndef TRINITY
// A counter for lua event stacks that occur (see event_level).
// This is used to determine whether an object belongs to the current call stack or not.
// 0 is reserved for always belonging to the call stack
// 1 is reserved for a non valid callstackid
uint64 callstackid = 2;
#endif
// A counter for the amount of nested events. When the event_level
// reaches 0 we are about to return back to C++. At this point the
// objects used during the event stack are invalidated.
Expand All @@ -200,7 +202,9 @@ class ELUNA_GAME_API Eluna
void CloseLua();
void DestroyBindStores();
void CreateBindStores();
#ifndef TRINITY
void InvalidateObjects();
#endif

// Use ReloadEluna() to make eluna reload
// This is called on world update to reload eluna
Expand Down Expand Up @@ -345,7 +349,9 @@ class ELUNA_GAME_API Eluna

void RunScripts();
bool HasLuaState() const { return L != NULL; }
#ifndef TRINITY
uint64 GetCallstackId() const { return callstackid; }
#endif
int Register(uint8 reg, uint32 entry, ObjectGuid guid, uint32 instanceId, uint32 event_id, int functionRef, uint32 shots);
void UpdateEluna(uint32 diff);

Expand Down
23 changes: 23 additions & 0 deletions LuaFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,29 @@ extern "C"
#include "VehicleMethods.h"
#include "BattleGroundMethods.h"

#ifdef TRINITY
ElunaConstrainedObjectRef<Aura> GetWeakPtrFor(Aura const* obj) { return { obj->GetWeakPtr(), obj->GetOwner()->GetMap() }; }
ElunaConstrainedObjectRef<Battleground> GetWeakPtrFor(Battleground const* obj) { return { obj->GetWeakPtr(), obj->GetBgMap() }; }
ElunaConstrainedObjectRef<Group> GetWeakPtrFor(Group const* obj) { return { obj->GetWeakPtr(), nullptr }; }
ElunaConstrainedObjectRef<Guild> GetWeakPtrFor(Guild const* obj) { return { obj->GetWeakPtr(), nullptr }; }
ElunaConstrainedObjectRef<Map> GetWeakPtrFor(Map const* obj) { return { obj->GetWeakPtr(), obj }; }
ElunaConstrainedObjectRef<Object> GetWeakPtrForObjectImpl(Object const* obj)
{
if (obj->isType(TYPEMASK_WORLDOBJECT))
return { obj->GetWeakPtr(), static_cast<WorldObject const*>(obj)->GetMap() };

if (obj->GetTypeId() == TYPEID_ITEM)
if (Player const* player = static_cast<Item const*>(obj)->GetOwner())
return { obj->GetWeakPtr(), player->GetMap() };

// possibly dangerous item
return { obj->GetWeakPtr(), nullptr };
}
ElunaConstrainedObjectRef<Quest> GetWeakPtrFor(Quest const* obj) { return { obj->GetWeakPtr(), nullptr }; }
ElunaConstrainedObjectRef<Spell> GetWeakPtrFor(Spell const* obj) { return { obj->GetWeakPtr(), obj->GetCaster()->GetMap() }; }
ElunaConstrainedObjectRef<Vehicle> GetWeakPtrFor(Vehicle const* obj) { return { obj->GetWeakPtr(), obj->GetBase()->GetMap() }; }
#endif

// Template by Mud from http://stackoverflow.com/questions/4484437/lua-integer-type/4485511#4485511
template<> int ElunaTemplate<unsigned long long>::Add(lua_State* L) { Eluna* E = Eluna::GetEluna(L); E->Push(E->CHECKVAL<unsigned long long>(1) + E->CHECKVAL<unsigned long long>(2)); return 1; }
template<> int ElunaTemplate<unsigned long long>::Substract(lua_State* L) { Eluna* E = Eluna::GetEluna(L); E->Push(E->CHECKVAL<unsigned long long>(1) - E->CHECKVAL<unsigned long long>(2)); return 1; }
Expand Down
2 changes: 2 additions & 0 deletions hooks/ServerHooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ void Eluna::OnTimedEvent(int funcRef, uint32 delay, uint32 calls, WorldObject* o
ExecuteCall(4, 0);

ASSERT(!event_level);
#ifndef TRINITY
InvalidateObjects();
#endif
}

void Eluna::OnGameEventStart(uint32 eventid)
Expand Down
3 changes: 1 addition & 2 deletions methods/TrinityCore/AuraMethods.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,9 @@ namespace LuaAura
/**
* Remove this [Aura] from the [Unit] it is applied to.
*/
int Remove(Eluna* E, Aura* aura)
int Remove(Eluna* /*E*/, Aura* aura)
{
aura->Remove();
E->CHECKOBJ<ElunaObject>(1)->Invalidate();
return 0;
}

Expand Down
1 change: 0 additions & 1 deletion methods/TrinityCore/GameObjectMethods.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,6 @@ namespace LuaGameObject
go->SetRespawnTime(0);
go->Delete();

E->CHECKOBJ<ElunaObject>(1)->Invalidate();
return 0;
}

Expand Down
3 changes: 0 additions & 3 deletions methods/TrinityCore/PlayerMethods.h
Original file line number Diff line number Diff line change
Expand Up @@ -3163,10 +3163,7 @@ namespace LuaPlayer
}
else
{
bool all = itemCount >= item->GetCount();
player->DestroyItemCount(item, itemCount, true);
if (all)
E->CHECKOBJ<ElunaObject>(2)->Invalidate();
}
return 0;
}
Expand Down