feat(lua): added instance property and child access via reference
This commit is contained in:
parent
6bb1d8b3a4
commit
cbed2bac95
6 changed files with 88 additions and 5 deletions
|
@ -17,6 +17,12 @@ void Data::Variant::Serialize(pugi::xml_node node) const {
|
||||||
}, this->wrapped);
|
}, this->wrapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Data::Variant::PushLuaValue(lua_State* state) const {
|
||||||
|
return std::visit([&](auto&& it) {
|
||||||
|
return it.PushLuaValue(state);
|
||||||
|
}, this->wrapped);
|
||||||
|
}
|
||||||
|
|
||||||
Data::Variant Data::Variant::Deserialize(pugi::xml_node node) {
|
Data::Variant Data::Variant::Deserialize(pugi::xml_node node) {
|
||||||
if (Data::TYPE_MAP.count(node.name()) == 0) {
|
if (Data::TYPE_MAP.count(node.name()) == 0) {
|
||||||
Logger::fatalErrorf("Unknown type for instance: '%s'", node.name());
|
Logger::fatalErrorf("Unknown type for instance: '%s'", node.name());
|
||||||
|
|
|
@ -37,6 +37,7 @@ namespace Data {
|
||||||
Data::String ToString() const;
|
Data::String ToString() const;
|
||||||
|
|
||||||
void Serialize(pugi::xml_node node) const;
|
void Serialize(pugi::xml_node node) const;
|
||||||
|
void PushLuaValue(lua_State* state) const;
|
||||||
static Data::Variant Deserialize(pugi::xml_node node);
|
static Data::Variant Deserialize(pugi::xml_node node);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
#include "datatypes/ref.h"
|
#include "datatypes/ref.h"
|
||||||
#include "color3.h"
|
#include "datatypes/base.h"
|
||||||
|
#include "logger.h"
|
||||||
#include "meta.h" // IWYU pragma: keep
|
#include "meta.h" // IWYU pragma: keep
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
|
#include "lua.h"
|
||||||
|
|
||||||
Data::InstanceRef::InstanceRef() {};
|
Data::InstanceRef::InstanceRef() {};
|
||||||
Data::InstanceRef::InstanceRef(std::weak_ptr<Instance> instance) : ref(instance) {};
|
Data::InstanceRef::InstanceRef(std::weak_ptr<Instance> instance) : ref(instance) {};
|
||||||
|
@ -33,7 +36,61 @@ void Data::InstanceRef::Serialize(pugi::xml_node node) const {
|
||||||
// return Color3::FromHex(node.text().get());
|
// return Color3::FromHex(node.text().get());
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
static int inst_gc(lua_State*);
|
||||||
|
static int inst_index(lua_State*);
|
||||||
|
static const struct luaL_Reg metatable [] = {
|
||||||
|
{"__gc", inst_gc},
|
||||||
|
{"__index", inst_index},
|
||||||
|
{NULL, NULL} /* end of array */
|
||||||
|
};
|
||||||
|
|
||||||
void Data::InstanceRef::PushLuaValue(lua_State* L) const {
|
void Data::InstanceRef::PushLuaValue(lua_State* L) const {
|
||||||
// TODO:
|
if (ref.expired()) return lua_pushnil(L);
|
||||||
panic();
|
|
||||||
|
int n = lua_gettop(L);
|
||||||
|
|
||||||
|
auto userdata = (std::shared_ptr<Instance>**)lua_newuserdata(L, sizeof(void*));
|
||||||
|
|
||||||
|
// Create new pointer, and assign userdata a pointer to it
|
||||||
|
std::shared_ptr<Instance>* ptr = new std::shared_ptr<Instance>(ref);
|
||||||
|
*userdata = ptr;
|
||||||
|
|
||||||
|
// Create the instance's metatable
|
||||||
|
luaL_newmetatable(L, "__mt_instance");
|
||||||
|
luaL_register(L, NULL, metatable);
|
||||||
|
|
||||||
|
lua_setmetatable(L, n+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int inst_gc(lua_State* L) {
|
||||||
|
// Destroy the contained shared_ptr
|
||||||
|
auto userdata = (std::shared_ptr<Instance>**)lua_touserdata(L, -1);
|
||||||
|
delete *userdata;
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int inst_index(lua_State* L) {
|
||||||
|
auto userdata = (std::shared_ptr<Instance>**)lua_touserdata(L, 1);
|
||||||
|
std::shared_ptr<Instance> inst = **userdata;
|
||||||
|
std::string key(lua_tostring(L, 2));
|
||||||
|
lua_pop(L, 2);
|
||||||
|
|
||||||
|
// Read property
|
||||||
|
std::optional<PropertyMeta> meta = inst->GetPropertyMeta(key);
|
||||||
|
if (meta) {
|
||||||
|
Data::Variant value = inst->GetPropertyValue(key).expect();
|
||||||
|
value.PushLuaValue(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for child
|
||||||
|
std::optional<std::shared_ptr<Instance>> child = inst->FindFirstChild(key);
|
||||||
|
if (child) {
|
||||||
|
Data::InstanceRef(child.value()).PushLuaValue(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return luaL_error(L, "'%s' is not a valid member of %s", key.c_str(), inst->GetClass()->className.c_str());
|
||||||
}
|
}
|
|
@ -154,6 +154,14 @@ bool Instance::IsA(std::string className) {
|
||||||
return cur != nullptr;
|
return cur != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::shared_ptr<Instance>> Instance::FindFirstChild(std::string name) {
|
||||||
|
for (auto child : children) {
|
||||||
|
if (child->name == name)
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
static std::shared_ptr<Instance> DUMMY_INSTANCE;
|
static std::shared_ptr<Instance> DUMMY_INSTANCE;
|
||||||
DescendantsIterator Instance::GetDescendantsStart() {
|
DescendantsIterator Instance::GetDescendantsStart() {
|
||||||
return DescendantsIterator(GetChildren().size() > 0 ? GetChildren()[0] : DUMMY_INSTANCE);
|
return DescendantsIterator(GetChildren().size() > 0 ? GetChildren()[0] : DUMMY_INSTANCE);
|
||||||
|
|
|
@ -102,6 +102,7 @@ public:
|
||||||
DescendantsIterator GetDescendantsEnd();
|
DescendantsIterator GetDescendantsEnd();
|
||||||
// Utility functions
|
// Utility functions
|
||||||
inline void AddChild(std::shared_ptr<Instance> object) { object->SetParent(this->shared_from_this()); }
|
inline void AddChild(std::shared_ptr<Instance> object) { object->SetParent(this->shared_from_this()); }
|
||||||
|
std::optional<std::shared_ptr<Instance>> FindFirstChild(std::string);
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
result<Data::Variant, MemberNotFound> GetPropertyValue(std::string name);
|
result<Data::Variant, MemberNotFound> GetPropertyValue(std::string name);
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "objects/base/member.h"
|
#include "objects/base/member.h"
|
||||||
#include "objects/script/scriptcontext.h"
|
#include "objects/script/scriptcontext.h"
|
||||||
#include <luajit-2.1/lauxlib.h>
|
#include "objects/workspace.h"
|
||||||
#include <luajit-2.1/lua.h>
|
#include "lua.h"
|
||||||
|
|
||||||
const InstanceType Script::TYPE = {
|
const InstanceType Script::TYPE = {
|
||||||
.super = &Instance::TYPE,
|
.super = &Instance::TYPE,
|
||||||
|
@ -40,7 +40,17 @@ void Script::Run() {
|
||||||
lua_State* L = dataModel().value()->GetService<ScriptContext>()->state;
|
lua_State* L = dataModel().value()->GetService<ScriptContext>()->state;
|
||||||
|
|
||||||
// Initialize script globals
|
// Initialize script globals
|
||||||
|
lua_getglobal(L, "_G");
|
||||||
|
|
||||||
|
lua_pushstring(L, "game");
|
||||||
|
Data::InstanceRef(dataModel().value()).PushLuaValue(L);
|
||||||
|
lua_rawset(L, -3);
|
||||||
|
|
||||||
|
lua_pushstring(L, "workspace");
|
||||||
|
Data::InstanceRef(dataModel().value()->GetService<Workspace>()).PushLuaValue(L);
|
||||||
|
lua_rawset(L, -3);
|
||||||
|
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
luaL_loadstring(L, source.c_str());
|
luaL_loadstring(L, source.c_str());
|
||||||
int status = lua_pcall(L, 0, LUA_MULTRET, 0);
|
int status = lua_pcall(L, 0, LUA_MULTRET, 0);
|
||||||
|
|
Loading…
Add table
Reference in a new issue