Browse Source

Add serialization and deserialization of LUA global vars

Panagiotis Christopoulos Charitos 7 years ago
parent
commit
cdeddb3eb1

+ 126 - 7
src/anki/script/LuaBinder.cpp

@@ -23,6 +23,7 @@ LuaBinder::LuaBinder()
 LuaBinder::~LuaBinder()
 LuaBinder::~LuaBinder()
 {
 {
 	lua_close(m_l);
 	lua_close(m_l);
+	m_userDataSigToDataInfo.destroy(m_alloc);
 
 
 	ANKI_ASSERT(m_alloc.getMemoryPool().getAllocationsCount() == 0 && "Leaking memory");
 	ANKI_ASSERT(m_alloc.getMemoryPool().getAllocationsCount() == 0 && "Leaking memory");
 }
 }
@@ -107,16 +108,24 @@ Error LuaBinder::evalString(lua_State* state, const CString& str)
 	return err;
 	return err;
 }
 }
 
 
-void LuaBinder::createClass(lua_State* l, const char* className)
+void LuaBinder::createClass(lua_State* l, const LuaUserDataTypeInfo* typeInfo)
 {
 {
+	ANKI_ASSERT(typeInfo);
 	lua_newtable(l); // push new table
 	lua_newtable(l); // push new table
-	lua_setglobal(l, className); // pop and make global
-	luaL_newmetatable(l, className); // push
+	lua_setglobal(l, typeInfo->m_typeName); // pop and make global
+	luaL_newmetatable(l, typeInfo->m_typeName); // push
 	lua_pushstring(l, "__index"); // push
 	lua_pushstring(l, "__index"); // push
 	lua_pushvalue(l, -2); // pushes copy of the metatable
 	lua_pushvalue(l, -2); // pushes copy of the metatable
 	lua_settable(l, -3); // pop*2: metatable.__index = metatable
 	lua_settable(l, -3); // pop*2: metatable.__index = metatable
 
 
 	// After all these the metatable is in the top of tha stack
 	// After all these the metatable is in the top of tha stack
+
+	// Now, store the typeInfo
+	void* ud;
+	lua_getallocf(l, &ud);
+	ANKI_ASSERT(ud);
+	LuaBinder& binder = *static_cast<LuaBinder*>(ud);
+	binder.m_userDataSigToDataInfo.emplace(binder.m_alloc, typeInfo->m_signature, typeInfo);
 }
 }
 
 
 void LuaBinder::pushLuaCFuncMethod(lua_State* l, const char* name, lua_CFunction luafunc)
 void LuaBinder::pushLuaCFuncMethod(lua_State* l, const char* name, lua_CFunction luafunc)
@@ -265,7 +274,7 @@ void LuaBinder::destroyLuaThread(LuaThread& luaThread)
 	luaThread.m_reference = -1;
 	luaThread.m_reference = -1;
 }
 }
 
 
