Skip to content

Commit

Permalink
重构:移动UObject绑定Lua的逻辑到ObjectRegistry
Browse files Browse the repository at this point in the history
  • Loading branch information
forsakenyang committed Apr 29, 2022
1 parent cc4855d commit d6c2612
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 115 deletions.
94 changes: 0 additions & 94 deletions Plugins/UnLua/Source/UnLua/Private/LuaCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -816,100 +816,6 @@ void PushStructArray(lua_State *L, FProperty *Property, void *Value, const char
PushPropertyArray<FProperty, true>(L, Property, Value, PushStructElement, MetatableName);
}

/**
* Create a Lua instance (table) for a UObject
*/
int32 NewLuaObject(lua_State *L, UObject *Object, const char *ModuleName)
{
check(Object);

int OldTop = lua_gettop(L);

lua_getfield(L, LUA_REGISTRYINDEX, "ObjectMap");
lua_pushlightuserdata(L, Object);
lua_newtable(L); // create a Lua table ('INSTANCE')
PushObjectCore(L, Object); // push UObject ('RAW_UOBJECT')
lua_pushstring(L, "Object");
lua_pushvalue(L, -2);
lua_rawset(L, -4); // INSTANCET.Object = RAW_UOBJECT

// in some case may occur module or object metatable can
// not be found problem
int32 TypeModule = GetLoadedModule(L, ModuleName); // push the required module/table ('REQUIRED_MODULE') to the top of the stack
int32 TypeMetatable = lua_getmetatable(L, -2); // get the metatable ('METATABLE_UOBJECT') of 'RAW_UOBJECT'
if ((TypeModule != LUA_TTABLE)
||(0 == TypeMetatable))
{
lua_pop(L, lua_gettop(L) - OldTop);
return LUA_REFNIL;
}

#if ENABLE_CALL_OVERRIDDEN_FUNCTION
lua_pushstring(L, "Overridden");
lua_pushvalue(L, -2);
lua_rawset(L, -4);
#endif
lua_setmetatable(L, -2); // REQUIRED_MODULE.metatable = METATABLE_UOBJECT
lua_setmetatable(L, -3); // INSTANCE.metatable = REQUIRED_MODULE
lua_pop(L, 1);

// TODO: refactor
const auto Ret = UnLua::FLuaEnv::FindEnvChecked(L).GetObjectRegistry()->Ref(L, Object, -1); // keep a reference for 'INSTANCE'

FUnLuaDelegates::OnObjectBinded.Broadcast(Object); // 'INSTANCE' is on the top of stack now

lua_rawset(L, -3);
lua_pop(L, 1);
return Ret;
}

/**
* Delete the Lua instance (table) for a UObject
*/
void DeleteLuaObject(lua_State *L, UObjectBaseUtility *Object)
{
if (!Object)
{
return;
}

lua_getfield(L, LUA_REGISTRYINDEX, "ObjectMap"); // get the object instance from 'ObjectMap'
lua_pushlightuserdata(L, Object);
int32 Type = lua_rawget(L, -2);
if (Type == LUA_TTABLE || Type == LUA_TUSERDATA)
{
FUnLuaDelegates::OnObjectUnbinded.Broadcast(Object); // object instance ('INSTANCE') is on the top of stack now

// todo: add comments here...
if (Type == LUA_TTABLE)
{
lua_pushstring(L, "Object");
Type = lua_rawget(L, -2);
check(Type == LUA_TUSERDATA);
void *Userdata = lua_touserdata(L, -1);
*((void**)Userdata) = nullptr;
lua_pop(L, 2);
}
else
{
void *Userdata = lua_touserdata(L, -1);
*((void**)Userdata) = nullptr;
lua_pop(L, 1);
}

// INSTANCE.Object = nil
lua_pushlightuserdata(L, Object);
lua_pushnil(L);
lua_rawset(L, -3);
lua_pop(L, 1);
}
else
{
check(Type == LUA_TNIL);
lua_pop(L, 2);
}
}

