summaryrefslogtreecommitdiff
path: root/Runtime/Lua/LuaBind
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2021-10-18 19:56:41 +0800
committerchai <chaifix@163.com>2021-10-18 19:56:41 +0800
commit45328cbadd8a946c19a77301f218efbf650e2f28 (patch)
tree8ec4f3a9737b2cbb9744f8347a56783743be2a4c /Runtime/Lua/LuaBind
parentb5702ece4c2cf751c252e76fb885a7ec41ccabe8 (diff)
*misc
Diffstat (limited to 'Runtime/Lua/LuaBind')
-rw-r--r--Runtime/Lua/LuaBind/LuaBind.h18
-rw-r--r--Runtime/Lua/LuaBind/LuaBindCFunctions.cpp19
-rw-r--r--Runtime/Lua/LuaBind/LuaBindCFunctions.h38
-rw-r--r--Runtime/Lua/LuaBind/LuaBindClass.cpp243
-rw-r--r--Runtime/Lua/LuaBind/LuaBindClass.hpp208
-rw-r--r--Runtime/Lua/LuaBind/LuaBindClass.inc632
-rw-r--r--Runtime/Lua/LuaBind/LuaBindConfig.h65
-rw-r--r--Runtime/Lua/LuaBind/LuaBindEnum.cpp67
-rw-r--r--Runtime/Lua/LuaBind/LuaBindEnum.h39
-rw-r--r--Runtime/Lua/LuaBind/LuaBindGlobalState.h7
-rw-r--r--Runtime/Lua/LuaBind/LuaBindInternal.h12
-rw-r--r--Runtime/Lua/LuaBind/LuaBindMemberRef.cpp16
-rw-r--r--Runtime/Lua/LuaBind/LuaBindMemberRef.h27
-rw-r--r--Runtime/Lua/LuaBind/LuaBindRef.cpp72
-rw-r--r--Runtime/Lua/LuaBind/LuaBindRef.h62
-rw-r--r--Runtime/Lua/LuaBind/LuaBindRefTable.cpp120
-rw-r--r--Runtime/Lua/LuaBind/LuaBindRefTable.h67
-rw-r--r--Runtime/Lua/LuaBind/LuaBindState.cpp893
-rw-r--r--Runtime/Lua/LuaBind/LuaBindState.h266
-rw-r--r--Runtime/Lua/LuaBind/LuaBindState.inc180
-rw-r--r--Runtime/Lua/LuaBind/LuaBindUtility.h69
-rw-r--r--Runtime/Lua/LuaBind/LuaBindVM.cpp82
-rw-r--r--Runtime/Lua/LuaBind/LuaBindVM.h58
-rw-r--r--Runtime/Lua/LuaBind/LuaBindWatchDog.cpp0
-rw-r--r--Runtime/Lua/LuaBind/LuaBindWatchDog.h33
25 files changed, 3293 insertions, 0 deletions
diff --git a/Runtime/Lua/LuaBind/LuaBind.h b/Runtime/Lua/LuaBind/LuaBind.h
new file mode 100644
index 0000000..1494b5c
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBind.h
@@ -0,0 +1,18 @@
+#ifndef __LUA_BIND_H__
+#define __LUA_BIND_H__
+
+//
+// (port) library 用于给lua注册类和函数
+//
+
+#include "LuaBindState.h"
+#include "LuaBindVM.h"
+#include "LuaBindRef.h"
+#include "LuaBindRefTable.h"
+#include "LuaBindEnum.h"
+#include "LuaBindClass.hpp"
+#include "LuaBindMemberRef.h"
+#include "LuaBindClass.inc"
+#include "LuaBindState.inc"
+
+#endif \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindCFunctions.cpp b/Runtime/Lua/LuaBind/LuaBindCFunctions.cpp
new file mode 100644
index 0000000..ca662a3
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindCFunctions.cpp
@@ -0,0 +1,19 @@
+#include "LuaBindCFunctions.h"
+#include "LuaBindConfig.h"
+
+namespace LuaBind
+{
+
+ int luax_c_getupvalue(lua_State* L)
+ {
+ lua_pushvalue(L, lua_upvalueindex(1));
+ return 1;
+ }
+
+ int luax_c_errfunc(lua_State* L)
+ {
+ cc8* msg = luaL_optstring(L, lua_upvalueindex(1), "");
+ return luaL_error(L, msg);
+ }
+
+} \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindCFunctions.h b/Runtime/Lua/LuaBind/LuaBindCFunctions.h
new file mode 100644
index 0000000..f0f07dd
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindCFunctions.h
@@ -0,0 +1,38 @@
+#ifndef __LUA_BIND_CFUNCTIONS_H__
+#define __LUA_BIND_CFUNCTIONS_H__
+
+#include "LuaBindConfig.h"
+
+/**
+ * luax_cfunction里的函数用来注册给lua,一些特殊功能的通用函数。
+*/
+
+namespace
+{
+
+ // 获得第一个upvalue
+ extern int luax_c_getupvalue(lua_State* L);
+
+ // 调用此函数时会报错,upvalue(1)是错误信息
+ extern int luax_c_errfunc(lua_State* L);
+
+#define luax_is(T, L, i) (lua_is##T(L, i))
+#define luax_isnumber(L, i) luax_is(number, L, i)
+
+ inline int luax_isinteger(lua_State* L, int i)
+ {
+ if (!luax_isnumber(L, i))
+ return 0;
+ return lua_tonumber(L, i) == lua_tointeger(L, i);
+ }
+
+ inline int luax_isfloat(lua_State* L, int i)
+ {
+ if (!luax_isnumber(L, i))
+ return 0;
+ return lua_tonumber(L, i) != lua_tointeger(L, i);
+ }
+
+}
+
+#endif \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindClass.cpp b/Runtime/Lua/LuaBind/LuaBindClass.cpp
new file mode 100644
index 0000000..7fd603c
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindClass.cpp
@@ -0,0 +1,243 @@
+#include "LuaBindClass.hpp"
+#include "LuaBindCFunctions.h"
+#include "LuaBindVM.h"
+
+namespace LuaBind
+{
+
+#if LUA_BIND_ENABLE_PLAIN_CLASS
+
+ int PlainClass::registry(lua_State* L)
+ {
+ LUA_BIND_STATE(L);
+
+ // params:
+ // 1: class name
+
+ cc8* type = state.GetValue<cc8*>(1, "");
+
+ lua_newtable(L); // class table
+
+ // GetClassName()
+ lua_pushstring(L, type);
+ lua_pushcclosure(L, luax_c_getupvalue, 1);
+ lua_setfield(L, -2, "GetClassName");
+
+ // GetClass()
+ lua_pushvalue(L, -1); // class table
+ lua_pushcclosure(L, luax_c_getupvalue, 1);
+ lua_setfield(L, -2, "GetClass");
+
+ // TypeOf()
+ lua_pushcfunction(L, _TypeOf);
+ lua_setfield(L, -2, "TypeOf");
+
+ // New()
+ lua_pushvalue(L, -1); // class table
+ lua_pushcclosure(L, _New, 1);
+ lua_setfield(L, -2, "New");
+
+ // Extend()
+ lua_pushvalue(L, -1); // class table
+ lua_pushcclosure(L, _Extend, 1);
+ lua_setfield(L, -2, "Extend");
+
+ lua_pushvalue(L, -1); // class table
+ lua_setfield(L, -2, "__index");
+
+ lua_pushstring(L, type);
+ lua_pushcclosure(L, __tostring, 1);
+ lua_setfield(L, -2, "__tostring");
+
+ return 1;
+ }
+
+ int PlainClass::__tostring(lua_State* L)
+ {
+ // upvalues:
+ // 1: class name
+
+ // params:
+ // 1: instance
+
+ if (!lua_istable(L, 1))
+ {
+ return luaL_typerror(L, 1, lua_typename(L, LUA_TTABLE));
+ }
+
+ cc8* type = lua_tostring(L, lua_upvalueindex(1));
+
+ lua_pushfstring(L, "%s: %p", type, lua_topointer(L, 1));
+
+ return 1;
+ }
+
+ //
+ // New函数接受n个参数,并尝试获取__init,将参数传给__init初始化实例。
+ //
+ int PlainClass::_New(lua_State* L)
+ {
+ LUA_BIND_STATE(L);
+
+ // upvalues:
+ // 1: class table
+
+ // params:
+ // n: params
+ int n = lua_gettop(L);
+
+ int classTable = lua_upvalueindex(1);
+
+ lua_newtable(L); // instance table
+
+ // instance 的 metatable 设置为 class
+ lua_pushvalue(L, classTable);
+ lua_setmetatable(L, -2);
+
+ // 找到构造函数,会触发metatable.__index,根据继承链向上找。
+ lua_getfield(L, classTable, "__init");
+ if (state.IsType(-1, LUA_TFUNCTION))
+ {
+ // stack:
+ // -1: __init()
+ // -2: instance
+ // -3~-n-2: params
+
+ lua_insert(L, -2 - n);
+ // stack:
+ // -1: instance
+ // -2~-n-1: params
+ // -n-2: __init()
+
+ lua_pushvalue(L, -1);
+ // stack:
+ // -1: instance
+ // -2: instance
+ // -3~-n-2: params
+ // -n-3: __init
+
+ lua_insert(L, -3 - n);
+ // stack:
+ // -1: instance
+ // -2~-n-1: params
+ // -n-2: __init()
+ // -n-3: instance
+
+ lua_insert(L, -1 - n);
+ // stack:
+ // -1~-n: params
+ // -n-1: instance
+ // -n-2: __init()
+ // -n-3: instance
+
+ lua_pcall(L, n + 1, 0, 0);
+ }
+ else
+ {
+ state.Pop();
+ }
+
+ return 1;
+ }
+
+ int PlainClass::_Extend(lua_State* L)
+ {
+ LUA_BIND_STATE(L);
+
+ // upvalues:
+ // 1: base class
+
+ // params:
+ // 1: class name
+
+ cc8* type = state.GetValue<cc8*>(1, "");
+
+ int baseClass = lua_upvalueindex(1);
+
+ lua_newtable(L); // class table
+
+ // GetClassName()
+ lua_pushstring(L, type);
+ lua_pushcclosure(L, luax_c_getupvalue, 1);
+ lua_setfield(L, -2, "GetClassName");
+
+ // GetClass()
+ lua_pushvalue(L, -1); // class table
+ lua_pushcclosure(L, luax_c_getupvalue, 1);
+ lua_setfield(L, -2, "GetClass");
+
+ // New()
+ lua_pushvalue(L, -1); // class table
+ lua_pushcclosure(L, _New, 1);
+ lua_setfield(L, -2, "New");
+
+ // Extend()
+ lua_pushvalue(L, -1); // class table
+ lua_pushcclosure(L, _Extend, 1);
+ lua_setfield(L, -2, "Extend");
+
+ // .__base 用来索引到基类
+ lua_pushvalue(L, baseClass); // base class
+ lua_setfield(L, -2, "__base");
+
+ lua_pushvalue(L, -1); // class table
+ lua_setfield(L, -2, "__index");
+
+ lua_pushstring(L, type);
+ lua_pushcclosure(L, __tostring, 1);
+ lua_setfield(L, -2, "__tostring");
+
+ // class的metatable设置为baseClass
+ lua_pushvalue(L, baseClass);
+ lua_setmetatable(L, -2);
+
+ return 1;
+ }
+
+ int PlainClass::_TypeOf(lua_State* L)
+ {
+ // params:
+ // 1: lua instance
+ // 2: type string
+
+ LUA_BIND_STATE(L);
+
+ cc8* type = state.GetValue<cc8*>(2, "");
+
+ if (!lua_istable(L, 1))
+ {
+ return luaL_typerror(L, 1, "Object");
+ }
+
+ lua_pushvalue(L, 1); // lua instance
+
+ while (lua_getmetatable(L, -1))
+ {
+ lua_getfield(L, -1, "GetClassName");
+ if (lua_isfunction(L, -1))
+ {
+ state.Call(0, 1);
+ cc8* name = state.GetValue<cc8*>(-1, "");
+ if (strcmp(name, type) == 0)
+ {
+ lua_pushboolean(L, true);
+ return 1;
+ }
+ else
+ {
+ state.Pop(); // name
+ }
+ }
+ else
+ {
+ state.Pop();
+ }
+ }
+
+ lua_pushboolean(L, false);
+ return 1;
+ }
+
+#endif /*LUA_BIND_ENABLE_PLAIN_CLASS*/
+
+} \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindClass.hpp b/Runtime/Lua/LuaBind/LuaBindClass.hpp
new file mode 100644
index 0000000..2bf1451
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindClass.hpp
@@ -0,0 +1,208 @@
+#ifndef __LUA_BIND_CLASS_H__
+#define __LUA_BIND_CLASS_H__
+
+#include "LuaBindConfig.h"
+
+#if LUA_BIND_PROFILER
+#include <unordered_set>
+#endif
+
+#include <vector>
+
+#include "LuaBindRef.h"
+#include "LuaBindMemberRef.h"
+#include "LuaBindCFunctions.h"
+#include "LuaBindWatchDog.h"
+#include "LuaBindUtility.h"
+
+namespace LuaBind
+{
+
+ class VM;
+
+ //
+ // 虚基类,为了实现多态。需要访问下面这些接口的外部基类需要虚继承此类,之后再派生链中就会
+ // 调用对应实体的方法。注意继承此类时不能实现下面的方法,实现在NativeClass中,实现会
+ // 导致二义性。
+ //
+ // 依据Effective C++条款40,如果在必须使用virtual base基类情况下,应该尽可能避免向其中放
+ // 置数据成员,规避数据成员初始化造成的一些隐性问题。依据这一点,vpb基类更加接近C#和Java中
+ // 的Interface。所以,在这里把类用I开头标识这是一个接口。
+ //
+ class Object
+ {
+ public:
+ Object() {};
+ virtual ~Object() {};
+
+ //
+ // 成员引用管理,在实例的ref table里。设置、取、清除。
+ //
+ virtual bool PushMemberRef(State& state, int refID) = 0;
+ virtual bool PushUserdata(State& state) = 0;
+ virtual bool PushMemberTable(State& state) = 0;
+ virtual bool PushRefTable(State& state) = 0;
+
+ //
+ // 被NativeClass实现。保持和释放native资源。
+ //
+ virtual void Retain() = 0;
+ virtual void Release() = 0;
+
+ };
+
+ // TODO: 将公共部分提取出来,不要重复生成代码
+ //class NativeClassBase
+ //{
+ //}
+
+ //
+ // 需要暴露给lua的native class需要继承此类。通过lua管理的实例要确保引用计数的正确性,在多个线程中需要确
+ // 定不会误释放。
+ //
+ template<class TYPE, class BASE = Object>
+ class NativeClass : public BASE
+ {
+ public:
+
+ //
+ // 将userdata作为key,在ref table里对userdata添加一个引用,以维持userdata的生命周期。
+ // 相比较member ref,这个用在实体会被多次被不同其他实体引用的情况,并频繁销毁这些实体,
+ // 避免lua频繁的调用gc检测。
+ //
+ template<class DATATYPE> void Retain(State& state, DATATYPE* userdata);
+
+ //
+ // 对userdata减少一个引用在ref table里,以尝试回收userdata。
+ //
+ template<class DATATYPE> void Release(State& state, DATATYPE* userdata);
+
+ //
+ // 将userdata push到栈顶,如果没有初始化mUserdata,初始化设置好元表并把初始化好的
+ // userdata留在栈顶。并添加一个引用。这是一个将native对象所有权移交给lua控制的方法。
+ //
+ bool PushMemberRef(State& state, int refID) override;
+ bool PushUserdata(State& state) override;
+ bool PushMemberTable(State& state) override;
+ bool PushRefTable(State& state) override;
+
+ //
+ // WatchDog添加一个native引用。luaVM引用不会提供外部接口。继承此类的派生类不能直接使用
+ // delete方法,应该使用Release释放。一般情况下这个操作由虚拟机__gc进行,但是允许用户
+ // 程序在native中隔绝虚拟机情况下释放,这种情况下要使用Release。
+ //
+ // 这两个函数是native接口。
+ //
+ void Retain() override final;
+ void Release() override final;
+
+#if LUA_BIND_PROFILER
+ // 对堆上创建的实例进行delete保险检查
+ static void operator delete(void* pdead, size_t size);
+#endif
+
+ protected:
+
+ NativeClass();
+ virtual ~NativeClass();
+
+ //
+ // 成员引用管理,在实例的ref table里。设置、取、清除
+ //
+ void SetMemberRef(State& state, MemberRef& memRef, int idx);
+ bool PushMemberRef(State& state, MemberRef& memRef);
+ void ClearMemberRef(State& state, MemberRef& memRef);
+
+ private:
+
+ friend class State;
+
+ static void RegisterClassShared(State& state);
+ static void RegisterFactoryClass(State& state);
+ static void RegisterSingletonClass(State& state);
+
+ static void SetClassTableRef(State& state, int idx);
+ static void PushClassTable(State& state);
+
+ //
+ // 创建userdata,绑定实例到state。
+ //
+ void BindToLua(State& state);
+
+ //------------------------------------------------------------------------------//
+
+ // 公共内容
+ static int __tostring (lua_State*);
+ static int _GetClass (lua_State*);
+ static int _GetClassName (lua_State*);
+
+ // 工厂类相关
+ static int __gc (lua_State*);
+ static int _GetRefTable (lua_State*);
+
+#if LUA_BIND_ENABLE_NATIVE_EXTEND
+ static int _New(lua_State*);
+
+ static int _ExtendFactory (lua_State*);
+ static int _ExtendSingleton (lua_State*);
+#endif
+
+ //--------------------------------------------------------------------------------//
+
+ //
+ // class table,工厂和单例都有。
+ //
+ static StrongRef mClassTable;
+
+ //
+ // 如果类是单例,这个用来保存singleton的引用关系,以保证不会被回收类似普通类的ref table。
+ // 单例的成员是全生命周期的,所以直接在_LUA_BIND_STRONGREF_TABLE。单例对userdata进行
+ // Retain\Release和member ref操作时和工厂实例不同,是存在下面这个ref table里
+ // 的,这个table在_LUA_BIND_STRONGREF_TABLE里。
+ //
+ static StrongRef mSingletonRefTable;
+
+ //
+ // 通过userdata可以拿到:
+ // 1: ref table
+ // 2: member table
+ // 3: class table
+ //
+ WeakRef mUserdata;
+
+ // 通过后才能删除
+ WatchDog mWatchDog;
+
+#if LUA_BIND_PROFILER
+ // 托管此对象的虚拟机
+ std::unordered_set<VM*> mRefVMs;
+ // 保险,此类的派生类不能在外部使用delete直接删除,而应该使用Release
+ bool mSafer;
+#endif
+
+ };
+
+#if LUA_BIND_ENABLE_PLAIN_CLASS
+ //
+ // 纯lua类
+ //
+ class PlainClass
+ {
+ public:
+
+ //
+ // 用来注册类的入口函数。可以通过registry(类名)注册类。
+ //
+ static int registry(lua_State* L);
+
+ LUA_BIND_DECL_METHOD(__tostring);
+ LUA_BIND_DECL_METHOD(_Extend);
+ LUA_BIND_DECL_METHOD(_New);
+ LUA_BIND_DECL_METHOD(_TypeOf);
+
+ };
+#endif
+
+}
+
+#endif \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindClass.inc b/Runtime/Lua/LuaBind/LuaBindClass.inc
new file mode 100644
index 0000000..05bd9c7
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindClass.inc
@@ -0,0 +1,632 @@
+namespace LuaBind
+{
+
+ //--------------------------------------------------------------------------------//
+
+ //
+ // 对不同类型,通过调用GetLuaClassName获得类型名,如果是派生类,GetClassName会被覆盖,指向luax_c_getupvalue。
+ //
+ template<class TYPE, class BASE>
+ int NativeClass<TYPE, BASE>::_GetClassName(lua_State* L)
+ {
+ LUA_BIND_SETUP(L, "*");
+
+ cc8* type = TYPE::GetClassName();
+ state.Push(type);
+ return 1;
+ }
+
+ //--------------------------------------------------------------------------------//
+
+ //
+ // 注册工厂和单例共有的类成员
+ //
+ template<class TYPE, class BASE>
+ void NativeClass<TYPE, BASE>::RegisterClassShared(State& state)
+ {
+ luaL_Reg regTable[] = {
+ { "GetClass", _GetClass },
+ { "GetClassName", _GetClassName },
+ { NULL, NULL }
+ };
+
+ state.RegisterMethods(regTable);
+ }
+
+ //
+ // 工厂类的成员,注册在class table
+ //
+ template<class TYPE, class BASE>
+ void NativeClass<TYPE, BASE>::RegisterFactoryClass(State& state)
+ {
+ luaL_Reg regTable[] = {
+ { "GetRefTable", _GetRefTable },
+ { NULL, NULL }
+ };
+
+ state.RegisterMethods(regTable);
+ }
+
+ //
+ // 单例类的成员,注册在class table
+ //
+ template<class TYPE, class BASE>
+ void NativeClass<TYPE, BASE>::RegisterSingletonClass(State& state)
+ {
+ luaL_Reg regTable[] = {
+ { NULL, NULL }
+ };
+
+ state.RegisterMethods(regTable);
+ }
+
+ template<class TYPE, class BASE>
+ void NativeClass<TYPE, BASE>::PushClassTable(State& state)
+ {
+ assert(mClassTable);
+
+ mClassTable.PushRef(state);
+ }
+
+ template<class TYPE, class BASE>
+ void NativeClass<TYPE, BASE>::SetClassTableRef(State& state, int idx)
+ {
+ mClassTable.SetRef(state, idx);
+ }
+
+ template<class TYPE, class BASE>
+ NativeClass<TYPE, BASE>::NativeClass()
+ : mWatchDog()
+#if LUA_BIND_PROFILER
+ , mSafer(false)
+#endif
+ {
+ }
+
+ template<class TYPE, class BASE>
+ NativeClass<TYPE, BASE>::~NativeClass()
+ {
+ }
+
+#if LUA_BIND_PROFILER
+ template<class TYPE, class BASE>
+ void NativeClass<TYPE, BASE>::operator delete(void* pdead, size_t size)
+ {
+ if (pdead == nullptr)
+ return;
+ // 堆上创建的实例必须使用Release释放。
+ TYPE* p = static_cast<TYPE*>(pdead);
+ assert(p->mSafer);
+ ::operator delete(pdead, size);
+ }
+#endif
+
+ template<class TYPE, class BASE>
+ void NativeClass<TYPE, BASE>::Retain()
+ {
+ ++mWatchDog.mNativeRef;
+ }
+
+ template<class TYPE, class BASE>
+ void NativeClass<TYPE, BASE>::Release()
+ {
+ if (mWatchDog.mNativeRef > 0)
+ --mWatchDog.mNativeRef;
+ if (mWatchDog)
+ {
+#if LUA_BIND_PROFILER
+ mSafer = true;
+#endif
+ delete this;
+ }
+ }
+
+ template<class TYPE, class BASE>
+ template<typename U>
+ void NativeClass<TYPE, BASE>::Retain(State& state, U* userdata)
+ {
+ if (PushRefTable(state))
+ {
+ if (userdata->PushUserdata(state))
+ {
+ lua_pushvalue(state, -1); // copy the userdata
+ lua_gettable(state, -3); // get the count (or nil)
+ u32 count = state.GetValue<u32>(-1, 0); // get the count (or 0)
+ lua_pop(state, 1); // pop the old count
+ lua_pushnumber(state, count + 1); // push the new count
+ lua_settable(state, -3); // save it in the table: reftable[userdata] = count
+ }
+ }
+ }
+
+ template<class TYPE, class BASE>
+ template<typename U>
+ void NativeClass<TYPE, BASE>::Release(State& state, U* userdata)
+ {
+ if (PushRefTable(state))
+ {
+ if (userdata->PushUserdata(state))
+ {
+ lua_pushvalue(state, -1); // copy the userdata
+ lua_gettable(state, -3); // get the count (or nil)
+ u32 count = state.GetValue<u32>(-1, 0); // get the count (or 0)
+ lua_pop(state, 1); // pop the old count
+
+ // no such reference
+ if (count == 0)
+ {
+ state.Pop(2); // userdata, reftable
+ return; // nothing to do
+ }
+
+ if (count > 1) {
+ lua_pushnumber(state, count - 1); // push the new count
+ }
+ else {
+ lua_pushnil(state); // maybe cause gc
+ }
+ lua_settable(state, -3); // save it in the table
+
+ state.Pop(1); // reftable
+ return;
+ }
+ state.Pop(2); // nil, reftable
+ return;
+ }
+ }
+
+ template<class TYPE, class BASE>
+ bool NativeClass<TYPE, BASE>::PushUserdata(State& state)
+ {
+ assert(!TYPE::IsClassSingleton());
+ if (!mUserdata)
+ {
+ BindToLua(state);
+ return true;
+ }
+ return mUserdata.PushRef(state);
+ }
+
+ template<class TYPE, class BASE>
+ bool NativeClass<TYPE, BASE>::PushMemberTable(State& state)
+ {
+ int top = state.GetTop();
+ if (this->PushUserdata(state))
+ {
+ if (lua_getmetatable(state, -1)) // ref table
+ {
+ lua_replace(state, -2);
+ if (lua_getmetatable(state, -1)) // member table
+ {
+ lua_replace(state, -2);
+ return true;
+ }
+ }
+ }
+ lua_settop(state, top);
+ lua_pushnil(state);
+ return false;
+ }
+
+ template<class TYPE, class BASE>
+ bool NativeClass<TYPE, BASE>::PushRefTable(State& state)
+ {
+ // Singleton
+ if (TYPE::IsClassSingleton())
+ {
+ if (!this->mSingletonRefTable) {
+ lua_newtable(state);
+ this->mSingletonRefTable.SetRef(state, -1); // strong ref to member table won't be garbage collected
+ }
+ else {
+ this->mSingletonRefTable.PushRef(state);
+ }
+ return true;
+ }
+ // Factory
+ else
+ {
+ if (this->PushUserdata(state))
+ {
+ if (lua_getmetatable(state, -1))
+ {
+ lua_replace(state, -2);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // 创建userdata,并以此添加ref table,member table和class table。
+ // ref table 是kv强引用table,保存对其他userdata的引用计数(通过userdata作为key,
+ // 计数为value),以及成员引用
+ // member table 保存lua创建的实例的成员
+ // class table 所有本类型的实例共有的函数表
+ //
+ // BindToLua只会在第一次注册给Lua虚拟机时调用。
+ template<class TYPE, class BASE>
+ void NativeClass<TYPE, BASE>::BindToLua(State& state)
+ {
+ // 单例不能绑定userdata
+ assert(!TYPE::IsClassSingleton());
+ assert(!mUserdata);
+
+ // 创建userdata并留在栈顶,注意地址要转换为TYPE*,直接用this可能会导致多重继承的类丧失多态。
+ // 如果直接传this进去,在多重继承情况下,是拿不到另一头的虚函数表的。所以这里需要将this
+ // 转换为整个对象的低地址,这样可以拿到另一个基类的虚函数表,通过另一个基类实现多态。
+ TYPE* p = static_cast<TYPE*>(this);
+ state.PushPtrUserdata(p);
+
+ lua_newtable(state); // ref table,无法在lua处访问,用来管理C对象的生命周期
+ lua_newtable(state); // member table,lua中创建的对象成员都保存在这里
+ PushClassTable(state); // class table
+
+ // stack:
+ // -1: class table
+ // -2: member table
+ // -3: ref table
+ // -4: userdata
+
+ int top = state.GetTop();
+ int memberTable = top - 1;
+ int refTable = top - 2;
+
+ // ref table 注册 __tostring 和 __gc
+ lua_pushcfunction(state, __tostring);
+ lua_setfield(state, refTable, "__tostring");
+
+ lua_pushcfunction(state, __gc);
+ lua_setfield(state, refTable, "__gc");
+
+ // ref table 的 __index 和 __newindex 设为 member table
+ lua_pushvalue(state, memberTable);
+ lua_setfield(state, refTable, "__index");
+
+ lua_pushvalue(state, memberTable);
+ lua_setfield(state, refTable, "__newindex");
+
+ // 设置元表
+ lua_setmetatable(state, -2); // class is meta of member
+ lua_setmetatable(state, -2); // member is meta of ref
+ lua_setmetatable(state, -2); // ref is meta of userdata
+
+ // 设置一个userdata的弱引用,方便通过PushLuaUserdata方法返回lua对象
+ mUserdata.SetRef(state, -1);
+ assert(mUserdata);
+
+ // 增加一个虚拟机引用,在GC时-1
+ ++mWatchDog.mVMRef;
+#if LUA_BIND_PROFILER
+ mRefVMs.insert(state.GetVM());
+#endif
+ }
+
+ //
+ // 成员引用管理
+ //
+ template<class TYPE, class BASE>
+ void NativeClass<TYPE, BASE>::SetMemberRef(State& state, MemberRef& memRef, int idx)
+ {
+ ClearMemberRef(state, memRef);
+ if (!lua_isnil(state, idx))
+ {
+ idx = state.AbsIndex(idx);
+ if (PushRefTable(state))
+ {
+ lua_pushvalue(state, idx);
+ memRef.refID = luaL_ref(state, -2);
+ state.Pop(); // ref table
+ }
+ }
+ }
+
+ template<class TYPE, class BASE>
+ bool NativeClass<TYPE, BASE>::PushMemberRef(State& state, MemberRef& memRef)
+ {
+ if (memRef)
+ {
+ if (PushRefTable(state))
+ {
+ lua_rawgeti(state, -1, memRef.refID);
+ lua_replace(state, -2); // ref table
+ if (lua_isnil(state, -1))
+ goto failed;
+ return true;
+ }
+ }
+ lua_pushnil(state);
+ failed:
+ memRef.refID = LUA_NOREF;
+ return false;
+ }
+
+ template<class TYPE, class BASE>
+ bool NativeClass<TYPE, BASE>::PushMemberRef(State& state, int refID)
+ {
+ if (PushRefTable(state))
+ {
+ lua_rawgeti(state, -1, refID);
+ lua_replace(state, -2); // ref table
+ if (lua_isnil(state, -1))
+ goto failed;
+ return true;
+ }
+ lua_pushnil(state);
+ failed:
+ return false;
+ }
+
+ template<class TYPE, class BASE>
+ void NativeClass<TYPE, BASE>::ClearMemberRef(State& state, MemberRef& memRef)
+ {
+ if (memRef)
+ {
+ if (PushRefTable(state))
+ {
+ luaL_unref(state, -1, memRef.refID);
+ state.Pop(); // ref table
+ }
+ memRef.refID = LUA_NOREF;
+ }
+ }
+
+ //--------------------------------------------------------------------------------//
+
+ //
+ // 释放工厂创建的实例
+ //
+ template<class TYPE, class BASE>
+ int NativeClass<TYPE, BASE>::__gc(lua_State* L)
+ {
+ LUA_BIND_STATE(L);
+
+ TYPE* self = state.GetUserdata<TYPE>(1);
+ assert(self);
+
+#if LUA_BIND_PROFILER
+ std::cout << ": GC<" << TYPE::GetClassName() << ">\n";
+#endif
+
+ if(self->mWatchDog.mVMRef > 0)
+ --self->mWatchDog.mVMRef;
+
+ self->Release();
+
+ return 0;
+ }
+
+ //
+ // 输出格式如下:
+ // 地址 类名
+ //
+ template<class TYPE, class BASE>
+ int NativeClass<TYPE, BASE>::__tostring(lua_State* L)
+ {
+ // params:
+ // 1: userdata
+
+ LUA_BIND_STATE(L);
+ TYPE* self = state.GetUserdata<TYPE>(1);
+ if (self)
+ {
+ cc8* classname = "";
+ lua_getfield(state, 1, "GetClassName");
+ if (state.IsType(-1, LUA_TFUNCTION))
+ {
+ lua_pushvalue(L, 1); // userdata
+ state.Call(1, 1); // 派生类的GetClassName函数
+ classname = state.GetValue<cc8*>(-1, "");
+ }
+ else
+ {
+ classname = TYPE::GetClassName();
+ }
+ lua_pushfstring(L, "%s: %p", classname, self);
+ return 1;
+ }
+ return 0;
+ }
+
+#if LUA_BIND_ENABLE_NATIVE_EXTEND
+ // 派生出子类,在lua里对派生类的成员和行为进行重新设计,但是保证了userdata的统一。Native class的派生提供__init支持,在
+ // native实体创建后可以使用__init进行初始化,派生类拥有和基类一样的New参数列表,且native对象是一样的类型。
+ template<class TYPE, class BASE>
+ int NativeClass<TYPE, BASE>::_ExtendFactory(lua_State* L)
+ {
+ // upvalues:
+ // 1: base class
+
+ // params:
+ // 1: class name
+
+ int baseClass = lua_upvalueindex(1);
+
+ lua_newtable(L); // class table
+
+ int inheritClass = lua_gettop(L);
+
+ // .GetClassName()
+ cc8* type = lua_tostring(L, 1);
+ lua_pushstring(L, type);
+ lua_pushcclosure(L, luax_c_getupvalue, 1);
+ lua_setfield(L, -2, "GetClassName");
+
+ // .GetClass()
+ lua_pushvalue(L, inheritClass);
+ lua_pushcclosure(L, luax_c_getupvalue, 1);
+ lua_setfield(L, -2, "GetClass");
+
+ // .Extend()
+ lua_pushvalue(L, inheritClass);
+ lua_pushcclosure(L, _ExtendFactory, 1);
+ lua_setfield(L, -2, "Extend");
+
+ // .New()
+ lua_pushvalue(L, inheritClass);
+ lua_getfield(L, baseClass, "New");
+ lua_pushcclosure(L, _New, 2);
+ lua_setfield(L, -2, "New");
+
+ // __base = baseClass
+ lua_pushvalue(L, baseClass);
+ lua_setfield(L, -2, "__base");
+
+ // __index = inheritClass
+ lua_pushvalue(L, inheritClass);
+ lua_setfield(L, -2, "__index");
+
+ // metatable is baseClass
+ lua_pushvalue(L, baseClass);
+ lua_setmetatable(L, inheritClass);
+
+ return 1;
+ }
+
+ template<class TYPE, class BASE>
+ int NativeClass<TYPE, BASE>::_ExtendSingleton(lua_State* L)
+ {
+ // upvalues:
+ // 1: base class
+
+ // params:
+ // 1: class name
+
+ int baseClass = lua_upvalueindex(1);
+
+ lua_newtable(L); // class name
+
+ int inheritClass = lua_gettop(L);
+
+ // .GetClassName()
+ cc8* type = lua_tostring(L, 1);
+ lua_pushstring(L, type);
+ lua_pushcclosure(L, luax_c_getupvalue, 1);
+ lua_setfield(L, -2, "GetClassName");
+
+ // .GetClass()
+ lua_pushvalue(L, inheritClass);
+ lua_pushcclosure(L, luax_c_getupvalue, 1);
+ lua_setfield(L, -2, "GetClass");
+
+ // .Extend()
+ lua_pushvalue(L, inheritClass);
+ lua_pushcclosure(L, _ExtendFactory, 1);
+ lua_setfield(L, -2, "Extend");
+
+ // __base = baseClass
+ lua_pushvalue(L, baseClass);
+ lua_setfield(L, -2, "__base");
+
+ // __index = inheritClass
+ lua_pushvalue(L, inheritClass);
+ lua_setfield(L, -2, "__index");
+
+ // metatable is baseClass
+ lua_pushvalue(L, baseClass);
+ lua_setmetatable(L, inheritClass);
+
+ return 1;
+ }
+
+ template<class TYPE, class BASE>
+ int NativeClass<TYPE, BASE>::_New(lua_State* L)
+ {
+ LUA_BIND_STATE(L);
+
+ // upvalues:
+ // 1: class table
+ // 2: original New()
+
+ // stack:
+ // -1~-n: args
+
+ int n = lua_gettop(L); // n args
+
+ lua_pushvalue(L, lua_upvalueindex(2));
+ if (state.IsType(-1, LUA_TFUNCTION))
+ {
+ // stack:
+ // -1: New
+ // -2~-1-n: args
+
+ state.PushValues(-1 - n, n);
+
+ // stack:
+ // -1~-n: args
+ // -n-1: New
+ // -n-2~-1-2n: args
+
+ state.Call(n, 1);
+
+ // stack:
+ // -1: userdata
+ // -2~-1-n: args
+
+ // reset member table's metatable to class table
+ if (state.IsType(-1, LUA_TUSERDATA))
+ {
+ if (lua_getmetatable(L, -1)) // ref table
+ {
+ if (lua_getmetatable(L, -1)) // member table
+ {
+ lua_pushvalue(L, lua_upvalueindex(1)); // class table
+ lua_setmetatable(L, -2);
+ state.Pop(); // member table
+ }
+ state.Pop(); // ref table
+ }
+
+ // stack:
+ // -1: userdata
+ // -2~-1-n: args
+
+ int args = state.AbsIndex(-1 - n);
+
+ // 尝试调用__init函数
+ lua_getfield(L, lua_upvalueindex(1), "__init");
+
+ if (state.IsType(-1, LUA_TFUNCTION))
+ {
+ lua_pushvalue(L, -2); // userdata
+ state.PushValues(args, n);
+ state.Call(n + 1, 0);
+ }
+ else
+ state.Pop();
+
+ }
+
+ return 1;
+ }
+ return 0;
+ }
+
+#endif /*LUA_BIND_ENABLE_NATIVE_EXTEND*/
+
+ template<class TYPE, class BASE>
+ int NativeClass<TYPE, BASE>::_GetClass(lua_State* L)
+ {
+ LUA_BIND_STATE(L);
+ if (!mClassTable)
+ lua_pushnil(L);
+ else
+ mClassTable.PushRef(state);
+ return 1;
+ }
+
+ template<class TYPE, class BASE>
+ int NativeClass<TYPE, BASE>::_GetRefTable(lua_State* L)
+ {
+ LUA_BIND_STATE(L);
+ TYPE* self = state.GetUserdata<TYPE>(1);
+ bool success = self->PushRefTable(state);
+ if (!success)
+ lua_pushnil(L);
+ return 1;
+ }
+
+ template<class TYPE, class BASE> StrongRef NativeClass<TYPE, BASE>::mClassTable; // class table
+ template<class TYPE, class BASE> StrongRef NativeClass<TYPE, BASE>::mSingletonRefTable; // 单例
+
+} \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindConfig.h b/Runtime/Lua/LuaBind/LuaBindConfig.h
new file mode 100644
index 0000000..ded072e
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindConfig.h
@@ -0,0 +1,65 @@
+#ifndef __LUA_BIND_TYPE_H__
+#define __LUA_BIND_TYPE_H__
+
+#include <iostream>
+
+extern "C" {
+#include "ThirdParty/lua51/lua.h"
+#include "ThirdParty/lua51/lualib.h"
+#include "ThirdParty/lua51/lauxlib.h"
+}
+
+#include <assert.h>
+
+namespace LuaBind
+{
+
+ typedef unsigned int uint;
+ typedef unsigned long uintptr;
+ typedef long sintptr;
+
+ typedef const char cc8;
+
+ typedef unsigned char u8;
+ typedef unsigned short u16;
+ typedef unsigned int u32;
+ typedef unsigned long long u64;
+
+ typedef signed char s8;
+ typedef signed short s16;
+ typedef signed int s32;
+ typedef signed long long s64;
+
+#ifdef _WIN32
+ #define LUA_BIND_FINAL final
+ #define LUA_BIND_LIBRARY_EXPORT __declspec(dllexport)
+ #define LUA_BIND_LIBRARY_IMPORT __declspec(dllimport)
+ #define LUA_BIND_FORCE_INLINE __forceinline
+ #define LUA_BIND_RESTRICT __restrict
+ #define LUA_BIND_ATTRIBUTE_USED
+ #define LUA_BIND_ABSTRACT
+ #define LUA_BIND_API LUA_BIND_LIBRARY_EXPORT
+#else
+ #define LUA_BIND_FINAL final
+ #define LUA_BIND_LIBRARY_EXPORT __attribute__((visibility("default")))
+ #define LUA_BIND_LIBRARY_IMPORT
+ #define LUA_BIND_FORCE_INLINE __attribute__((always_inline)) inline
+ #define LUA_BIND_RESTRICT __restrict__
+ #define LUA_BIND_ATTRIBUTE_USED __attribute__((used))
+ #define LUA_BIND_ABSTRACT
+ #define LUA_BIND_API LUA_BIND_LIBRARY_EXPORT
+#endif
+
+#define LUA_BIND_ENABLE_NATIVE_EXTEND 0
+#define LUA_BIND_ENABLE_PLAIN_CLASS 0
+#define LUA_BIND_ENABLE_PLAIN_ENUM 0
+
+#define LUA_BIND_PROFILER 1
+
+}
+
+#if LUA_BIND_PROFILER
+#include <iostream>
+#endif
+
+#endif // __LUA_BIND_TYPE_H__ \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindEnum.cpp b/Runtime/Lua/LuaBind/LuaBindEnum.cpp
new file mode 100644
index 0000000..63e2567
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindEnum.cpp
@@ -0,0 +1,67 @@
+#include "LuaBindEnum.h"
+#include "LuaBindState.h"
+#include "LuaBindVM.h"
+
+namespace LuaBind
+{
+
+ //
+ // 只读metatable的__index
+ //
+ int _rmt__index(lua_State* L)
+ {
+ // params:
+ // 1: enum table
+ // 2: key
+
+ // upvalues:
+ // 1: metatable
+
+ int mt = lua_upvalueindex(1);
+ lua_pushvalue(L, 2);
+ lua_rawget(L, mt);
+
+ return 1;
+ }
+
+ int _rmt__newindex(lua_State* L)
+ {
+ // upvalue:
+ // 1: enum table name
+
+ cc8* name = lua_tostring(L, lua_upvalueindex(1));
+
+ return luaL_error(L, "Enum called \"%s\" is readonly.", name);
+ }
+
+ //--------------------------------------------------------------------------------//
+#if LUA_BIND_ENABLE_PLAIN_ENUM
+ int PlainEnum::registry(lua_State* L)
+ {
+ // params:
+ // 1: enum name
+ // 2: metatable
+
+ cc8* name = luaL_checkstring(L, 1);
+
+ if (!lua_istable(L, 2))
+ {
+ return luaL_error(L, "Create plain enum failed. Require table, but get %s", luaL_typename(L, 2));
+ }
+
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+
+ lua_pushstring(L, name);
+ lua_pushcclosure(L, _rmt__newindex, 1);
+ lua_setfield(L, -2, "__newindex");
+
+ lua_newtable(L); // enum table
+
+ lua_pushvalue(L, -2); // metatable
+ lua_setmetatable(L, -2);
+
+ return 1;
+ }
+#endif
+} \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindEnum.h b/Runtime/Lua/LuaBind/LuaBindEnum.h
new file mode 100644
index 0000000..122e845
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindEnum.h
@@ -0,0 +1,39 @@
+#ifndef __LUA_BIND_ENUM_H__
+#define __LUA_BIND_ENUM_H__
+
+#include "LuaBindConfig.h"
+
+namespace LuaBind
+{
+
+ //
+ // 导出枚举,枚举是一类不可修改整型集合,枚举的值在
+ //
+ struct Enum
+ {
+ cc8* name;
+ int value;
+ };
+
+ extern int _rmt__index(lua_State* L);
+
+ extern int _rmt__newindex(lua_State* L);
+
+ //--------------------------------------------------------------------------------//
+
+#if LUA_BIND_ENABLE_PLAIN_ENUM
+ //
+ // 纯lua的枚举,创建不可修改的table
+ //
+ class PlainEnum
+ {
+ public:
+
+ static int registry(lua_State* L);
+
+ };
+#endif
+
+}
+
+#endif \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindGlobalState.h b/Runtime/Lua/LuaBind/LuaBindGlobalState.h
new file mode 100644
index 0000000..fa3cc4f
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindGlobalState.h
@@ -0,0 +1,7 @@
+#ifndef __LUA_BIND_GLOBAL_STATE_H__
+#define __LUA_BIND_GLOBAL_STATE_H__
+
+// 索引到lua里的global_State
+typedef struct global_State global_State;
+
+#endif \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindInternal.h b/Runtime/Lua/LuaBind/LuaBindInternal.h
new file mode 100644
index 0000000..1d4a226
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindInternal.h
@@ -0,0 +1,12 @@
+#ifndef __LUA_BIND_INTERNAL_H__
+#define __LUA_BIND_INTERNAL_H__
+
+//
+// 对lua源代码的深度使用
+//
+extern "C"
+{
+#include "ThirdParty/lua51/lstate.h"
+}
+
+#endif \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindMemberRef.cpp b/Runtime/Lua/LuaBind/LuaBindMemberRef.cpp
new file mode 100644
index 0000000..e680cce
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindMemberRef.cpp
@@ -0,0 +1,16 @@
+#include "LuaBindMemberRef.h"
+
+namespace LuaBind
+{
+
+ MemberRef::MemberRef()
+ : refID(LUA_NOREF)
+ {
+ }
+
+ MemberRef::~MemberRef()
+ {
+
+ }
+
+} \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindMemberRef.h b/Runtime/Lua/LuaBind/LuaBindMemberRef.h
new file mode 100644
index 0000000..045d6ef
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindMemberRef.h
@@ -0,0 +1,27 @@
+#ifndef __LUA_BIND_MEMBER_REF_H__
+#define __LUA_BIND_MEMBER_REF_H__
+
+#include "LuaBindConfig.h"
+
+namespace LuaBind
+{
+
+ //
+ // 实例的ref table保存的member ref。由luax class做具体的管理。实例的ref table是强引用,用来管理里面member的生命周期。
+ // 用来在lua和native之间进行数据沟通。
+ //
+ class MemberRef
+ {
+ public:
+ MemberRef();
+ ~MemberRef();
+
+ inline operator bool() { return refID != LUA_NOREF; };
+
+ int refID;
+
+ };
+
+}
+
+#endif \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindRef.cpp b/Runtime/Lua/LuaBind/LuaBindRef.cpp
new file mode 100644
index 0000000..00a65d0
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindRef.cpp
@@ -0,0 +1,72 @@
+#include "LuaBindVM.h"
+#include "LuaBindRef.h"
+
+namespace LuaBind
+{
+
+ Ref::Ref(int mode)
+ : mRefID(LUA_NOREF)
+ , mMode(mode)
+ {
+ }
+
+ Ref::~Ref()
+ {
+ }
+
+ Ref::operator bool()
+ {
+ return (mRefID != LUA_NOREF);
+ }
+
+ bool Ref::PushRef(State& state)
+ {
+ assert(mRefID != LUA_NOREF);
+
+ VM* vm = state.GetVM();
+ if (!vm) return false;
+ if (mMode == STRONG_REF)
+ {
+ RefTable& table = vm->GetStrongRefTable();
+ table.PushRef(state, mRefID);
+ }
+ else if (mMode == WEAK_REF)
+ {
+ RefTable& table = vm->GetWeakRefTable();
+ table.PushRef(state, mRefID);
+ }
+ else
+ {
+ state.PushNil();
+ return false;
+ }
+ return true;
+ }
+
+ void Ref::SetRef(State& state, int idx)
+ {
+ VM* vm = state.GetVM();
+ if (!vm) return;
+ if (mMode == STRONG_REF)
+ {
+ RefTable& table = vm->GetStrongRefTable();
+ mRefID = table.Ref(state, idx);
+ }
+ else if (mMode == WEAK_REF)
+ {
+ RefTable& table = vm->GetWeakRefTable();
+ mRefID = table.Ref(state, idx);
+ }
+ }
+
+ StrongRef::StrongRef()
+ : Ref(STRONG_REF)
+ {
+ }
+
+ WeakRef::WeakRef()
+ : Ref(WEAK_REF)
+ {
+ }
+
+}
diff --git a/Runtime/Lua/LuaBind/LuaBindRef.h b/Runtime/Lua/LuaBind/LuaBindRef.h
new file mode 100644
index 0000000..93b30be
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindRef.h
@@ -0,0 +1,62 @@
+#ifndef __LUA_BIND_REF_H__
+#define __LUA_BIND_REF_H__
+
+#include "LuaBindConfig.h"
+#include "LuaBindState.h"
+
+namespace LuaBind
+{
+
+ //
+ // 引用,存在LUA_REGISTRYINDEX下面的两个表里
+ //
+ class Ref
+ {
+ public:
+
+ enum RefMode
+ {
+ STRONG_REF,
+ WEAK_REF
+ };
+
+ Ref(int mode = STRONG_REF);
+ virtual ~Ref();
+
+ operator bool();
+
+ void SetRef(State& state, int idx);
+ bool PushRef(State& state);
+
+ int GetRefID();
+
+ private:
+
+ int mRefID; // luaL_ref
+ int mMode; // strong or weak
+
+ };
+
+ //
+ // 强引用,在LUA_REGISTRYINDEX["_LUA_BIND_STRONGREF_TABLE"]里,保证lua object不会被回收。
+ //
+ class StrongRef: public Ref
+ {
+ public:
+ StrongRef();
+
+ };
+
+ //
+ // 弱引用,在LUA_REGISTRYINDEX["_LUA_BIND_WEAKREF_TABLE"]里,不影响lua object的回收,只是作为一个方便取lua object的映射。
+ //
+ class WeakRef : public Ref
+ {
+ public:
+ WeakRef();
+
+ };
+
+}
+
+#endif \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindRefTable.cpp b/Runtime/Lua/LuaBind/LuaBindRefTable.cpp
new file mode 100644
index 0000000..39ef9ab
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindRefTable.cpp
@@ -0,0 +1,120 @@
+#include "LuaBindRefTable.h"
+#include "LuaBindState.h"
+
+namespace LuaBind
+{
+
+ RefTable::RefTable()
+ : mState(nullptr)
+ {
+ }
+
+ RefTable::~RefTable()
+ {
+ }
+
+ void RefTable::Init(State& state, cc8* name, cc8* mode)
+ {
+ assert(!mState);
+ assert(name);
+
+ mName = name;
+ mMode = 0;
+ for (int i = 0; mode && mode[i]; ++i)
+ {
+ if (mode[i] == 'k') mMode |= WEAK_KEY;
+ else if (mode[i] == 'v') mMode |= WEAK_VALUE;
+ }
+ mState = state.GetHandle();
+
+ state.GetField(LUA_REGISTRYINDEX, name); // register[mName]
+ if (state.IsNil(-1))
+ {
+ state.Pop();
+
+ lua_newtable(state); // ref table
+ int ridx = state.AbsIndex(-1);
+ lua_newtable(state); // metatable of ref table
+ int idx = state.AbsIndex(-1);
+
+ // __mode
+ if (mode)
+ {
+ state.Push(mode);
+ state.SetField(idx, "__mode");
+ }
+
+ state.Settop(idx);
+ lua_setmetatable(state, ridx);
+
+ state.Settop(ridx);
+ state.SetField(LUA_REGISTRYINDEX, name);
+ }
+ else
+ {
+ state.Pop();
+ }
+ }
+
+ bool RefTable::IsKeyWeak()
+ {
+ assert(mState);
+
+ return mMode & WEAK_KEY;
+ }
+
+ bool RefTable::IsValueWeak()
+ {
+ assert(mState);
+
+ return mMode & WEAK_VALUE;
+ }
+
+ int RefTable::Ref(State& state, int idx)
+ {
+ assert(mState);
+
+ idx = state.AbsIndex(idx);
+ state.GetField(LUA_REGISTRYINDEX, mName); // ref table
+ lua_pushvalue(state, idx); // stuff
+ int refID = luaL_ref(state, -2);
+ assert(refID != LUA_NOREF);
+ state.Pop();
+ return refID;
+ }
+
+ void RefTable::Unref(State& state, int refID)
+ {
+ assert(mState);
+
+ state.GetField(LUA_REGISTRYINDEX, mName); // ref table
+ luaL_unref(state, -1, refID);
+ state.Pop();
+ return;
+ }
+
+ void RefTable::PushRefTable(State& state)
+ {
+ assert(mState);
+
+ lua_getfield(state, LUA_REGISTRYINDEX, mName);
+ }
+
+ void RefTable::PushRef(State& state, int refID)
+ {
+ assert(mState);
+
+ lua_getfield(state, LUA_REGISTRYINDEX, mName);
+ lua_rawgeti(state, -1, refID);
+ lua_replace(state, -2);
+ }
+
+ void RefTable::Clear(State& state)
+ {
+ assert(mState);
+
+ lua_newtable(state);
+ state.SetField(LUA_REGISTRYINDEX, mName);
+ }
+
+} \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindRefTable.h b/Runtime/Lua/LuaBind/LuaBindRefTable.h
new file mode 100644
index 0000000..0d4c2d4
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindRefTable.h
@@ -0,0 +1,67 @@
+#ifndef __LUA_BIND_REFTABLE_H__
+#define __LUA_BIND_REFTABLE_H__
+
+#include "LuaBindConfig.h"
+
+namespace LuaBind
+{
+
+ class State;
+
+ //
+ // ref table 管理,对strong ref table和weak ref table两个table的代理。
+ //
+ class RefTable
+ {
+ public:
+
+ enum
+ {
+ WEAK_KEY = 1,
+ WEAK_VALUE = 1 << 1
+ };
+
+ RefTable();
+ ~RefTable();
+
+ inline operator bool() { return mState; };
+
+ void Init(State& state, cc8* name, cc8* mode = nullptr);
+
+ bool IsKeyWeak();
+ bool IsValueWeak();
+
+ //
+ // 对stack[idx]的实体在此ref table中增加一个引用,并返回refID
+ //
+ int Ref(State& state, int idx);
+ void Unref(State& state, int refID);
+
+ //
+ // 将此 ref table 放在栈顶
+ //
+ void PushRefTable(State& state);
+
+ //
+ // 将 reftable[refID] 放在栈顶
+ //
+ void PushRef(State& state, int refID);
+
+ //
+ // 清空 ref table,表还留在LUA_REGISTRYINDEX[mName]
+ //
+ void Clear(State& state);
+
+ private:
+
+ friend class State;
+
+ lua_State* mState; // 用来做一些确认工作
+ cc8* mName; // ref table的名称
+ int mMode; // ref table的类型
+
+ };
+
+}
+
+#endif \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindState.cpp b/Runtime/Lua/LuaBind/LuaBindState.cpp
new file mode 100644
index 0000000..4ee87f4
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindState.cpp
@@ -0,0 +1,893 @@
+#include "LuaBindEnum.h"
+#include "LuaBindState.h"
+#include "LuaBindVM.h"
+#include "LuaBindClass.hpp"
+#include "LuaBindInternal.h"
+
+#include <string>
+
+namespace LuaBind
+{
+
+ State::State(lua_State* state)
+ : mState(state)
+ {
+ assert(state);
+ }
+
+ State::State(const State& state)
+ : mState(state.mState)
+ {
+ assert(state.mState);
+ }
+
+ State::~State()
+ {
+ }
+
+ void State::OpenLibs()
+ {
+ luaL_openlibs(mState);
+ }
+
+ global_State* State::GetGlobalState()
+ {
+ return G(mState);
+ }
+
+ VM* State::GetVM()
+ {
+ return VM::TryGetVM(G(mState));
+ }
+
+ void State::PushGlobalNamespace()
+ {
+#if false
+ int top = GetTop();
+
+ lua_newtable(mState); // pseudo namespace table
+ int pnt = GetTop();
+
+ lua_newtable(mState); // metatable
+ int mt = GetTop();
+
+ // __index = _G
+ // __newindex = _G
+ lua_pushvalue(mState, LUA_GLOBALSINDEX);
+ lua_pushvalue(mState, LUA_GLOBALSINDEX);
+ lua_setfield(mState, mt, "__index");
+ lua_setfield(mState, mt, "__newindex");
+
+ lua_setmetatable(mState, pnt);
+
+ // stack:
+ // -1 pseudo global namespace
+#else
+ lua_pushvalue(mState, LUA_GLOBALSINDEX);
+#endif
+ }
+
+ void State::PushNamespace(cc8* name)
+ {
+ assert(IsNamespace(-1));
+
+ int top = GetTop();
+
+ lua_getfield(mState, -1, name);
+ if (lua_isnil(mState, -1))
+ {
+ lua_pop(mState, 1);
+
+ lua_newtable(mState);
+ lua_pushvalue(mState, -1);
+ lua_setfield(mState, top, name);
+ }
+
+ // stack:
+ // -1 namespace
+ }
+
+ void State::PopNamespace()
+ {
+ assert(lua_istable(mState, -1));
+ lua_pop(mState, 1);
+ }
+
+ bool State::IsNamespace(int idx)
+ {
+ return lua_istable(mState, idx);
+ }
+
+ void State::DoString(const std::string& code)
+ {
+ luaL_dostring(mState, code.c_str());
+ }
+
+ void State::DoFile(const std::string & path)
+ {
+ luaL_dofile(mState, path.c_str());
+ }
+
+ int State::AbsIndex(int idx)
+ {
+/*
+#define abs_index(mState, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \
+ lua_gettop(mState) + (i) + 1)
+*/
+ if (idx < 0) {
+ //return lua_gettop(mState) + idx + 1;
+ return ((idx) > 0 || (idx) <= LUA_REGISTRYINDEX ? (idx) : \
+ lua_gettop(mState) + (idx)+1);
+ }
+ return idx;
+ }
+
+ void State::Call(int nArgs, int nResults)
+ {
+ lua_pcall(mState, nArgs, nResults, 0);
+ }
+
+ void State::PushNil()
+ {
+ lua_pushnil(mState);
+ }
+
+ void State::Push(bool value)
+ {
+ lua_pushboolean(mState, value ? 1 : 0);
+ }
+
+ void State::Push(cc8* value)
+ {
+ lua_pushstring(mState, value);
+ }
+
+ void State::Push(double value)
+ {
+ lua_pushnumber(mState, value);
+ }
+
+ void State::Push(float value)
+ {
+ lua_pushnumber(mState, value);
+ }
+
+ void State::Push(int value)
+ {
+ lua_pushnumber(mState, value);
+ }
+
+ void State::Push(u16 value)
+ {
+ lua_pushnumber(mState, value);
+ }
+
+ void State::Push(u32 value)
+ {
+ lua_pushnumber(mState, value);
+ }
+
+ void State::Push(u64 value)
+ {
+ lua_pushnumber(mState, (double)value);
+ }
+
+ void State::Push(s64 value)
+ {
+ lua_pushinteger(mState, value);
+ }
+
+ void State::Push(uintptr value)
+ {
+ lua_pushlightuserdata(mState, (void*)value);
+ }
+
+ void State::Push(lua_CFunction value)
+ {
+ lua_pushcfunction(mState, value);
+ }
+
+ void State::Push(void* data, size_t size)
+ {
+ lua_pushlstring(mState, (cc8*)data, size);
+ }
+
+ void State::Push(const void* value)
+ {
+ lua_pushlightuserdata(mState, (void*)value);
+ }
+
+ void State::Push(std::string value)
+ {
+ Push(value.c_str());
+ }
+
+ void State::PushValues(int idx, int n)
+ {
+ idx = AbsIndex(idx);
+ for (int i = idx; i < idx + n; ++i)
+ lua_pushvalue(mState, i);
+ }
+
+ void State::Pop(int n /* = 1 */)
+ {
+ lua_pop(mState, n);
+ }
+
+ bool State::IsNil(int idx)
+ {
+ return lua_isnil(mState, idx);
+ }
+
+ bool State::IsNilOrNone(int idx)
+ {
+ int t = lua_type(mState, idx);
+ return ((t == LUA_TNONE) || (t == LUA_TNIL));
+ }
+
+ bool State::IsTableOrUserdata(int idx)
+ {
+ int check = lua_type(mState, idx);
+ return ((check == LUA_TTABLE) || (check == LUA_TUSERDATA));
+ }
+
+ bool State::IsTrueOrNotNil(int idx)
+ {
+ if (lua_isboolean(mState, idx)) {
+ return lua_toboolean(mState, idx) ? true : false;
+ }
+ return !lua_isnil(mState, idx);
+ }
+
+ bool State::IsType(int idx, int type)
+ {
+ return (lua_type(mState, idx) == type);
+ }
+
+ bool State::IsType(int idx, cc8* name, int type)
+ {
+ return this->HasField(idx, name, type);
+ }
+
+ bool State::IsValid()
+ {
+ return (mState != 0);
+ }
+
+ void State::Settop(int idx)
+ {
+ lua_settop(mState, idx);
+ }
+
+ int State::GetTop()
+ {
+ return lua_gettop(mState);
+ }
+
+ bool State::HasField(int idx, cc8* name) {
+
+ lua_getfield(mState, idx, name);
+ bool hasField = (lua_isnil(mState, -1) == false);
+ lua_pop(mState, 1);
+
+ return hasField;
+ }
+
+ bool State::HasField(int idx, int key) {
+
+ this->GetField(idx, key);
+ bool hasField = (lua_isnil(mState, -1) == false);
+ lua_pop(mState, 1);
+
+ return hasField;
+ }
+
+ bool State::HasField(int idx, cc8* name, int type) {
+
+ lua_getfield(mState, idx, name);
+ bool hasField = (lua_type(mState, -1) == type);
+ lua_pop(mState, 1);
+
+ return hasField;
+ }
+
+ bool State::HasField(int idx, int key, int type) {
+
+ this->GetField(idx, key);
+ bool hasField = (lua_type(mState, -1) == type);
+ lua_pop(mState, 1);
+
+ return hasField;
+ }
+
+ bool State::HasKeys(int idx) {
+
+ idx = this->AbsIndex(idx);
+
+ lua_pushnil(mState); /* first key */
+ if (lua_next(mState, idx) != 0) {
+ lua_pop(mState, 2);
+ return true;
+ }
+ return false;
+ }
+
+ void State::GetField(int idx, cc8* name)
+ {
+ lua_getfield(mState, idx, name);
+ }
+
+ void State::GetField(int idx, int key)
+ {
+ idx = this->AbsIndex(idx);
+
+ lua_pushinteger(mState, key);
+ lua_gettable(mState, idx);
+ }
+
+ std::string State::GetField(int idx, cc8* key, cc8* default_value)
+ {
+ std::string str;
+ if (this->GetFieldWithType(idx, key, LUA_TSTRING)) {
+ str = lua_tostring(mState, -1);
+ lua_pop(mState, 1);
+ }
+ else {
+ str = default_value;
+ }
+ return str;
+ }
+
+ std::string State::GetField(int idx, int key, cc8* default_value)
+ {
+ std::string str;
+ if (this->GetFieldWithType(idx, key, LUA_TSTRING)) {
+ str = lua_tostring(mState, -1);
+ lua_pop(mState, 1);
+ }
+ else {
+ str = default_value;
+ }
+ return str;
+ }
+
+ std::string State::GetField(int idx, cc8* key, const std::string& value)
+ {
+ std::string str;
+ if (this->GetFieldWithType(idx, key, LUA_TSTRING)) {
+ str = lua_tostring(mState, -1);
+ lua_pop(mState, 1);
+ }
+ else {
+ str = value;
+ }
+ return str;
+ }
+
+ std::string State::GetField(int idx, int key, const std::string& value)
+ {
+ std::string str;
+ if (this->GetFieldWithType(idx, key, LUA_TSTRING)) {
+ str = lua_tostring(mState, -1);
+ lua_pop(mState, 1);
+ }
+ else {
+ str = value;
+ }
+ return str;
+ }
+
+ bool State::GetFieldWithType(int idx, cc8* name, int type)
+ {
+ lua_getfield(mState, idx, name);
+ if (lua_type(mState, -1) != type) {
+ lua_pop(mState, 1);
+ return false;
+ }
+ return true;
+ }
+
+ bool State::GetFieldWithType(int idx, int key, int type)
+ {
+ this->GetField(idx, key);
+ if (lua_type(mState, -1) != type) {
+ lua_pop(mState, 1);
+ return false;
+ }
+ return true;
+ }
+
+ void State::SetField(int idx, cc8* key)
+ {
+ if (IsTableOrUserdata(idx))
+ {
+ idx = AbsIndex(idx);
+ lua_setfield(mState, idx, key);
+ }
+ }
+
+ cc8* State::GetLuaTypeName(int type)
+ {
+ switch (type) {
+ case LUA_TNONE: return "none";
+ case LUA_TNIL: return "nil";
+ case LUA_TBOOLEAN: return "boolean";
+ case LUA_TLIGHTUSERDATA: return "lightuserdata";
+ case LUA_TNUMBER: return "number";
+ case LUA_TSTRING: return "string";
+ case LUA_TTABLE: return "table";
+ case LUA_TFUNCTION: return "function";
+ case LUA_TUSERDATA: return "userdata";
+ case LUA_TTHREAD: return "thread";
+ }
+ return "unknown";
+ }
+
+
+ bool State::GetSubfieldWithType(int idx, cc8* format, int type, ...)
+ {
+ va_list args;
+ va_start(args, type);
+
+ idx = this->AbsIndex(idx);
+ lua_pushvalue(this->mState, idx);
+
+ for (cc8* c = format; *c; ++c) {
+ switch (*c) {
+ // number
+ case 'N':
+ lua_pushnumber(this->mState, va_arg(args, int));
+ lua_gettable(this->mState, -1);
+ break;
+
+ // string
+ case 'S':
+ lua_getfield(this->mState, -1, va_arg(args, char*));
+ break;
+
+ default:
+ lua_pushnil(this->mState);
+ }
+
+ if (lua_isnil(this->mState, -1)) break;
+ lua_replace(this->mState, -2);
+ }
+ va_end(args);
+ if (lua_type(this->mState, -1) != type) {
+ lua_pop(this->mState, 1);
+ return false;
+ }
+ return true;
+ }
+
+ bool State::CheckParams(int idx, cc8* format)
+ {
+ idx = AbsIndex(idx);
+
+ for (int i = 0; format[i]; ++i) {
+
+ int pos = idx + i;
+ int type = LUA_TNIL;
+ int expected = LUA_TNONE;
+
+ if (pos <= GetTop()) {
+ type = lua_type(mState, pos);
+ }
+
+ switch (format[i]) {
+
+ // boolean
+ case 'B':
+ if (type != LUA_TBOOLEAN) expected = LUA_TBOOLEAN;
+ break;
+
+ // coroutine
+ case 'C':
+ if (type != LUA_TTHREAD) expected = LUA_TTHREAD;
+ break;
+
+ // function
+ case 'F':
+ if (type != LUA_TFUNCTION) expected = LUA_TFUNCTION;
+ break;
+
+ // light userdata
+ case 'L':
+ if (type != LUA_TLIGHTUSERDATA) expected = LUA_TLIGHTUSERDATA;
+ break;
+
+ // number
+ case 'N':
+ if (type != LUA_TNUMBER) expected = LUA_TNUMBER;
+ break;
+
+ // string
+ case 'S':
+ if (type != LUA_TSTRING) expected = LUA_TSTRING;
+ break;
+
+ // table
+ case 'T':
+ if (type != LUA_TTABLE) expected = LUA_TTABLE;
+ break;
+
+ // userdata
+ case 'U':
+ if (type != LUA_TUSERDATA) expected = LUA_TUSERDATA;
+ break;
+
+ // any type
+ case '*':
+ case '.':
+ break;
+ }
+
+ if (expected != LUA_TNONE) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ template <>
+ bool State::GetValue < bool >(int idx, const bool value) {
+
+ if (this->IsType(idx, LUA_TBOOLEAN)) {
+ return (lua_toboolean(this->mState, idx) != 0);
+ }
+ return value;
+ }
+
+ static std::string s_str;
+ template <>
+ cc8* State::GetValue < cc8* >(int idx, const cc8* value) {
+
+ if (this->IsType(idx, LUA_TSTRING)) {
+ return lua_tostring(this->mState, idx);
+ }
+
+ if (this->IsType(idx, LUA_TNUMBER)) {
+ if (luax_isinteger(mState, -1)) {
+ int num = lua_tointeger(this->mState, idx);
+ s_str = std::to_string(num);
+ cc8* str = s_str.c_str();
+ return str;
+ }
+ else {
+ float num = lua_tonumber(this->mState, idx);
+ s_str = std::to_string(num);
+ cc8* str = s_str.c_str();
+ return str;
+ }
+ }
+
+ if (this->IsType(idx, LUA_TBOOLEAN)) {
+ bool b = lua_toboolean(this->mState, idx);
+ return b ? "true" : "false";
+ }
+
+ if (this->IsType(idx, LUA_TNIL)) {
+ return "NIL";
+ }
+
+ return value;
+ }
+
+ template <>
+ std::string State::GetValue<std::string>(int idx, const std::string value)
+ {
+ std::string str;
+ if (lua_type(this->mState, idx) == LUA_TSTRING) {
+ str = lua_tostring(this->mState, idx);
+ }
+ else {
+ str = value;
+ }
+ return str;
+ }
+
+ template <>
+ double State::GetValue < double >(int idx, const double value)
+ {
+ if (this->IsType(idx, LUA_TNUMBER)) {
+ return lua_tonumber(this->mState, idx);
+ }
+ return value;
+ }
+
+ template <>
+ float State::GetValue < float >(int idx, const float value)
+ {
+ if (this->IsType(idx, LUA_TNUMBER)) {
+ return (float)lua_tonumber(this->mState, idx);
+ }
+ return value;
+ }
+
+ template <>
+ s8 State::GetValue < s8 >(int idx, const s8 value)
+ {
+ if (this->IsType(idx, LUA_TNUMBER)) {
+ return (s8)lua_tonumber(this->mState, idx);
+ }
+ return value;
+ }
+
+
+ template <>
+ s16 State::GetValue < s16 >(int idx, const s16 value)
+ {
+ if (this->IsType(idx, LUA_TNUMBER)) {
+ return (s16)lua_tonumber(this->mState, idx);
+ }
+ return value;
+ }
+
+
+ template <>
+ s32 State::GetValue < s32 >(int idx, const s32 value)
+ {
+ if (this->IsType(idx, LUA_TNUMBER)) {
+ return (s32)lua_tonumber(this->mState, idx);
+ }
+ return value;
+ }
+
+ template <>
+ s64 State::GetValue < s64 >(int idx, const s64 value)
+ {
+ if (this->IsType(idx, LUA_TNUMBER)) {
+ return (s64)lua_tonumber(this->mState, idx);
+ }
+ return value;
+ }
+
+ template <>
+ u8 State::GetValue < u8 >(int idx, const u8 value)
+ {
+ if (this->IsType(idx, LUA_TNUMBER)) {
+ return (u8)lua_tonumber(this->mState, idx);
+ }
+ return value;
+ }
+
+ template <>
+ u16 State::GetValue < u16 >(int idx, const u16 value)
+ {
+ if (this->IsType(idx, LUA_TNUMBER)) {
+ return (u16)lua_tonumber(this->mState, idx);
+ }
+ return value;
+ }
+
+ template <>
+ u32 State::GetValue < u32 >(int idx, const u32 value)
+ {
+ if (this->IsType(idx, LUA_TNUMBER)) {
+ return (u32)lua_tonumber(this->mState, idx);
+ }
+ return value;
+ }
+
+ template <>
+ u64 State::GetValue < u64 >(int idx, const u64 value)
+ {
+ if (this->IsType(idx, LUA_TNUMBER)) {
+ return (u64)lua_tonumber(this->mState, idx);
+ }
+ return value;
+ }
+
+ template <>
+ const void* State::GetValue < const void* >(int idx, const void* value)
+ {
+ if (this->IsType(idx, LUA_TLIGHTUSERDATA)) {
+ return (void*)lua_touserdata(this->mState, idx);
+ }
+ return value;
+ }
+
+ void State::PushPtrUserdata(void* ptr)
+ {
+ void** handle = (void**)lua_newuserdata(this->mState, sizeof(void*));
+ assert(handle);
+ (*handle) = ptr;
+ }
+
+ void State::RegisterEnum(cc8* name, Enum* en)
+ {
+ assert(name);
+ assert(en);
+
+ // short name
+ lua_State* L = mState;
+
+ int top = GetTop();
+
+ lua_newtable(L); // enum table
+
+ int et = GetTop();
+
+ lua_newtable(L); // matatable
+
+ // 所有枚举都存在metatable下,修改时触发__newindex报错
+ for (; en->name; ++en)
+ {
+ lua_pushinteger(L, en->value);
+ lua_setfield(L, -2, en->name);
+ }
+
+ // __index
+ //lua_pushvalue(L, -1); // metatable
+ //lua_pushcclosure(L, _rmt__index, 1);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+
+ // __newinedx
+ lua_pushstring(L, name); // enum name
+ lua_pushcclosure(L, _rmt__newindex, 1);
+ lua_setfield(L, -2, "__newindex");
+
+ lua_setmetatable(L, et);
+
+ lua_setfield(L, top, name);
+ }
+
+
+ void State::RegisterMethods(const luaL_Reg *l)
+ {
+ assert(lua_istable(mState, -1));
+ // luaL_register第二个参数为空,则向-1位置注册luaL_Reg中这些函数
+ luaL_register(mState, 0, l);
+ }
+
+ void State::RegisterMethod(cc8* fname, lua_CFunction func)
+ {
+ assert(lua_istable(mState, -1));
+ lua_pushcfunction(mState, func);
+ lua_setfield(mState, -2, fname);
+ }
+
+ void State::RegisterPreloader(cc8* libname, lua_CFunction preloader)
+ {
+ lua_getglobal(mState, "package");
+ lua_getfield(mState, -1, "preload");
+ lua_pushcfunction(mState, preloader);
+ lua_setfield(mState, -2, libname);
+ lua_pop(mState, 2);
+ }
+
+ void State::RegisterLib(cc8* libname, const luaL_Reg* l)
+ {
+ luaL_register(mState, libname, l);
+ }
+
+#if LUA_BIND_ENABLE_PLAIN_CLASS
+ void State::RegisterPlainClassRegistry(cc8* name)
+ {
+ assert(lua_istable(mState, -1));
+ lua_pushcfunction(mState, PlainClass::registry);
+ lua_setfield(mState, -2, name);
+ }
+#endif
+
+#if LUA_BIND_ENABLE_PLAIN_ENUM
+ void State::RegisterPlainEnumRegistry(cc8* name)
+ {
+ assert(lua_istable(mState, -1));
+ lua_pushcfunction(mState, PlainEnum::registry);
+ lua_setfield(mState, -2, name);
+ }
+#endif
+
+ int State::ErrorType(int idx, cc8* hint)
+ {
+ return luaL_typerror(mState, idx, hint);
+ }
+
+ template <>
+ bool State::CheckValue < bool >(int idx)
+ {
+ bool b = false;
+ if (lua_type(mState, idx) == LUA_TBOOLEAN)
+ {
+ b = lua_toboolean(mState, idx);
+ }
+ else
+ {
+ luaL_typerror(mState, idx, lua_typename(mState, LUA_TBOOLEAN));
+ }
+ return b;
+ }
+
+ template <>
+ cc8* State::CheckValue < cc8* >(int idx)
+ {
+ return luaL_checkstring(mState, idx);
+ }
+
+ template <>
+ double State::CheckValue < double >(int idx)
+ {
+ return luaL_checknumber(mState, idx);
+ }
+
+ template <>
+ float State::CheckValue < float >(int idx)
+ {
+ return luaL_checknumber(mState, idx);
+ }
+
+ template <>
+ s8 State::CheckValue < s8 >(int idx)
+ {
+ return luaL_checkinteger(mState, idx);
+ }
+
+ template <>
+ s16 State::CheckValue < s16 >(int idx)
+ {
+ return luaL_checkinteger(mState, idx);
+ }
+
+ template <>
+ s32 State::CheckValue < s32 >(int idx)
+ {
+ return luaL_checkinteger(mState, idx);
+ }
+
+ template <>
+ s64 State::CheckValue < s64 >(int idx)
+ {
+ return luaL_checkinteger(mState, idx);
+ }
+
+ template <>
+ u8 State::CheckValue < u8 >(int idx)
+ {
+ return luaL_checkinteger(mState, idx);
+ }
+
+ template <>
+ u16 State::CheckValue < u16 >(int idx)
+ {
+ return luaL_checkinteger(mState, idx);
+ }
+
+ template <>
+ u32 State::CheckValue < u32 >(int idx)
+ {
+ return luaL_checkinteger(mState, idx);
+ }
+
+ template <>
+ u64 State::CheckValue < u64 >(int idx)
+ {
+ return luaL_checkinteger(mState, idx);
+ }
+
+ template <>
+ std::string State::CheckValue < std::string >(int idx)
+ {
+ return luaL_checkstring(mState, idx);
+ }
+
+ //
+ // check light userdata
+ //
+ template <>
+ const void* State::CheckValue < const void* >(int idx)
+ {
+ if (IsType(idx, LUA_TLIGHTUSERDATA))
+ {
+ return GetValue<const void*>(idx, nullptr);
+ }
+ else
+ {
+ luaL_typerror(mState, idx, "light userdata");
+ return nullptr;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindState.h b/Runtime/Lua/LuaBind/LuaBindState.h
new file mode 100644
index 0000000..776b23d
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindState.h
@@ -0,0 +1,266 @@
+#ifndef __LUA_BIND_STATE_H__
+#define __LUA_BIND_STATE_H__
+
+#include <string>
+
+#include "LuaBindConfig.h"
+#include "LuaBindRefTable.h"
+#include "LuaBindGlobalState.h"
+
+namespace LuaBind
+{
+
+ class VM;
+ class Enum;
+ class StrongRef;
+ class WeakRef;
+
+ // 对lua_State的代理,除了保存一个lua_State的引用不保存其他内容。一个实例的metatable如下:
+ // class table
+ // member table
+ // ref table
+ // userdata
+ // 从userdata通过getmetatable获取上级metatable。除此之外还有一个class table注册在对应
+ // 的名称空间里。
+ LUA_BIND_API class State
+ {
+ public:
+
+ State(lua_State* state);
+ State(const State& state);
+ virtual ~State();
+
+ inline lua_State* operator ->() { return mState; };
+ inline lua_State& operator *() { return *mState; };
+ inline operator lua_State*() { return mState; }
+ inline operator bool() { return mState != nullptr; };
+
+ // 获取绑定的lua_State
+ inline lua_State* GetHandle() { return mState; };
+
+ global_State* GetGlobalState();
+
+ VM* GetVM();
+
+ //------------------------------------------------------------------------------//
+
+ void OpenLibs();
+
+ //------------------------------------------------------------------------------//
+ // 名称空间管理,名称空间就是一个表,_G是最上面的表
+
+ void PushGlobalNamespace();
+ void PushNamespace(cc8* name);
+ void PopNamespace();
+ bool IsNamespace(int idx);
+
+ //------------------------------------------------------------------------------//
+
+ void SetTop(int top);
+ int GetTop();
+ bool CheckParams(int idx, cc8* format);
+ int AbsIndex(int idx);
+ void Call(int nArgs, int nResults);
+
+ //------------------------------------------------------------------------------//
+
+ void GetField(int idx, cc8* name);
+ void GetField(int idx, int key);
+ std::string GetField(int idx, cc8* key, cc8* value);
+ std::string GetField(int idx, int key, cc8* value);
+ std::string GetField(int idx, cc8* key, const std::string& value);
+ std::string GetField(int idx, int key, const std::string& value);
+ bool GetFieldWithType(int idx, cc8* name, int type);
+ bool GetFieldWithType(int idx, int key, int type);
+ bool GetSubfieldWithType(int idx, cc8* format, int type, ...);
+ static cc8* GetLuaTypeName(int type);
+
+ void SetField(int idx, cc8* key);
+
+ bool IsNil(int idx);
+ bool IsNilOrNone(int idx);
+ bool IsTableOrUserdata(int idx);
+ bool IsTrueOrNotNil(int idx);
+ bool IsType(int idx, int type);
+ bool IsType(int idx, cc8* name, int type);
+ bool IsValid();
+
+ bool HasField(int idx, cc8* name);
+ bool HasField(int idx, int key);
+ bool HasField(int idx, cc8* name, int type);
+ bool HasField(int idx, int name, int type);
+ bool HasKeys(int idx);
+
+ void PushNil();
+ void Push(bool value);
+ void Push(cc8* value);
+ void Push(double value);
+ void Push(float value);
+ void Push(int value);
+ void Push(u16 value);
+ void Push(u32 value);
+ void Push(u64 value);
+ void Push(s64 value);
+ void Push(uintptr value);
+ void Push(lua_CFunction value);
+ void Push(void* data, size_t size);
+ void Push(const void* value);
+ void Push(std::string value);
+
+ // 将idx开始的n个push到栈顶,idx会被取正,n向上生长。
+ void PushValues(int idx, int n);
+
+ // 以void** 的形式创建userdata,并将值设置为ptr
+ void PushPtrUserdata(void* ptr);
+
+ void Pop(int n = 1);
+
+ void Settop(int idx);
+
+ template<typename T> T* GetUserdata(int idx = 1);
+
+ //------------------------------------------------------------------------------//
+
+ int ErrorType(int idx, cc8* hint);
+
+ //------------------------------------------------------------------------------//
+
+ template<typename T> T GetValue(int idx, T default_value);
+ template<typename T> T GetField(int idx, int key, T value);
+ template<typename T> T GetField(int idx, cc8* key, T value);
+ template<typename T> void SetField(int idx, cc8* key, T value);
+ template<typename T> void SetFieldByIndex(int idx, int key, T value);
+
+ template<typename T> T* CheckUserdata(int idx);
+ template<typename T> T CheckValue(int idx);
+
+ //------------------------------------------------------------------------------//
+
+ void DoString(const std::string& code);
+ void DoFile(const std::string& file);
+
+ //------------------------------------------------------------------------------//
+ // 注册方法
+
+ // 注册工厂,适用于普通类,有New方法
+ template<class TYPE> void RegisterFactory();
+
+ // 注册单例,没有New方法
+ template<class TYPE> void RegisterSingleton();
+
+ // 注册枚举
+ void RegisterEnum(cc8* name, Enum* enums);
+
+ // 注册C函数,注意后面加一行{0, 0}
+ void RegisterMethods(const luaL_Reg *l);
+
+ // 注册单个C函数
+ void RegisterMethod(cc8* fname, lua_CFunction func);
+
+ // 把preloader加到package.preload里,当require"libname"时lua的loader_preload根据
+ // libname找到preloader直接加载。用来实现需要require的时候才加载,并且加载过一次后
+ // package.loaded记录下来,下次不会再加载。通过require会调用这个preloader。
+ void RegisterPreloader(cc8* libname, lua_CFunction preloader);
+
+ // 根据luaL_Reg建立lib table,并在_G和package.loaded建立对libname的索引,指向lib table。
+ void RegisterLib(cc8* libname, const luaL_Reg* l);
+
+#if LUA_BIND_ENABLE_PLAIN_CLASS
+ // 注册纯lua类的注册函数,用来创建纯lua类。
+ void RegisterPlainClassRegistry(cc8* name);
+#endif
+
+#if LUA_BIND_ENABLE_PLAIN_ENUM
+ // 注册纯lua的枚举,以防止修改枚举值。
+ void RegisterPlainEnumRegistry(cc8* name);
+#endif
+
+ protected:
+
+ friend class VM;
+
+ // 屏蔽对State的地址相关操作
+ void* operator &();
+ void* operator new(size_t size);
+
+ lua_State* const mState;
+ };
+
+ //--------------------------------------------------------------------------------//
+ // GetValue()模板特化
+
+ template <> bool State::GetValue < bool >(int idx, const bool value);
+ template <> cc8* State::GetValue < cc8* >(int idx, const cc8* value);
+ template <> double State::GetValue < double >(int idx, const double value);
+ template <> float State::GetValue < float >(int idx, const float value);
+ template <> s8 State::GetValue < s8 >(int idx, const s8 value);
+ template <> s16 State::GetValue < s16 >(int idx, const s16 value);
+ template <> s32 State::GetValue < s32 >(int idx, const s32 value);
+ template <> s64 State::GetValue < s64 >(int idx, const s64 value);
+ template <> u8 State::GetValue < u8 >(int idx, const u8 value);
+ template <> u16 State::GetValue < u16 >(int idx, const u16 value);
+ template <> u32 State::GetValue < u32 >(int idx, const u32 value);
+ template <> u64 State::GetValue < u64 >(int idx, const u64 value);
+ template <> std::string State::GetValue < std::string >(int idx, const std::string value);
+ template <> const void* State::GetValue < const void* >(int idx, const void* value);
+
+ //--------------------------------------------------------------------------------//
+ // CheckValue模板特化
+
+ template <> bool State::CheckValue < bool >(int idx);
+ template <> cc8* State::CheckValue < cc8* >(int idx);
+ template <> double State::CheckValue < double >(int idx);
+ template <> float State::CheckValue < float >(int idx);
+ template <> s8 State::CheckValue < s8 >(int idx);
+ template <> s16 State::CheckValue < s16 >(int idx);
+ template <> s32 State::CheckValue < s32 >(int idx);
+ template <> s64 State::CheckValue < s64 >(int idx);
+ template <> u8 State::CheckValue < u8 >(int idx);
+ template <> u16 State::CheckValue < u16 >(int idx);
+ template <> u32 State::CheckValue < u32 >(int idx);
+ template <> u64 State::CheckValue < u64 >(int idx);
+ template <> std::string State::CheckValue < std::string >(int idx);
+ template <> const void* State::CheckValue < const void* >(int idx);
+
+ // 在成员方法里创建State并对参数进行检查。
+#define LUA_BIND_SETUP(L, params) \
+ LuaBind::State state(L); \
+ if(!state.CheckParams(1, params)) return 0
+
+#define LUA_BIND_STATE(L) \
+ LuaBind::State state(L)
+
+ //--------------------------------------------------------------------------------//
+
+ // 确保不安全的lua调用能够在调用之后返回到最初stack状态。
+ class ScopedState
+ : public State
+ {
+ public:
+ ScopedState(lua_State* state)
+ : State(state)
+ {
+ mRestoreTop = lua_gettop(mState);
+ }
+ ScopedState(const State& state)
+ : State(state)
+ {
+ mRestoreTop = lua_gettop(mState);
+ }
+ ~ScopedState()
+ {
+ if (mState) {
+ if (lua_gettop(mState) != mRestoreTop) {
+ lua_settop(mState, mRestoreTop);
+ }
+ }
+ }
+ private:
+ void* operator new(size_t);
+ int mRestoreTop;
+
+ };
+
+}
+
+#endif \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindState.inc b/Runtime/Lua/LuaBind/LuaBindState.inc
new file mode 100644
index 0000000..4e7090d
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindState.inc
@@ -0,0 +1,180 @@
+namespace LuaBind
+{
+
+ //
+ // 注册工厂,注册class table,以type name为键设置在名称空间上。在注册阶段不会设置元表,等到New方法调用的时候才会。
+ //
+ template<class TYPE>
+ void State::RegisterFactory()
+ {
+ cc8* type = TYPE::GetFactoryName();
+
+ lua_State* L = mState;
+ State& state = *this;
+
+ int top = lua_gettop(L); // namespace table
+ assert(lua_istable(L, top));
+
+ // class table
+ lua_newtable(L);
+ TYPE::RegisterClassShared(state);
+ TYPE::RegisterFactoryClass(state);
+ TYPE::RegisterClass(state);
+
+ // 检测TYPE里面是否没有注册必须的方法
+#define _assertmethod(I, NAME) \
+ GetField(I, NAME); \
+ assert(IsType(-1, LUA_TFUNCTION)); \
+ Pop();
+
+ //_assertmethod(-1, "New");
+
+#undef _assertmethod
+
+#if LUA_BIND_ENABLE_NATIVE_EXTEND
+ // .Extend()
+ lua_pushvalue(state, -1); // class table
+ lua_pushcclosure(state, TYPE::_ExtendFactory, 1);
+ lua_setfield(state, -2, "Extend");
+#endif
+
+ // class["__index"] = class
+ lua_pushvalue(state, -1); // class table
+ lua_setfield(state, -2, "__index");
+
+ TYPE::SetClassTableRef(state, -1);
+
+ SetField(top, type);
+
+ // reset top
+ lua_settop(L, top);
+
+ // 后处理
+ TYPE::RegisterPostprocess(state);
+ }
+
+ //
+ // Singleton
+ //
+ template<typename TYPE>
+ void State::RegisterSingleton()
+ {
+ lua_State* L = mState;
+ State& state = *this;
+
+ int top = lua_gettop(L); // namespace table
+ assert(lua_istable(L, top));
+
+ // class table.
+ lua_newtable(L);
+ TYPE::RegisterClassShared(state);
+ TYPE::RegisterSingletonClass(state);
+ TYPE::RegisterClass(state);
+
+ TYPE::SetClassTableRef(state, -1);
+
+ lua_pushvalue(state, -1);
+ lua_setfield(state, -2, "__index");
+
+#if LUA_BIND_ENABLE_NATIVE_EXTEND
+ // .Extend()
+ lua_pushvalue(state, -1); // class table
+ lua_pushcclosure(state, TYPE::_ExtendSingleton, 1);
+ lua_setfield(state, -2, "Extend");
+#endif
+
+ cc8* type = TYPE::GetSingletonName();
+ SetField(top, type);
+
+ // reset top
+ lua_settop(L, top);
+
+ // 后处理
+ TYPE::RegisterPostprocess(state);
+ }
+
+ template<typename TYPE>
+ void State::SetField(int idx, cc8* key, TYPE value)
+ {
+ if (IsTableOrUserdata(idx))
+ {
+ idx = AbsIndex(idx);
+ this->Push(value);
+ lua_setfield(mState, idx, key);
+ }
+ }
+
+ template<typename TYPE>
+ void State::SetFieldByIndex(int idx, int key, TYPE value)
+ {
+ if (IsTableOrUserdata(idx))
+ {
+ idx = AbsIndex(idx);
+ this->Push(value);
+ lua_rawseti(mState, idx, key);
+ }
+ }
+
+ template<typename TYPE>
+ TYPE State::GetField(int idx, cc8* key, TYPE value)
+ {
+ GetField(idx, key);
+ TYPE result = GetValue < TYPE >(-1, value);
+ this->Pop();
+
+ return result;
+ }
+
+ template<typename TYPE>
+ TYPE State::GetField(int idx, int key, TYPE value)
+ {
+ GetField(idx, key);
+ TYPE result = GetValue < TYPE >(-1, value);
+ Pop();
+
+ return result;
+ }
+
+ template<typename TYPE>
+ TYPE* State::GetUserdata(int idx)
+ {
+ void* p = nullptr;
+
+ if (IsType(idx, LUA_TUSERDATA))
+ {
+ p = *(void**)lua_touserdata(mState, idx);
+ }
+
+ return static_cast<TYPE*>(p);
+ }
+
+ template<typename TYPE>
+ TYPE* State::CheckUserdata(int idx)
+ {
+ if (IsType(idx, LUA_TUSERDATA))
+ {
+ if (lua_getmetatable(mState, idx)) // ref table
+ {
+ if (lua_getmetatable(mState, -1)) // member table
+ {
+ if (lua_getmetatable(mState, -1)) // class table
+ {
+ TYPE::PushClassTable(*this); // target class table
+ if (lua_rawequal(mState, -1, -2))
+ {
+ Pop(4); // ref\member\class\target class
+ TYPE* udata = GetUserdata<TYPE>(idx);
+ return udata; // userdata
+ }
+ Pop(2); // target class table\class table
+ }
+ Pop(1); // member table
+ }
+ Pop(1); // ref table
+ }
+ }
+ luaL_typerror(mState, idx, TYPE::GetClassName());
+ return nullptr;
+ }
+
+} \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindUtility.h b/Runtime/Lua/LuaBind/LuaBindUtility.h
new file mode 100644
index 0000000..ffc5099
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindUtility.h
@@ -0,0 +1,69 @@
+#ifndef __LUA_BIND_UTILITY_H__
+#define __LUA_BIND_UTILITY_H__
+
+// 导出native接口
+
+// RegisterClass 注册类的方法和成员,比如枚举、常量等到class table GetFactoryName 获得工厂的类名,
+// 同时用来避免注册时错误注册为了singleton,通过编译时报错避免
+#define LUA_BIND_DECL_FACTORY(type, ...) \
+ friend class ::State; \
+ friend class ::NativeClass<type,##__VA_ARGS__>; \
+ static void RegisterClass(::State&); \
+ static void RegisterPostprocess(::State&); \
+ static const char* GetFactoryName() { return #type; };\
+ static const char* GetClassName() { return #type; };\
+ static bool IsClassSingleton() { return false; }
+
+// 作为基类的抽象工厂类可以使用此宏,注册一个入口,在派生类的注册函数中调用,注册基类的这些方法。
+#define LUA_BIND_DECL_ABSTRACT_FACTORY() \
+ static void RegisterClass(::State&);\
+ static void RegisterPostprocess(::State&)
+
+// RegisterClass 注册类的方法和成员,比如枚举、常量等到class table GetSingletonName 获得单例的类名
+#define LUA_BIND_DECL_SINGLETON(type, ...) \
+ friend class ::State; \
+ friend class ::NativeClass<type,##__VA_ARGS__>; \
+ static void RegisterClass(::State&); \
+ static void RegisterPostprocess(::State&); \
+ static const char* GetSingletonName() { return #type; }; \
+ static const char* GetClassName() { return #type; }; \
+ static bool IsClassSingleton() { return true; }
+
+#define LUA_BIND_DECL_METHOD(mtd) static int mtd(lua_State* L)
+
+#define LUA_BIND_DECL_ENUM(e, under_line_index)
+
+// 标明方法实现的宏。上下文里有一个L。
+#define LUA_BIND_IMPL_METHOD(type, f) int type::f(lua_State* L)
+
+// 由应用程序实现的两个接口。上下文里有一个state。
+#define LUA_BIND_REGISTRY(type) void type::RegisterClass(::State& state)
+#define LUA_BIND_POSTPROCESS(type) void type::RegisterPostprocess(::State& state)
+
+// 用来注册的宏。之前这里忘了用可变宏,导致没有luaclastable ref没有注册对。
+#define LUA_BIND_REGISTER_FACTORY(state, param) state.RegisterFactory<param>()
+#define LUA_BIND_REGISTER_SINGLETON(state, param) state.RegisterSingleton<param>()
+#define LUA_BIND_REGISTER_ABSTRACT_FACTORY(state, type) type::RegisterPostprocess(state)
+#define LUA_BIND_REGISTER_METHODS(state, ...) \
+ do{ \
+ luaL_Reg __m[] = {__VA_ARGS__,{0, 0}}; \
+ state.RegisterMethods(__m); \
+ }while(0)
+#define LUA_BIND_REGISTER_ENUM(state, name, ...) \
+ do{ \
+ ::Enum __e[] = {__VA_ARGS__,{0, 0}}; \
+ state.RegisterEnum(name, __e); \
+ }while(0)
+
+#define LUA_BIND_PREPARE(L, T) \
+ LUA_BIND_STATE(L); \
+ T* self = state.GetUserdata<T>(1);
+
+#define LUA_BIND_CHECK(L, params)\
+ if(!state.CheckParams(1, params)) return 0
+
+#define LUA_BIND_INHERIT(state, type) type::RegisterClass(state)
+
+#define luaxport private
+
+#endif \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindVM.cpp b/Runtime/Lua/LuaBind/LuaBindVM.cpp
new file mode 100644
index 0000000..268a5ed
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindVM.cpp
@@ -0,0 +1,82 @@
+#include "LuaBindInternal.h"
+#include "LuaBindVM.h"
+
+namespace LuaBind
+{
+
+ VM::VMap VM::VMs; // 通过线程查找虚拟机,为了方便
+
+ VM* VM::TryGetVM(global_State* gState)
+ {
+ auto it = VMs.find(gState);
+ if (it != VMs.end())
+ return it->second;
+ else
+ return nullptr;
+ }
+
+ VM* VM::TryGetVM(lua_State* state)
+ {
+ return TryGetVM(G(state));
+ }
+
+ VM::VM()
+ : mStrongRefTable()
+ , mWeakRefTable()
+ {
+ mMainThread = luaL_newstate();
+ assert(mMainThread);
+ mGlobalState = G(mMainThread);
+
+ VMs.insert(std::pair<global_State*, VM*>(mGlobalState, this));
+ }
+
+ VM::~VM()
+ {
+ VMs.erase(mGlobalState);
+ lua_close(mMainThread);
+ }
+
+ // 初始化context
+ void VM::Setup()
+ {
+ LUA_BIND_STATE(mMainThread);
+
+ mStrongRefTable.Init(state, "GAMELAB_UNIVERSAL_STRONG_REFERENCE_TABLE");
+ mWeakRefTable.Init(state, "GAMELAB_UNIVERSAL_WEAK_REFERENCE_TABLE", "v");
+ }
+
+ lua_State* VM::CreateThread()
+ {
+ lua_State* thread = lua_newthread(mMainThread);
+ assert(thread);
+ return thread;
+ }
+
+ lua_State* VM::GetMainThread()
+ {
+ return mMainThread;
+ }
+
+ State VM::GetMainState()
+ {
+ return mMainThread;
+ }
+
+ RefTable& VM::GetStrongRefTable()
+ {
+ return mStrongRefTable;
+ }
+
+ RefTable& VM::GetWeakRefTable()
+ {
+ return mWeakRefTable;
+ }
+
+ void VM::OpenLibs()
+ {
+ assert(mMainThread);
+ luaL_openlibs(mMainThread);
+ }
+
+} \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindVM.h b/Runtime/Lua/LuaBind/LuaBindVM.h
new file mode 100644
index 0000000..3bfe899
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindVM.h
@@ -0,0 +1,58 @@
+#ifndef __LUA_BIND_CONTEXT_H__
+#define __LUA_BIND_CONTEXT_H__
+
+#include <map>
+#include <unordered_set>
+
+#include "LuaBindRef.h"
+#include "LuaBindConfig.h"
+#include "LuaBindState.h"
+#include "LuaBindGlobalState.h"
+
+namespace LuaBind
+{
+
+ // 单个lua_state相关的context。是一系列代理的集合,拷贝也没关系,主要是为了节约内存。
+ class VM
+ {
+ public:
+
+ // 根据global_State拿到虚拟机。
+ static VM* TryGetVM(global_State* gState);
+ static VM* TryGetVM(lua_State* state);
+
+ VM();
+ ~VM();
+
+ // 创建虚拟机后,需要手动调用Setup函数,初始化一些虚拟机状态。
+ void Setup();
+ void OpenLibs();
+
+ lua_State* GetMainThread();
+ lua_State* CreateThread();
+ State GetMainState();
+
+ RefTable& GetStrongRefTable();
+ RefTable& GetWeakRefTable();
+
+ private:
+
+ typedef std::map<global_State*, VM*> VMap;
+
+ static VMap VMs; // 通过global_State索引虚拟机,为了方便
+
+ RefTable mStrongRefTable; // GAMELAB_UNIVERSAL_STRONG_REFERENCE_TABLE
+ RefTable mWeakRefTable; // GAMELAB_UNIVERSAL_WEAK_REFERENCE_TABLE
+
+ global_State* mGlobalState; // 虚拟机的global_State,由当前虚拟机的所有线程共享
+ lua_State* mMainThread; // 主线程
+
+#if LUA_BIND_PROFILER
+ size_t mObjectCount; // 统计所有在此虚拟机中创建的实例
+#endif
+
+ };
+
+}
+
+#endif \ No newline at end of file
diff --git a/Runtime/Lua/LuaBind/LuaBindWatchDog.cpp b/Runtime/Lua/LuaBind/LuaBindWatchDog.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindWatchDog.cpp
diff --git a/Runtime/Lua/LuaBind/LuaBindWatchDog.h b/Runtime/Lua/LuaBind/LuaBindWatchDog.h
new file mode 100644
index 0000000..794faa9
--- /dev/null
+++ b/Runtime/Lua/LuaBind/LuaBindWatchDog.h
@@ -0,0 +1,33 @@
+#ifndef __LUA_BIND_DOG_H__
+#define __LUA_BIND_DOG_H__
+
+#include "LuaBindConfig.h"
+
+namespace LuaBind
+{
+
+ //
+ // NativeClass实例的引用计数额watch dog,只有在watch dog通过时才可以delete。
+ //
+ class WatchDog
+ {
+ public:
+ WatchDog()
+ : mVMRef(0)
+ , mNativeRef(0)
+ {
+ }
+
+ inline operator bool()
+ {
+ return mVMRef == 0 && mNativeRef == 0;
+ }
+
+ uint mVMRef; // 托管给的虚拟机数
+ uint mNativeRef; // 本地引用数
+
+ };
+
+}
+
+#endif \ No newline at end of file