-void LuaBinder::dumpGlobals(lua_State* l, LuaBinderDumpGlobalsCallback& callback)
+void LuaBinder::serializeGlobals(lua_State* l, LuaBinderSerializeGlobalsCallback& callback)
 {
 {
 	ANKI_ASSERT(l);
 	ANKI_ASSERT(l);
 
 
@@ -295,11 +304,35 @@ void LuaBinder::dumpGlobals(lua_State* l, LuaBinderDumpGlobalsCallback& callback
 		switch(valueType)
 		switch(valueType)
 		{
 		{
 		case LUA_TNUMBER:
 		case LUA_TNUMBER:
-			callback.number(keyString, lua_tonumber(l, -1));
+		{
+			// Write name
+			callback.write(keyString.cstr(), keyString.getLength() + 1);
+
+			// Write type
+			U32 type = LUA_TNUMBER;
+			callback.write(&type, sizeof(type));
+
+			// Write value
+			F64 val = lua_tonumber(l, -1);
+			callback.write(&val, sizeof(val));
+
 			break;
 			break;
+		}
 		case LUA_TSTRING:
 		case LUA_TSTRING:
-			callback.string(keyString, lua_tostring(l, -1));
+		{
+			// Write name
+			callback.write(keyString.cstr(), keyString.getLength() + 1);
+
+			// Write type
+			U32 type = LUA_TSTRING;
+			callback.write(&type, sizeof(type));
+
+			// Write str len
+			CString val = lua_tostring(l, -1);
+			callback.write(val.cstr(), val.getLength() + 1);
+
 			break;
 			break;
+		}
 		case LUA_TUSERDATA:
 		case LUA_TUSERDATA:
 		{
 		{
 			LuaUserData* ud = static_cast<LuaUserData*>(lua_touserdata(l, -1));
 			LuaUserData* ud = static_cast<LuaUserData*>(lua_touserdata(l, -1));
@@ -313,12 +346,26 @@ void LuaBinder::dumpGlobals(lua_State* l, LuaBinderDumpGlobalsCallback& callback
 				if(dumpSize <= buff.getSize())
 				if(dumpSize <= buff.getSize())
 				{
 				{
 					cb(*ud, &buff[0], dumpSize);
 					cb(*ud, &buff[0], dumpSize);
-					callback.userData(keyString, ud->getDataTypeInfo(), &buff[0], dumpSize);
 				}
 				}
 				else
 				else
 				{
 				{
 					ANKI_ASSERT(!"TODO");
 					ANKI_ASSERT(!"TODO");
 				}
 				}
+
+				// Write name
+				callback.write(keyString.cstr(), keyString.getLength() + 1);
+
+				// Write type
+				U32 type = LUA_TUSERDATA;
+				callback.write(&type, sizeof(type));
+
+				// Write sig
+				callback.write(&ud->getDataTypeInfo().m_signature, sizeof(ud->getDataTypeInfo().m_signature));
+
+				// Write data
+				U32 size = dumpSize;
+				callback.write(&size, sizeof(size));
+				callback.write(&buff[0], dumpSize);
 			}
 			}
 			else
 			else
 			{
 			{
@@ -333,4 +380,76 @@ void LuaBinder::dumpGlobals(lua_State* l, LuaBinderDumpGlobalsCallback& callback
 	}
 	}
 }
 }
 
 
+void LuaBinder::deserializeGlobals(lua_State* l, const void* data, PtrSize dataSize)
+{
+	ANKI_ASSERT(dataSize > 0 && data);
+	const U8* ptr = static_cast<const U8*>(data);
+	const U8* end = ptr + dataSize;
+
+	while(ptr < end)
+	{
+		// Get name
+		CString name = reinterpret_cast<const char*>(ptr);
+		U32 len = name.getLength();
+		ANKI_ASSERT(len > 0);
+		ptr += len + 1;
+
+		// Get type
+		I type = *reinterpret_cast<const U32*>(ptr);
+		ptr += sizeof(U32);
+
+		switch(type)
+		{
+		case LUA_TNUMBER:
+		{
+			const F64 val = *reinterpret_cast<const F64*>(ptr);
+			ptr += sizeof(F64);
+			lua_pushnumber(l, val);
+			lua_setglobal(l, name.cstr());
+			break;
+		}
+		case LUA_TSTRING:
+		{
+			CString val = reinterpret_cast<const char*>(ptr);
+			const U len = val.getLength();
+			ptr += len + 1;
+			ANKI_ASSERT(len > 0);
+			lua_pushstring(l, val.cstr());
+			lua_setglobal(l, name.cstr());
+			break;
+		}
+		case LUA_TUSERDATA:
+		{
+			// Get sig
+			const I64 sig = *reinterpret_cast<const I64*>(ptr);
+			ptr += sizeof(sig);
+
+			// Get input data size
+			const U32 dataSize = *reinterpret_cast<const U32*>(ptr);
+			ptr += sizeof(dataSize);
+
+			// Get the type info
+			void* ud;
+			lua_getallocf(l, &ud);
+			ANKI_ASSERT(ud);
+			LuaBinder& binder = *static_cast<LuaBinder*>(ud);
+			auto it = binder.m_userDataSigToDataInfo.find(sig);
+			ANKI_ASSERT(it != binder.m_userDataSigToDataInfo.getEnd());
+			const LuaUserDataTypeInfo* typeInfo = *it;
+
+			// Create user data
+			LuaUserData* userData = static_cast<LuaUserData*>(lua_newuserdata(l, typeInfo->m_structureSize));
+			userData->initGarbageCollected(typeInfo);
+			ANKI_ASSERT(typeInfo->m_deserializeCallback);
+			typeInfo->m_deserializeCallback(ptr, *userData);
+			ptr += dataSize;
+			luaL_setmetatable(l, typeInfo->m_typeName);
+			lua_setglobal(l, name.cstr());
+
+			break;
+		}
+		}
+	}
+}
+
 } // end namespace anki
 } // end namespace anki

+ 14 - 8
src/anki/script/LuaBinder.h

@@ -11,6 +11,7 @@
 #include <anki/util/Allocator.h>
 #include <anki/util/Allocator.h>
 #include <anki/util/String.h>
 #include <anki/util/String.h>
 #include <anki/util/Functions.h>
 #include <anki/util/Functions.h>
+#include <anki/util/HashMap.h>
 #include <lua.hpp>
 #include <lua.hpp>
 #ifndef ANKI_LUA_HPP
 #ifndef ANKI_LUA_HPP
 #	error "Wrong LUA header included"
 #	error "Wrong LUA header included"
@@ -28,13 +29,18 @@ class LuaUserData;
 /// @memberof LuaUserData
 /// @memberof LuaUserData
 using LuaUserDataSerializeCallback = void (*)(LuaUserData& self, void* data, PtrSize& size);
 using LuaUserDataSerializeCallback = void (*)(LuaUserData& self, void* data, PtrSize& size);
 
 
+/// @memberof LuaUserData
+using LuaUserDataDeserializeCallback = void (*)(const void* data, LuaUserData& self);
+
 /// @memberof LuaUserData
 /// @memberof LuaUserData
 class LuaUserDataTypeInfo
 class LuaUserDataTypeInfo
 {
 {
 public:
 public:
 	I64 m_signature;
 	I64 m_signature;
 	const char* m_typeName;
 	const char* m_typeName;
+	PtrSize m_structureSize;
 	LuaUserDataSerializeCallback m_serializeCallback;
 	LuaUserDataSerializeCallback m_serializeCallback;
+	LuaUserDataDeserializeCallback m_deserializeCallback;
 };
 };
 
 
 /// LUA userdata.
 /// LUA userdata.
@@ -159,14 +165,10 @@ private:
 };
 };
 
 
 /// @memberof LuaBinder
 /// @memberof LuaBinder
-class LuaBinderDumpGlobalsCallback
+class LuaBinderSerializeGlobalsCallback
 {
 {
 public:
 public:
-	virtual void number(CString name, F64 value) = 0;
-
-	virtual void string(CString name, CString value) = 0;
-
-	virtual void userData(CString name, const LuaUserDataTypeInfo& typeInfo, const void* value, PtrSize valueSize) = 0;
+	virtual void write(const void* data, PtrSize dataSize) = 0;
 };
 };
 
 
 /// Lua binder class. A wrapper on top of LUA
 /// Lua binder class. A wrapper on top of LUA
@@ -231,7 +233,7 @@ public:
 	static void stackDump(lua_State* l);
 	static void stackDump(lua_State* l);
 
 
 	/// Create a new LUA class
 	/// Create a new LUA class
-	static void createClass(lua_State* l, const char* className);
+	static void createClass(lua_State* l, const LuaUserDataTypeInfo* typeInfo);
 
 
 	/// Add new function in a class that it's already in the stack
 	/// Add new function in a class that it's already in the stack
 	static void pushLuaCFuncMethod(lua_State* l, const char* name, lua_CFunction luafunc);
 	static void pushLuaCFuncMethod(lua_State* l, const char* name, lua_CFunction luafunc);
@@ -243,7 +245,10 @@ public:
 	static void pushLuaCFunc(lua_State* l, const char* name, lua_CFunction luafunc);
 	static void pushLuaCFunc(lua_State* l, const char* name, lua_CFunction luafunc);
 
 
 	/// Dump global variables.
 	/// Dump global variables.
-	static void dumpGlobals(lua_State* l, LuaBinderDumpGlobalsCallback& callback);
+	static void serializeGlobals(lua_State* l, LuaBinderSerializeGlobalsCallback& callback);
+
+	/// Deserialize global variables.
+	static void deserializeGlobals(lua_State* l, const void* data, PtrSize dataSize);
 
 
 	/// Make sure that the arguments match the argsCount number
 	/// Make sure that the arguments match the argsCount number
 	static ANKI_USE_RESULT Error checkArgsCount(lua_State* l, I argsCount);
 	static ANKI_USE_RESULT Error checkArgsCount(lua_State* l, I argsCount);
@@ -280,6 +285,7 @@ private:
 	ScriptAllocator m_alloc;
 	ScriptAllocator m_alloc;
 	lua_State* m_l = nullptr;
 	lua_State* m_l = nullptr;
 	void* m_parent = nullptr; ///< Point to the ScriptManager
 	void* m_parent = nullptr; ///< Point to the ScriptManager
+	HashMap<I64, const LuaUserDataTypeInfo*> m_userDataSigToDataInfo;
 
 
 	static void* luaAllocCallback(void* userData, void* ptr, PtrSize osize, PtrSize nsize);
 	static void* luaAllocCallback(void* userData, void* ptr, PtrSize osize, PtrSize nsize);
 
 

+ 48 - 18
src/anki/script/Math.cpp

@@ -11,14 +11,24 @@
 namespace anki
 namespace anki
 {
 {
 
 
-// Type info for Vec2
+/// Serialize Vec2
 static void serializeVec2(LuaUserData& self, void* data, PtrSize& size)
 static void serializeVec2(LuaUserData& self, void* data, PtrSize& size)
 {
 {
 	Vec2* obj = self.getData<Vec2>();
 	Vec2* obj = self.getData<Vec2>();
 	obj->serialize(data, size);
 	obj->serialize(data, size);
 }
 }
 
 
-LuaUserDataTypeInfo luaUserDataTypeInfoVec2 = {6804478823655046388, "Vec2", serializeVec2};
+/// De-serialize Vec2
+static void deserializeVec2(const void* data, LuaUserData& self)
+{
+	ANKI_ASSERT(data);
+	Vec2* obj = self.getData<Vec2>();
+	::new(obj) Vec2();
+	obj->deserialize(data);
+}
+
+LuaUserDataTypeInfo luaUserDataTypeInfoVec2 = {
+	6804478823655046388, "Vec2", LuaUserData::computeSizeForGarbageCollected<Vec2>(), serializeVec2, deserializeVec2};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Vec2>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Vec2>()
@@ -1047,7 +1057,7 @@ static int wrapVec2dot(lua_State* l)
 /// Wrap class Vec2.
 /// Wrap class Vec2.
 static inline void wrapVec2(lua_State* l)
 static inline void wrapVec2(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoVec2.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoVec2);
 	LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfoVec2.m_typeName, "new", wrapVec2Ctor);
 	LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfoVec2.m_typeName, "new", wrapVec2Ctor);
 	LuaBinder::pushLuaCFuncMethod(l, "__gc", wrapVec2Dtor);
 	LuaBinder::pushLuaCFuncMethod(l, "__gc", wrapVec2Dtor);
 	LuaBinder::pushLuaCFuncMethod(l, "getX", wrapVec2getX);
 	LuaBinder::pushLuaCFuncMethod(l, "getX", wrapVec2getX);
@@ -1070,14 +1080,24 @@ static inline void wrapVec2(lua_State* l)
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for Vec3
+/// Serialize Vec3
 static void serializeVec3(LuaUserData& self, void* data, PtrSize& size)
 static void serializeVec3(LuaUserData& self, void* data, PtrSize& size)
 {
 {
 	Vec3* obj = self.getData<Vec3>();
 	Vec3* obj = self.getData<Vec3>();
 	obj->serialize(data, size);
 	obj->serialize(data, size);
 }
 }
 
 
-LuaUserDataTypeInfo luaUserDataTypeInfoVec3 = {6804478823655046389, "Vec3", serializeVec3};
+/// De-serialize Vec3
+static void deserializeVec3(const void* data, LuaUserData& self)
+{
+	ANKI_ASSERT(data);
+	Vec3* obj = self.getData<Vec3>();
+	::new(obj) Vec3();
+	obj->deserialize(data);
+}
+
+LuaUserDataTypeInfo luaUserDataTypeInfoVec3 = {
+	6804478823655046389, "Vec3", LuaUserData::computeSizeForGarbageCollected<Vec3>(), serializeVec3, deserializeVec3};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Vec3>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Vec3>()
@@ -2249,7 +2269,7 @@ static int wrapVec3dot(lua_State* l)
 /// Wrap class Vec3.
 /// Wrap class Vec3.
 static inline void wrapVec3(lua_State* l)
 static inline void wrapVec3(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoVec3.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoVec3);
 	LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfoVec3.m_typeName, "new", wrapVec3Ctor);
 	LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfoVec3.m_typeName, "new", wrapVec3Ctor);
 	LuaBinder::pushLuaCFuncMethod(l, "__gc", wrapVec3Dtor);
 	LuaBinder::pushLuaCFuncMethod(l, "__gc", wrapVec3Dtor);
 	LuaBinder::pushLuaCFuncMethod(l, "getX", wrapVec3getX);
 	LuaBinder::pushLuaCFuncMethod(l, "getX", wrapVec3getX);