/**
* Get target UObject and Lua function pointer for a delegate
*/
Expand Down
6 changes: 0 additions & 6 deletions Plugins/UnLua/Source/UnLua/Private/LuaCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,6 @@ void PushStructArray(lua_State *L, FProperty *Property, void *Value, const char
*/
void PushObjectCore(lua_State *L, UObjectBaseUtility *Object);

/**
* Functions to New/Delete Lua instance for UObjectBaseUtility
*/
int32 NewLuaObject(lua_State *L, UObject *Object, const char *ModuleName);
void DeleteLuaObject(lua_State *L, UObjectBaseUtility *Object);

/**
* Get UObject and Lua function address for delegate
*/
Expand Down
84 changes: 75 additions & 9 deletions Plugins/UnLua/Source/UnLua/Private/Registries/ObjectRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "ObjectRegistry.h"

#include "lauxlib.h"
#include "LuaEnv.h"
#include "UnLuaDelegates.h"

static int ReleaseSharedPtr(lua_State* L)
{
Expand All @@ -37,22 +39,86 @@ FObjectRegistry::FObjectRegistry(lua_State* GL)

void FObjectRegistry::NotifyUObjectDeleted(UObject* Object)
{
int32 LuaRef;
if (!ObjectRefs.RemoveAndCopyValue(Object, LuaRef))
return;
luaL_unref(GL, LUA_REGISTRYINDEX, LuaRef);
Unbind(Object);
}

int FObjectRegistry::Ref(lua_State* L, UObject* Object, const int Index)
int FObjectRegistry::Bind(UObject* Object, const char* ModuleName)
{
check(!ObjectRefs.Contains(Object));
lua_pushvalue(L, Index);
const int Ret = luaL_ref(L, LUA_REGISTRYINDEX);
// TODO: remove dependency of module name
if (const auto Exists = ObjectRefs.Find(Object))
return *Exists;

const auto& Env = UnLua::FLuaEnv::FindEnvChecked(GL);
const auto L = Env.GetMainState();

int OldTop = lua_gettop(L);

lua_getfield(L, LUA_REGISTRYINDEX, "ObjectMap");
lua_pushlightuserdata(L, Object);
lua_newtable(L); // create a Lua table ('INSTANCE')
PushObjectCore(L, Object); // push UObject ('RAW_UOBJECT')
lua_pushstring(L, "Object");
lua_pushvalue(L, -2);
lua_rawset(L, -4); // INSTANCE.Object = RAW_UOBJECT

// in some case may occur module or object metatable can
// not be found problem
int32 TypeModule = GetLoadedModule(L, ModuleName); // push the required module/table ('REQUIRED_MODULE') to the top of the stack
int32 TypeMetatable = lua_getmetatable(L, -2); // get the metatable ('METATABLE_UOBJECT') of 'RAW_UOBJECT'
if ((TypeModule != LUA_TTABLE)
|| (0 == TypeMetatable))
{
lua_pop(L, lua_gettop(L) - OldTop);
return LUA_REFNIL;
}

#if ENABLE_CALL_OVERRIDDEN_FUNCTION
lua_pushstring(L, "Overridden");
lua_pushvalue(L, -2);
lua_rawset(L, -4);
#endif
lua_setmetatable(L, -2); // REQUIRED_MODULE.metatable = METATABLE_UOBJECT
lua_setmetatable(L, -3); // INSTANCE.metatable = REQUIRED_MODULE
lua_pop(L, 1);

lua_pushvalue(L, -1);
const auto Ret = luaL_ref(L, LUA_REGISTRYINDEX);
ObjectRefs.Add(Object, Ret);

FUnLuaDelegates::OnObjectBinded.Broadcast(Object); // 'INSTANCE' is on the top of stack now

lua_rawset(L, -3);
lua_pop(L, 1);
return Ret;
}

bool FObjectRegistry::IsBound(UObject* Object)
bool FObjectRegistry::IsBound(const UObject* Object) const
{
return ObjectRefs.Contains(Object);
}

void FObjectRegistry::Unbind(UObject* Object)
{
int32 Ref;
if (!ObjectRefs.RemoveAndCopyValue(Object, Ref))
return;

const auto L = GL;
lua_rawgeti(L, LUA_REGISTRYINDEX, Ref); // get the object instance from 'ObjectMap'

FUnLuaDelegates::OnObjectUnbinded.Broadcast(Object); // object instance ('INSTANCE') is on the top of stack now

lua_pushstring(L, "Object");
lua_rawget(L, -2);
void* Userdata = lua_touserdata(L, -1);
*((void**)Userdata) = nullptr; // TODO: mark as BIT_DELETED_UOBJECT
lua_pop(L, 1);

// INSTANCE.Object = nil
lua_pushlightuserdata(L, Object);
lua_pushnil(L);
lua_rawset(L, -3);
lua_pop(L, 1);

luaL_unref(GL, LUA_REGISTRYINDEX, Ref);
}
18 changes: 15 additions & 3 deletions Plugins/UnLua/Source/UnLua/Private/Registries/ObjectRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,29 @@ class FObjectRegistry
FObjectRegistry(lua_State* GL);

void NotifyUObjectDeleted(UObject* Object);

template <typename T>
void Push(lua_State* L, TSharedPtr<T> Ptr);

template <typename T>
TSharedPtr<T> Get(lua_State* L, int Index);

int Ref(lua_State* L, UObject* Object, const int Index);
/**
* 将一个UObject绑定到Lua环境,作为lua table访问。
* @return lua引用ID
*/
int Bind(UObject* Object, const char* ModuleName);

bool IsBound(UObject* Object);
/**
* 获取一个值,表示UObject是否绑定到了Lua环境。
*/
bool IsBound(const UObject* Object) const;

/**
* 将指定的UObject从Lua环境解绑。
*/
void Unbind(UObject* Object);

private:
TMap<UObject*, int32> ObjectRefs;
lua_State* GL;
Expand Down
4 changes: 1 addition & 3 deletions Plugins/UnLua/Source/UnLua/Private/UnLuaManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ bool UUnLuaManager::Bind(UObject *Object, UClass *Class, const TCHAR *InModuleNa
FString RealModuleName = *ModuleNames.Find(Class);

// create a Lua instance for this UObject
NewLuaObject(L, Object, TCHAR_TO_UTF8(*RealModuleName));
Env->GetObjectRegistry()->Bind(Object, TCHAR_TO_UTF8(*RealModuleName));

// try call user first user function handler
bool bResult = false;
Expand Down Expand Up @@ -164,8 +164,6 @@ void UUnLuaManager::NotifyUObjectDeleted(const UObjectBase *Object, bool bClass)
ClearLoadedModule(Env->GetMainState(), TCHAR_TO_UTF8(*ModuleName));
}
}

DeleteLuaObject(Env->GetMainState(), (UObjectBaseUtility*)Object); // delete the Lua instance (table)
}

/**
Expand Down
1 change: 1 addition & 0 deletions TPSProject.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=UCLASS/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=UFUNCTION/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=UNLUA/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=UOBJECT/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=UPROPERTY/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=upvalue/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>

0 comments on commit d6c2612

Please sign in to comment.