From 74b8bca10ab3d4ff2d40c96f6a9967fb70d22448 Mon Sep 17 00:00:00 2001 From: maelstrom Date: Fri, 11 Jul 2025 00:05:17 +0200 Subject: [PATCH] feat(lua): added Instance.new for object creation --- core/src/lua/instancelib.cpp | 77 +++++++++++++++++++ core/src/objects/base/instance.h | 1 + .../objects/service/script/scriptcontext.cpp | 1 + editor/script/scriptdocument.cpp | 2 +- 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 core/src/lua/instancelib.cpp diff --git a/core/src/lua/instancelib.cpp b/core/src/lua/instancelib.cpp new file mode 100644 index 0000000..b81f333 --- /dev/null +++ b/core/src/lua/instancelib.cpp @@ -0,0 +1,77 @@ +#include "objects/base/instance.h" +#include "datatypes/ref.h" +#include "luaapis.h" // IWYU pragma: keep +#include "objects/meta.h" +#include + +static int lib_Instance_index(lua_State*); +static int lib_Instance_tostring(lua_State*); +static const struct luaL_Reg lib_Instance_metatable [] = { + {"__index", lib_Instance_index}, + {"__tostring", lib_Instance_tostring}, + {NULL, NULL} /* end of array */ +}; + +static int __lua_impl__Instance__new(lua_State* L) { + int n = lua_gettop(L); + + // First argument (className) + std::string className = luaL_checkstring(L, 1); + + // [Optional] Second argument (parent) + std::shared_ptr parent; + if (n > 1) { + parent = **(std::shared_ptr**)luaL_checkudata(L, 2, "__mt_instance"); + } + + // Look up class name + if (INSTANCE_MAP.count(className) == 0) + return luaL_error(L, "Attempt to create instance of unknown type '%s'", className.c_str()); + + const InstanceType* type = INSTANCE_MAP[className]; + + if (type->flags & (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE) || type->constructor == nullptr) + return luaL_error(L, "Attempt to create Instance of type '%s', which is not creatable", className.c_str()); + + std::shared_ptr object = type->constructor(); + + if (parent != nullptr) + object->SetParent(parent); + + InstanceRef(object).PushLuaValue(L); + return 1; +} + +void Instance::PushLuaLibrary(lua_State* L) { + lua_getglobal(L, "_G"); + lua_pushstring(L, "Instance"); + + lua_newuserdata(L, 0); + + // Create the library's metatable + luaL_newmetatable(L, "__mt_lib_Instance"); + luaL_register(L, NULL, lib_Instance_metatable); + lua_setmetatable(L, -2); + + lua_rawset(L, -3); + lua_pop(L, 1); +} + + +int lib_Instance_tostring(lua_State* L) { + lua_pushstring(L, "Instance"); + return 1; +} + +static int lib_Instance_index(lua_State* L) { + std::string key(lua_tostring(L, 2)); + lua_pop(L, 2); + + if (key == "new") { + lua_pushcfunction(L, __lua_impl__Instance__new); + return 1; + } + + return luaL_error(L, "%s is not a valid member of %s\n", key.c_str(), "Instance"); +} + diff --git a/core/src/objects/base/instance.h b/core/src/objects/base/instance.h index 7ae77fb..e565380 100644 --- a/core/src/objects/base/instance.h +++ b/core/src/objects/base/instance.h @@ -95,6 +95,7 @@ public: // Instance is abstract, so it should not implement GetClass directly virtual const InstanceType* GetClass() = 0; + static void PushLuaLibrary(lua_State*); // Defined in lua/instancelib.cpp bool SetParent(std::optional> newParent); std::optional> GetParent(); bool IsParentLocked(); diff --git a/core/src/objects/service/script/scriptcontext.cpp b/core/src/objects/service/script/scriptcontext.cpp index 205a7bd..6c3c0f4 100644 --- a/core/src/objects/service/script/scriptcontext.cpp +++ b/core/src/objects/service/script/scriptcontext.cpp @@ -46,6 +46,7 @@ void ScriptContext::InitService() { Vector3::PushLuaLibrary(state); CFrame::PushLuaLibrary(state); Color3::PushLuaLibrary(state); + Instance::PushLuaLibrary(state); // TODO: custom os library diff --git a/editor/script/scriptdocument.cpp b/editor/script/scriptdocument.cpp index 6a9db0e..d02e66a 100644 --- a/editor/script/scriptdocument.cpp +++ b/editor/script/scriptdocument.cpp @@ -71,7 +71,7 @@ class ObLuaLexer : public QsciLexerLua { //"foreach foreachi getn " // Openblocks extensions - "shared require game workspace " + "shared require game workspace Instance Instance.new " "_G _VERSION getfenv getmetatable ipairs loadstring " "next pairs pcall rawequal rawget rawset select "