@@ -2274,14 +2294,24 @@ static inline void wrapVec3(lua_State* l)
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for Vec4
+/// Serialize Vec4
 static void serializeVec4(LuaUserData& self, void* data, PtrSize& size)
 static void serializeVec4(LuaUserData& self, void* data, PtrSize& size)
 {
 {
 	Vec4* obj = self.getData<Vec4>();
 	Vec4* obj = self.getData<Vec4>();
 	obj->serialize(data, size);
 	obj->serialize(data, size);
 }
 }
 
 
-LuaUserDataTypeInfo luaUserDataTypeInfoVec4 = {6804478823655046386, "Vec4", serializeVec4};
+/// De-serialize Vec4
+static void deserializeVec4(const void* data, LuaUserData& self)
+{
+	ANKI_ASSERT(data);
+	Vec4* obj = self.getData<Vec4>();
+	::new(obj) Vec4();
+	obj->deserialize(data);
+}
+
+LuaUserDataTypeInfo luaUserDataTypeInfoVec4 = {
+	6804478823655046386, "Vec4", LuaUserData::computeSizeForGarbageCollected<Vec4>(), serializeVec4, deserializeVec4};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Vec4>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Vec4>()
@@ -3559,7 +3589,7 @@ static int wrapVec4dot(lua_State* l)
 /// Wrap class Vec4.
 /// Wrap class Vec4.
 static inline void wrapVec4(lua_State* l)
 static inline void wrapVec4(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoVec4.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoVec4);
 	LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfoVec4.m_typeName, "new", wrapVec4Ctor);
 	LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfoVec4.m_typeName, "new", wrapVec4Ctor);
 	LuaBinder::pushLuaCFuncMethod(l, "__gc", wrapVec4Dtor);
 	LuaBinder::pushLuaCFuncMethod(l, "__gc", wrapVec4Dtor);
 	LuaBinder::pushLuaCFuncMethod(l, "getX", wrapVec4getX);
 	LuaBinder::pushLuaCFuncMethod(l, "getX", wrapVec4getX);
@@ -3586,8 +3616,8 @@ static inline void wrapVec4(lua_State* l)
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for Mat3
-LuaUserDataTypeInfo luaUserDataTypeInfoMat3 = {6306819796139686981, "Mat3", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoMat3 = {
+	6306819796139686981, "Mat3", LuaUserData::computeSizeForGarbageCollected<Mat3>(), nullptr, nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Mat3>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Mat3>()
@@ -3984,7 +4014,7 @@ static int wrapMat3setAll(lua_State* l)
 /// Wrap class Mat3.
 /// Wrap class Mat3.
 static inline void wrapMat3(lua_State* l)
 static inline void wrapMat3(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoMat3.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoMat3);
 	LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfoMat3.m_typeName, "new", wrapMat3Ctor);
 	LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfoMat3.m_typeName, "new", wrapMat3Ctor);
 	LuaBinder::pushLuaCFuncMethod(l, "__gc", wrapMat3Dtor);
 	LuaBinder::pushLuaCFuncMethod(l, "__gc", wrapMat3Dtor);
 	LuaBinder::pushLuaCFuncMethod(l, "copy", wrapMat3copy);
 	LuaBinder::pushLuaCFuncMethod(l, "copy", wrapMat3copy);
@@ -3994,8 +4024,8 @@ static inline void wrapMat3(lua_State* l)
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for Mat3x4
-LuaUserDataTypeInfo luaUserDataTypeInfoMat3x4 = {-2654194732934255869, "Mat3x4", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoMat3x4 = {
+	-2654194732934255869, "Mat3x4", LuaUserData::computeSizeForGarbageCollected<Mat3x4>(), nullptr, nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Mat3x4>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Mat3x4>()
@@ -4410,7 +4440,7 @@ static int wrapMat3x4setAll(lua_State* l)
 /// Wrap class Mat3x4.
 /// Wrap class Mat3x4.
 static inline void wrapMat3x4(lua_State* l)
 static inline void wrapMat3x4(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoMat3x4.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoMat3x4);
 	LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfoMat3x4.m_typeName, "new", wrapMat3x4Ctor);
 	LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfoMat3x4.m_typeName, "new", wrapMat3x4Ctor);
 	LuaBinder::pushLuaCFuncMethod(l, "__gc", wrapMat3x4Dtor);
 	LuaBinder::pushLuaCFuncMethod(l, "__gc", wrapMat3x4Dtor);
 	LuaBinder::pushLuaCFuncMethod(l, "copy", wrapMat3x4copy);
 	LuaBinder::pushLuaCFuncMethod(l, "copy", wrapMat3x4copy);
@@ -4420,8 +4450,8 @@ static inline void wrapMat3x4(lua_State* l)
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for Transform
-LuaUserDataTypeInfo luaUserDataTypeInfoTransform = {7048620195620777229, "Transform", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoTransform = {
+	7048620195620777229, "Transform", LuaUserData::computeSizeForGarbageCollected<Transform>(), nullptr, nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Transform>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Transform>()
@@ -4920,7 +4950,7 @@ static int wrapTransformsetScale(lua_State* l)
 /// Wrap class Transform.
 /// Wrap class Transform.
 static inline void wrapTransform(lua_State* l)
 static inline void wrapTransform(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoTransform.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoTransform);
 	LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfoTransform.m_typeName, "new", wrapTransformCtor);
 	LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfoTransform.m_typeName, "new", wrapTransformCtor);
 	LuaBinder::pushLuaCFuncMethod(l, "__gc", wrapTransformDtor);
 	LuaBinder::pushLuaCFuncMethod(l, "__gc", wrapTransformDtor);
 	LuaBinder::pushLuaCFuncMethod(l, "copy", wrapTransformcopy);
 	LuaBinder::pushLuaCFuncMethod(l, "copy", wrapTransformcopy);

+ 6 - 6
src/anki/script/Renderer.cpp

@@ -22,8 +22,8 @@ static MainRenderer* getMainRenderer(lua_State* l)
 	return &scriptManager->getMainRenderer();
 	return &scriptManager->getMainRenderer();
 }
 }
 
 
-// Type info for Dbg
-LuaUserDataTypeInfo luaUserDataTypeInfoDbg = {-2784798555522127122, "Dbg", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoDbg = {
+	-2784798555522127122, "Dbg", LuaUserData::computeSizeForGarbageCollected<Dbg>(), nullptr, nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Dbg>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Dbg>()
@@ -128,14 +128,14 @@ static int wrapDbgsetEnabled(lua_State* l)
 /// Wrap class Dbg.
 /// Wrap class Dbg.
 static inline void wrapDbg(lua_State* l)
 static inline void wrapDbg(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoDbg.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoDbg);
 	LuaBinder::pushLuaCFuncMethod(l, "getEnabled", wrapDbggetEnabled);
 	LuaBinder::pushLuaCFuncMethod(l, "getEnabled", wrapDbggetEnabled);
 	LuaBinder::pushLuaCFuncMethod(l, "setEnabled", wrapDbgsetEnabled);
 	LuaBinder::pushLuaCFuncMethod(l, "setEnabled", wrapDbgsetEnabled);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for MainRenderer
-LuaUserDataTypeInfo luaUserDataTypeInfoMainRenderer = {919289102518575326, "MainRenderer", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoMainRenderer = {
+	919289102518575326, "MainRenderer", LuaUserData::computeSizeForGarbageCollected<MainRenderer>(), nullptr, nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<MainRenderer>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<MainRenderer>()
@@ -191,7 +191,7 @@ static int wrapMainRenderergetAspectRatio(lua_State* l)
 /// Wrap class MainRenderer.
 /// Wrap class MainRenderer.
 static inline void wrapMainRenderer(lua_State* l)
 static inline void wrapMainRenderer(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoMainRenderer.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoMainRenderer);
 	LuaBinder::pushLuaCFuncMethod(l, "getAspectRatio", wrapMainRenderergetAspectRatio);
 	LuaBinder::pushLuaCFuncMethod(l, "getAspectRatio", wrapMainRenderergetAspectRatio);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }

+ 111 - 66
src/anki/script/Scene.cpp

@@ -61,8 +61,11 @@ static EventManager* getEventManager(lua_State* l)
 
 
 using WeakArraySceneNodePtr = WeakArray<SceneNode*>;
 using WeakArraySceneNodePtr = WeakArray<SceneNode*>;
 
 
-// Type info for WeakArraySceneNodePtr
-LuaUserDataTypeInfo luaUserDataTypeInfoWeakArraySceneNodePtr = {4158963409681942864, "WeakArraySceneNodePtr", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoWeakArraySceneNodePtr = {4158963409681942864,
+	"WeakArraySceneNodePtr",
+	LuaUserData::computeSizeForGarbageCollected<WeakArraySceneNodePtr>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<WeakArraySceneNodePtr>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<WeakArraySceneNodePtr>()
@@ -180,14 +183,17 @@ static int wrapWeakArraySceneNodePtrgetAt(lua_State* l)
 /// Wrap class WeakArraySceneNodePtr.
 /// Wrap class WeakArraySceneNodePtr.
 static inline void wrapWeakArraySceneNodePtr(lua_State* l)
 static inline void wrapWeakArraySceneNodePtr(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoWeakArraySceneNodePtr.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoWeakArraySceneNodePtr);
 	LuaBinder::pushLuaCFuncMethod(l, "getSize", wrapWeakArraySceneNodePtrgetSize);
 	LuaBinder::pushLuaCFuncMethod(l, "getSize", wrapWeakArraySceneNodePtrgetSize);
 	LuaBinder::pushLuaCFuncMethod(l, "getAt", wrapWeakArraySceneNodePtrgetAt);
 	LuaBinder::pushLuaCFuncMethod(l, "getAt", wrapWeakArraySceneNodePtrgetAt);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for MoveComponent
-LuaUserDataTypeInfo luaUserDataTypeInfoMoveComponent = {2038493110845313445, "MoveComponent", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoMoveComponent = {2038493110845313445,
+	"MoveComponent",
+	LuaUserData::computeSizeForGarbageCollected<MoveComponent>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<MoveComponent>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<MoveComponent>()
@@ -595,7 +601,7 @@ static int wrapMoveComponentgetLocalTransform(lua_State* l)
 /// Wrap class MoveComponent.
 /// Wrap class MoveComponent.
 static inline void wrapMoveComponent(lua_State* l)
 static inline void wrapMoveComponent(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoMoveComponent.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoMoveComponent);
 	LuaBinder::pushLuaCFuncMethod(l, "setLocalOrigin", wrapMoveComponentsetLocalOrigin);
 	LuaBinder::pushLuaCFuncMethod(l, "setLocalOrigin", wrapMoveComponentsetLocalOrigin);
 	LuaBinder::pushLuaCFuncMethod(l, "getLocalOrigin", wrapMoveComponentgetLocalOrigin);
 	LuaBinder::pushLuaCFuncMethod(l, "getLocalOrigin", wrapMoveComponentgetLocalOrigin);
 	LuaBinder::pushLuaCFuncMethod(l, "setLocalRotation", wrapMoveComponentsetLocalRotation);
 	LuaBinder::pushLuaCFuncMethod(l, "setLocalRotation", wrapMoveComponentsetLocalRotation);
@@ -607,8 +613,11 @@ static inline void wrapMoveComponent(lua_State* l)
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for LightComponent
-LuaUserDataTypeInfo luaUserDataTypeInfoLightComponent = {7940823622056993903, "LightComponent", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoLightComponent = {7940823622056993903,
+	"LightComponent",
+	LuaUserData::computeSizeForGarbageCollected<LightComponent>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<LightComponent>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<LightComponent>()
@@ -1190,7 +1199,7 @@ static int wrapLightComponentgetShadowEnabled(lua_State* l)
 /// Wrap class LightComponent.
 /// Wrap class LightComponent.
 static inline void wrapLightComponent(lua_State* l)
 static inline void wrapLightComponent(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoLightComponent.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoLightComponent);
 	LuaBinder::pushLuaCFuncMethod(l, "setDiffuseColor", wrapLightComponentsetDiffuseColor);
 	LuaBinder::pushLuaCFuncMethod(l, "setDiffuseColor", wrapLightComponentsetDiffuseColor);
 	LuaBinder::pushLuaCFuncMethod(l, "getDiffuseColor", wrapLightComponentgetDiffuseColor);
 	LuaBinder::pushLuaCFuncMethod(l, "getDiffuseColor", wrapLightComponentgetDiffuseColor);
 	LuaBinder::pushLuaCFuncMethod(l, "setRadius", wrapLightComponentsetRadius);
 	LuaBinder::pushLuaCFuncMethod(l, "setRadius", wrapLightComponentsetRadius);
@@ -1206,8 +1215,11 @@ static inline void wrapLightComponent(lua_State* l)
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for DecalComponent
-LuaUserDataTypeInfo luaUserDataTypeInfoDecalComponent = {-1979693900066114370, "DecalComponent", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoDecalComponent = {-1979693900066114370,
+	"DecalComponent",
+	LuaUserData::computeSizeForGarbageCollected<DecalComponent>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<DecalComponent>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<DecalComponent>()
@@ -1419,15 +1431,18 @@ static int wrapDecalComponentupdateShape(lua_State* l)
 /// Wrap class DecalComponent.
 /// Wrap class DecalComponent.
 static inline void wrapDecalComponent(lua_State* l)
 static inline void wrapDecalComponent(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoDecalComponent.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoDecalComponent);
 	LuaBinder::pushLuaCFuncMethod(l, "setDiffuseDecal", wrapDecalComponentsetDiffuseDecal);
 	LuaBinder::pushLuaCFuncMethod(l, "setDiffuseDecal", wrapDecalComponentsetDiffuseDecal);
 	LuaBinder::pushLuaCFuncMethod(l, "setSpecularRoughnessDecal", wrapDecalComponentsetSpecularRoughnessDecal);
 	LuaBinder::pushLuaCFuncMethod(l, "setSpecularRoughnessDecal", wrapDecalComponentsetSpecularRoughnessDecal);
 	LuaBinder::pushLuaCFuncMethod(l, "updateShape", wrapDecalComponentupdateShape);
 	LuaBinder::pushLuaCFuncMethod(l, "updateShape", wrapDecalComponentupdateShape);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for LensFlareComponent
-LuaUserDataTypeInfo luaUserDataTypeInfoLensFlareComponent = {-2019248835133422777, "LensFlareComponent", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoLensFlareComponent = {-2019248835133422777,
+	"LensFlareComponent",
+	LuaUserData::computeSizeForGarbageCollected<LensFlareComponent>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<LensFlareComponent>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<LensFlareComponent>()
@@ -1542,14 +1557,17 @@ static int wrapLensFlareComponentsetColorMultiplier(lua_State* l)
 /// Wrap class LensFlareComponent.
 /// Wrap class LensFlareComponent.
 static inline void wrapLensFlareComponent(lua_State* l)
 static inline void wrapLensFlareComponent(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoLensFlareComponent.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoLensFlareComponent);
 	LuaBinder::pushLuaCFuncMethod(l, "setFirstFlareSize", wrapLensFlareComponentsetFirstFlareSize);
 	LuaBinder::pushLuaCFuncMethod(l, "setFirstFlareSize", wrapLensFlareComponentsetFirstFlareSize);
 	LuaBinder::pushLuaCFuncMethod(l, "setColorMultiplier", wrapLensFlareComponentsetColorMultiplier);
 	LuaBinder::pushLuaCFuncMethod(l, "setColorMultiplier", wrapLensFlareComponentsetColorMultiplier);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for TriggerComponent
-LuaUserDataTypeInfo luaUserDataTypeInfoTriggerComponent = {7180780522076545145, "TriggerComponent", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoTriggerComponent = {7180780522076545145,
+	"TriggerComponent",
+	LuaUserData::computeSizeForGarbageCollected<TriggerComponent>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<TriggerComponent>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<TriggerComponent>()
@@ -1611,13 +1629,13 @@ static int wrapTriggerComponentgetContactSceneNodes(lua_State* l)
 /// Wrap class TriggerComponent.
 /// Wrap class TriggerComponent.
 static inline void wrapTriggerComponent(lua_State* l)
 static inline void wrapTriggerComponent(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoTriggerComponent.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoTriggerComponent);
 	LuaBinder::pushLuaCFuncMethod(l, "getContactSceneNodes", wrapTriggerComponentgetContactSceneNodes);
 	LuaBinder::pushLuaCFuncMethod(l, "getContactSceneNodes", wrapTriggerComponentgetContactSceneNodes);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for SceneNode
-LuaUserDataTypeInfo luaUserDataTypeInfoSceneNode = {-2220074417980276571, "SceneNode", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoSceneNode = {
+	-2220074417980276571, "SceneNode", LuaUserData::computeSizeForGarbageCollected<SceneNode>(), nullptr, nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<SceneNode>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<SceneNode>()
@@ -2042,7 +2060,7 @@ static int wrapSceneNodegetTriggerComponent(lua_State* l)
 /// Wrap class SceneNode.
 /// Wrap class SceneNode.
 static inline void wrapSceneNode(lua_State* l)
 static inline void wrapSceneNode(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoSceneNode.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoSceneNode);
 	LuaBinder::pushLuaCFuncMethod(l, "getName", wrapSceneNodegetName);
 	LuaBinder::pushLuaCFuncMethod(l, "getName", wrapSceneNodegetName);
 	LuaBinder::pushLuaCFuncMethod(l, "addChild", wrapSceneNodeaddChild);
 	LuaBinder::pushLuaCFuncMethod(l, "addChild", wrapSceneNodeaddChild);
 	LuaBinder::pushLuaCFuncMethod(l, "setMarkedForDeletion", wrapSceneNodesetMarkedForDeletion);
 	LuaBinder::pushLuaCFuncMethod(l, "setMarkedForDeletion", wrapSceneNodesetMarkedForDeletion);
@@ -2054,8 +2072,8 @@ static inline void wrapSceneNode(lua_State* l)
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for ModelNode
-LuaUserDataTypeInfo luaUserDataTypeInfoModelNode = {-1856316251880904290, "ModelNode", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoModelNode = {
+	-1856316251880904290, "ModelNode", LuaUserData::computeSizeForGarbageCollected<ModelNode>(), nullptr, nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<ModelNode>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<ModelNode>()
@@ -2115,13 +2133,16 @@ static int wrapModelNodegetSceneNodeBase(lua_State* l)
 /// Wrap class ModelNode.
 /// Wrap class ModelNode.
 static inline void wrapModelNode(lua_State* l)
 static inline void wrapModelNode(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoModelNode.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoModelNode);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapModelNodegetSceneNodeBase);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapModelNodegetSceneNodeBase);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for PerspectiveCameraNode
-LuaUserDataTypeInfo luaUserDataTypeInfoPerspectiveCameraNode = {-7590637754681648962, "PerspectiveCameraNode", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoPerspectiveCameraNode = {-7590637754681648962,
+	"PerspectiveCameraNode",
+	LuaUserData::computeSizeForGarbageCollected<PerspectiveCameraNode>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<PerspectiveCameraNode>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<PerspectiveCameraNode>()
@@ -2248,14 +2269,17 @@ static int wrapPerspectiveCameraNodesetAll(lua_State* l)
 /// Wrap class PerspectiveCameraNode.
 /// Wrap class PerspectiveCameraNode.
 static inline void wrapPerspectiveCameraNode(lua_State* l)
 static inline void wrapPerspectiveCameraNode(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoPerspectiveCameraNode.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoPerspectiveCameraNode);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapPerspectiveCameraNodegetSceneNodeBase);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapPerspectiveCameraNodegetSceneNodeBase);
 	LuaBinder::pushLuaCFuncMethod(l, "setAll", wrapPerspectiveCameraNodesetAll);
 	LuaBinder::pushLuaCFuncMethod(l, "setAll", wrapPerspectiveCameraNodesetAll);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for PointLightNode
-LuaUserDataTypeInfo luaUserDataTypeInfoPointLightNode = {8507789763949195644, "PointLightNode", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoPointLightNode = {8507789763949195644,
+	"PointLightNode",
+	LuaUserData::computeSizeForGarbageCollected<PointLightNode>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<PointLightNode>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<PointLightNode>()
@@ -2373,14 +2397,17 @@ static int wrapPointLightNodeloadLensFlare(lua_State* l)
 /// Wrap class PointLightNode.
 /// Wrap class PointLightNode.
 static inline void wrapPointLightNode(lua_State* l)
 static inline void wrapPointLightNode(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoPointLightNode.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoPointLightNode);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapPointLightNodegetSceneNodeBase);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapPointLightNodegetSceneNodeBase);
 	LuaBinder::pushLuaCFuncMethod(l, "loadLensFlare", wrapPointLightNodeloadLensFlare);
 	LuaBinder::pushLuaCFuncMethod(l, "loadLensFlare", wrapPointLightNodeloadLensFlare);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for SpotLightNode
-LuaUserDataTypeInfo luaUserDataTypeInfoSpotLightNode = {-9214759951813290587, "SpotLightNode", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoSpotLightNode = {-9214759951813290587,
+	"SpotLightNode",
+	LuaUserData::computeSizeForGarbageCollected<SpotLightNode>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<SpotLightNode>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<SpotLightNode>()
@@ -2440,13 +2467,16 @@ static int wrapSpotLightNodegetSceneNodeBase(lua_State* l)
 /// Wrap class SpotLightNode.
 /// Wrap class SpotLightNode.
 static inline void wrapSpotLightNode(lua_State* l)
 static inline void wrapSpotLightNode(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoSpotLightNode.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoSpotLightNode);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapSpotLightNodegetSceneNodeBase);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapSpotLightNodegetSceneNodeBase);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for StaticCollisionNode
-LuaUserDataTypeInfo luaUserDataTypeInfoStaticCollisionNode = {-4376619865753613291, "StaticCollisionNode", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoStaticCollisionNode = {-4376619865753613291,
+	"StaticCollisionNode",
+	LuaUserData::computeSizeForGarbageCollected<StaticCollisionNode>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<StaticCollisionNode>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<StaticCollisionNode>()
@@ -2506,13 +2536,16 @@ static int wrapStaticCollisionNodegetSceneNodeBase(lua_State* l)
 /// Wrap class StaticCollisionNode.
 /// Wrap class StaticCollisionNode.
 static inline void wrapStaticCollisionNode(lua_State* l)
 static inline void wrapStaticCollisionNode(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoStaticCollisionNode.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoStaticCollisionNode);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapStaticCollisionNodegetSceneNodeBase);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapStaticCollisionNodegetSceneNodeBase);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for ParticleEmitterNode
-LuaUserDataTypeInfo luaUserDataTypeInfoParticleEmitterNode = {4851204309813771919, "ParticleEmitterNode", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoParticleEmitterNode = {4851204309813771919,
+	"ParticleEmitterNode",
+	LuaUserData::computeSizeForGarbageCollected<ParticleEmitterNode>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<ParticleEmitterNode>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<ParticleEmitterNode>()
@@ -2572,13 +2605,16 @@ static int wrapParticleEmitterNodegetSceneNodeBase(lua_State* l)
 /// Wrap class ParticleEmitterNode.
 /// Wrap class ParticleEmitterNode.
 static inline void wrapParticleEmitterNode(lua_State* l)
 static inline void wrapParticleEmitterNode(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoParticleEmitterNode.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoParticleEmitterNode);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapParticleEmitterNodegetSceneNodeBase);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapParticleEmitterNodegetSceneNodeBase);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for ReflectionProbeNode
-LuaUserDataTypeInfo luaUserDataTypeInfoReflectionProbeNode = {-801309373000950648, "ReflectionProbeNode", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoReflectionProbeNode = {-801309373000950648,
+	"ReflectionProbeNode",
+	LuaUserData::computeSizeForGarbageCollected<ReflectionProbeNode>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<ReflectionProbeNode>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<ReflectionProbeNode>()
@@ -2638,13 +2674,16 @@ static int wrapReflectionProbeNodegetSceneNodeBase(lua_State* l)
 /// Wrap class ReflectionProbeNode.
 /// Wrap class ReflectionProbeNode.
 static inline void wrapReflectionProbeNode(lua_State* l)
 static inline void wrapReflectionProbeNode(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoReflectionProbeNode.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoReflectionProbeNode);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapReflectionProbeNodegetSceneNodeBase);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapReflectionProbeNodegetSceneNodeBase);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for ReflectionProxyNode
-LuaUserDataTypeInfo luaUserDataTypeInfoReflectionProxyNode = {2307826176097073810, "ReflectionProxyNode", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoReflectionProxyNode = {2307826176097073810,
+	"ReflectionProxyNode",
+	LuaUserData::computeSizeForGarbageCollected<ReflectionProxyNode>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<ReflectionProxyNode>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<ReflectionProxyNode>()
@@ -2704,13 +2743,16 @@ static int wrapReflectionProxyNodegetSceneNodeBase(lua_State* l)
 /// Wrap class ReflectionProxyNode.
 /// Wrap class ReflectionProxyNode.
 static inline void wrapReflectionProxyNode(lua_State* l)
 static inline void wrapReflectionProxyNode(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoReflectionProxyNode.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoReflectionProxyNode);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapReflectionProxyNodegetSceneNodeBase);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapReflectionProxyNodegetSceneNodeBase);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for OccluderNode
-LuaUserDataTypeInfo luaUserDataTypeInfoOccluderNode = {-6885028590097645115, "OccluderNode", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoOccluderNode = {-6885028590097645115,
+	"OccluderNode",
+	LuaUserData::computeSizeForGarbageCollected<OccluderNode>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<OccluderNode>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<OccluderNode>()
@@ -2770,13 +2812,13 @@ static int wrapOccluderNodegetSceneNodeBase(lua_State* l)
 /// Wrap class OccluderNode.
 /// Wrap class OccluderNode.
 static inline void wrapOccluderNode(lua_State* l)
 static inline void wrapOccluderNode(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoOccluderNode.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoOccluderNode);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapOccluderNodegetSceneNodeBase);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapOccluderNodegetSceneNodeBase);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for DecalNode
-LuaUserDataTypeInfo luaUserDataTypeInfoDecalNode = {1097508121406753350, "DecalNode", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoDecalNode = {
+	1097508121406753350, "DecalNode", LuaUserData::computeSizeForGarbageCollected<DecalNode>(), nullptr, nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<DecalNode>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<DecalNode>()
@@ -2836,13 +2878,13 @@ static int wrapDecalNodegetSceneNodeBase(lua_State* l)
 /// Wrap class DecalNode.
 /// Wrap class DecalNode.
 static inline void wrapDecalNode(lua_State* l)
 static inline void wrapDecalNode(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoDecalNode.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoDecalNode);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapDecalNodegetSceneNodeBase);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapDecalNodegetSceneNodeBase);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for TriggerNode
-LuaUserDataTypeInfo luaUserDataTypeInfoTriggerNode = {-3029786875306006141, "TriggerNode", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoTriggerNode = {
+	-3029786875306006141, "TriggerNode", LuaUserData::computeSizeForGarbageCollected<TriggerNode>(), nullptr, nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<TriggerNode>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<TriggerNode>()
@@ -2902,13 +2944,13 @@ static int wrapTriggerNodegetSceneNodeBase(lua_State* l)
 /// Wrap class TriggerNode.
 /// Wrap class TriggerNode.
 static inline void wrapTriggerNode(lua_State* l)
 static inline void wrapTriggerNode(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoTriggerNode.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoTriggerNode);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapTriggerNodegetSceneNodeBase);
 	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapTriggerNodegetSceneNodeBase);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for SceneGraph
-LuaUserDataTypeInfo luaUserDataTypeInfoSceneGraph = {-7754439619132389154, "SceneGraph", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoSceneGraph = {
+	-7754439619132389154, "SceneGraph", LuaUserData::computeSizeForGarbageCollected<SceneGraph>(), nullptr, nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<SceneGraph>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<SceneGraph>()
@@ -3716,7 +3758,7 @@ static int wrapSceneGraphsetActiveCameraNode(lua_State* l)
 /// Wrap class SceneGraph.
 /// Wrap class SceneGraph.
 static inline void wrapSceneGraph(lua_State* l)
 static inline void wrapSceneGraph(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoSceneGraph.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoSceneGraph);
 	LuaBinder::pushLuaCFuncMethod(l, "newPerspectiveCameraNode", wrapSceneGraphnewPerspectiveCameraNode);
 	LuaBinder::pushLuaCFuncMethod(l, "newPerspectiveCameraNode", wrapSceneGraphnewPerspectiveCameraNode);
 	LuaBinder::pushLuaCFuncMethod(l, "newModelNode", wrapSceneGraphnewModelNode);
 	LuaBinder::pushLuaCFuncMethod(l, "newModelNode", wrapSceneGraphnewModelNode);
 	LuaBinder::pushLuaCFuncMethod(l, "newPointLightNode", wrapSceneGraphnewPointLightNode);
 	LuaBinder::pushLuaCFuncMethod(l, "newPointLightNode", wrapSceneGraphnewPointLightNode);
@@ -3732,8 +3774,8 @@ static inline void wrapSceneGraph(lua_State* l)
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for Event
-LuaUserDataTypeInfo luaUserDataTypeInfoEvent = {1660689530604735101, "Event", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoEvent = {
+	1660689530604735101, "Event", LuaUserData::computeSizeForGarbageCollected<Event>(), nullptr, nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Event>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Event>()
@@ -3795,13 +3837,13 @@ static int wrapEventgetAssociatedSceneNodes(lua_State* l)
 /// Wrap class Event.
 /// Wrap class Event.
 static inline void wrapEvent(lua_State* l)
 static inline void wrapEvent(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoEvent.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoEvent);
 	LuaBinder::pushLuaCFuncMethod(l, "getAssociatedSceneNodes", wrapEventgetAssociatedSceneNodes);
 	LuaBinder::pushLuaCFuncMethod(l, "getAssociatedSceneNodes", wrapEventgetAssociatedSceneNodes);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for LightEvent
-LuaUserDataTypeInfo luaUserDataTypeInfoLightEvent = {840634010629725278, "LightEvent", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoLightEvent = {
+	840634010629725278, "LightEvent", LuaUserData::computeSizeForGarbageCollected<LightEvent>(), nullptr, nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<LightEvent>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<LightEvent>()
@@ -3919,14 +3961,17 @@ static int wrapLightEventsetFrequency(lua_State* l)
 /// Wrap class LightEvent.
 /// Wrap class LightEvent.
 static inline void wrapLightEvent(lua_State* l)
 static inline void wrapLightEvent(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoLightEvent.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoLightEvent);
 	LuaBinder::pushLuaCFuncMethod(l, "setIntensityMultiplier", wrapLightEventsetIntensityMultiplier);
 	LuaBinder::pushLuaCFuncMethod(l, "setIntensityMultiplier", wrapLightEventsetIntensityMultiplier);
 	LuaBinder::pushLuaCFuncMethod(l, "setFrequency", wrapLightEventsetFrequency);
 	LuaBinder::pushLuaCFuncMethod(l, "setFrequency", wrapLightEventsetFrequency);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }
 
 
-// Type info for EventManager
-LuaUserDataTypeInfo luaUserDataTypeInfoEventManager = {-6959305329499243407, "EventManager", nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoEventManager = {-6959305329499243407,
+	"EventManager",
+	LuaUserData::computeSizeForGarbageCollected<EventManager>(),
+	nullptr,
+	nullptr};
 
 
 template<>
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<EventManager>()
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<EventManager>()
@@ -4014,7 +4059,7 @@ static int wrapEventManagernewLightEvent(lua_State* l)
 /// Wrap class EventManager.
 /// Wrap class EventManager.
 static inline void wrapEventManager(lua_State* l)
 static inline void wrapEventManager(lua_State* l)
 {
 {
-	LuaBinder::createClass(l, luaUserDataTypeInfoEventManager.m_typeName);
+	LuaBinder::createClass(l, &luaUserDataTypeInfoEventManager);
 	LuaBinder::pushLuaCFuncMethod(l, "newLightEvent", wrapEventManagernewLightEvent);
 	LuaBinder::pushLuaCFuncMethod(l, "newLightEvent", wrapEventManagernewLightEvent);
 	lua_settop(l, 0);
 	lua_settop(l, 0);
 }
 }

+ 7 - 2
src/anki/script/ScriptEnvironment.h

@@ -40,9 +40,14 @@ public:
 		return LuaBinder::evalString(m_thread.m_luaState, str);
 		return LuaBinder::evalString(m_thread.m_luaState, str);
 	}
 	}
 
 
-	void dumpGlobals(LuaBinderDumpGlobalsCallback& callback)
+	void serializeGlobals(LuaBinderSerializeGlobalsCallback& callback)
 	{
 	{
-		LuaBinder::dumpGlobals(m_thread.m_luaState, callback);
+		LuaBinder::serializeGlobals(m_thread.m_luaState, callback);
+	}
+
+	void deserializeGlobals(const void* data, PtrSize dataSize)
+	{
+		LuaBinder::deserializeGlobals(m_thread.m_luaState, data, dataSize);
 	}
 	}
 
 
 	lua_State& getLuaState()
 	lua_State& getLuaState()

+ 21 - 5
src/anki/script/lua_glue_gen.py

@@ -548,13 +548,13 @@ def class_(class_el):
 
 
 	class_name = class_el.get("name")
 	class_name = class_el.get("name")
 
 
-	wglue("// Type info for %s" % class_name)
-
 	# Write serializer
 	# Write serializer
 	serialize = class_el.get("serialize") is not None and class_el.get("serialize") == "true"
 	serialize = class_el.get("serialize") is not None and class_el.get("serialize") == "true"
 	if serialize:
 	if serialize:
+		# Serialize
 		serialize_cb_name = "serialize%s" % class_name
 		serialize_cb_name = "serialize%s" % class_name
-		wglue("static void %s(LuaUserData& self, void* data, PtrSize& size)" % (serialize_cb_name))
+		wglue("/// Serialize %s" % class_name)
+		wglue("static void %s(LuaUserData& self, void* data, PtrSize& size)" % serialize_cb_name)
 		wglue("{")
 		wglue("{")
 		ident(1)
 		ident(1)
 		wglue("%s* obj = self.getData<%s>();" % (class_name, class_name))
 		wglue("%s* obj = self.getData<%s>();" % (class_name, class_name))
@@ -562,13 +562,29 @@ def class_(class_el):
 		ident(-1)
 		ident(-1)
 		wglue("}")
 		wglue("}")
 		wglue("")
 		wglue("")
+
+		# Deserialize
+		deserialize_cb_name = "deserialize%s" % class_name
+		wglue("/// De-serialize %s" % class_name)
+		wglue("static void %s(const void* data, LuaUserData& self)" % deserialize_cb_name)
+		wglue("{")
+		ident(1)
+		wglue("ANKI_ASSERT(data);")
+		wglue("%s* obj = self.getData<%s>();" % (class_name, class_name))
+		wglue("::new(obj) %s();" % class_name)
+		wglue("obj->deserialize(data);")
+		ident(-1)
+		wglue("}")
+		wglue("")
 	else:
 	else:
 		serialize_cb_name = "nullptr"
 		serialize_cb_name = "nullptr"
+		deserialize_cb_name = "nullptr"
 
 
 	# Write the type info
 	# Write the type info
 	wglue("LuaUserDataTypeInfo luaUserDataTypeInfo%s = {" % class_name)
 	wglue("LuaUserDataTypeInfo luaUserDataTypeInfo%s = {" % class_name)
 	ident(1)
 	ident(1)
-	wglue("%d, \"%s\", %s" % (type_sig(class_name), class_name, serialize_cb_name))
+	wglue("%d, \"%s\", LuaUserData::computeSizeForGarbageCollected<%s>(), %s, %s"
+			% (type_sig(class_name), class_name, class_name, serialize_cb_name, deserialize_cb_name))
 	ident(-1)
 	ident(-1)
 	wglue("};")
 	wglue("};")
 	wglue("")
 	wglue("")
@@ -616,7 +632,7 @@ def class_(class_el):
 	wglue("static inline void wrap%s(lua_State* l)" % class_name)
 	wglue("static inline void wrap%s(lua_State* l)" % class_name)
 	wglue("{")
 	wglue("{")
 	ident(1)
 	ident(1)
-	wglue("LuaBinder::createClass(l, luaUserDataTypeInfo%s.m_typeName);" % class_name)
+	wglue("LuaBinder::createClass(l, &luaUserDataTypeInfo%s);" % class_name)
 
 
 	# Register constructor
 	# Register constructor
 	if has_constructor:
 	if has_constructor:

+ 17 - 0
src/anki/util/HashMap.h

@@ -38,6 +38,23 @@ public:
 	}
 	}
 };
 };
 
 
+/// Specialization for I64 keys.
+template<>
+class DefaultHasher<I64>
+{
+public:
+	U64 operator()(const I64 a) const
+	{
+		union
+		{
+			U64 u64;
+			I64 i64;
+		};
+		i64 = a;
+		return u64;
+	}
+};
+
 /// Hash map template.
 /// Hash map template.
 template<typename TKey, typename TValue, typename THasher = DefaultHasher<TKey>>
 template<typename TKey, typename TValue, typename THasher = DefaultHasher<TKey>>
 class HashMap
 class HashMap

+ 20 - 19
tests/script/LuaBinder.cpp

@@ -66,7 +66,7 @@ myFunc()
 	ANKI_TEST_EXPECT_NO_ERR(env->evalString(script1));
 	ANKI_TEST_EXPECT_NO_ERR(env->evalString(script1));
 }
 }
 
 
-ANKI_TEST(Script, LuaBinderThreadsDump)
+ANKI_TEST(Script, LuaBinderSerialize)
 {
 {
 	ScriptManager sm;
 	ScriptManager sm;
 	ANKI_TEST_EXPECT_NO_ERR(sm.init(allocAligned, nullptr));
 	ANKI_TEST_EXPECT_NO_ERR(sm.init(allocAligned, nullptr));
@@ -82,29 +82,30 @@ vec = Vec3.new(1, 2, 3)
 
 
 	ANKI_TEST_EXPECT_NO_ERR(env->evalString(script));
 	ANKI_TEST_EXPECT_NO_ERR(env->evalString(script));
 
 
-	class Callback : public LuaBinderDumpGlobalsCallback
+	class Callback : public LuaBinderSerializeGlobalsCallback
 	{
 	{
 	public:
 	public:
-		void number(CString name, F64 value)
-		{
-			printf("%s = %f\n", name.cstr(), value);
-		}
-
-		void string(CString name, CString value)
-		{
-			printf("%s = %s\n", name.cstr(), value.cstr());
-		}
+		Array<U8, 1024> m_buff;
+		U32 m_offset = 0;
 
 
-		void userData(CString name, const LuaUserDataTypeInfo& typeInfo, const void* value, PtrSize valueSize)
+		void write(const void* data, PtrSize dataSize)
 		{
 		{
-			if(LuaUserData::getDataTypeInfoFor<Vec3>().m_signature == typeInfo.m_signature)
-			{
-				Vec3 v;
-				v.deserialize(value);
-				printf("%s = %f %f %f\n", name.cstr(), v.x(), v.y(), v.z());
-			}
+			memcpy(&m_buff[m_offset], data, dataSize);
+			m_offset += dataSize;
 		}
 		}
 	} callback;
 	} callback;
 
 
-	env->dumpGlobals(callback);
+	env->serializeGlobals(callback);
+	env.reset(nullptr);
+	ANKI_TEST_EXPECT_NO_ERR(sm.newScriptEnvironment(env));
+
+	env->deserializeGlobals(&callback.m_buff[0], callback.m_offset);
+
+	static const char* script2 = R"(
+print(num)
+print(str)
+print(vec:getX(), vec:getY(), vec:getZ())
+)";
+
+	ANKI_TEST_EXPECT_NO_ERR(env->evalString(script2));
 }
 }