From eb7f4986a88764c8321025cf4608a522e467fdf1 Mon Sep 17 00:00:00 2001 From: praydog Date: Wed, 26 Jun 2024 01:22:38 -0700 Subject: [PATCH] Lua: Add support for reading/modifying StructProperty properties --- lua-api/lib/include/ScriptUtility.hpp | 3 ++ lua-api/lib/src/ScriptContext.cpp | 6 +++- lua-api/lib/src/ScriptUtility.cpp | 32 ++++++++++++++-------- lua-api/lib/src/datatypes/StructObject.cpp | 27 +++++++++++++++++- 4 files changed, 55 insertions(+), 13 deletions(-) diff --git a/lua-api/lib/include/ScriptUtility.hpp b/lua-api/lib/include/ScriptUtility.hpp index 315c8e2d..ea03da92 100644 --- a/lua-api/lib/include/ScriptUtility.hpp +++ b/lua-api/lib/include/ScriptUtility.hpp @@ -8,7 +8,10 @@ namespace lua::utility { bool is_ue5(); sol::object prop_to_object(sol::this_state s, void* self, uevr::API::FProperty* desc, bool is_self_temporary = false); + sol::object prop_to_object(sol::this_state s, void* self, uevr::API::UStruct* desc, const std::wstring& name); sol::object prop_to_object(sol::this_state s, uevr::API::UObject* self, const std::wstring& name); + + void set_property(sol::this_state s, void* self, uevr::API::UStruct* desc, const std::wstring& name, sol::object value); void set_property(sol::this_state s, uevr::API::UObject* self, const std::wstring& name, sol::object value); sol::object call_function(sol::this_state s, uevr::API::UObject* self, uevr::API::UFunction* fn, sol::variadic_args args); diff --git a/lua-api/lib/src/ScriptContext.cpp b/lua-api/lib/src/ScriptContext.cpp index 37097ccd..e6a1e15e 100644 --- a/lua-api/lib/src/ScriptContext.cpp +++ b/lua-api/lib/src/ScriptContext.cpp @@ -7,6 +7,7 @@ #include #include "datatypes/Vector.hpp" +#include "datatypes/StructObject.hpp" #include "ScriptUtility.hpp" #include "ScriptContext.hpp" @@ -160,6 +161,7 @@ int ScriptContext::setup_bindings() { m_lua.registry()["uevr_context"] = this; lua::datatypes::bind_vectors(m_lua); + lua::datatypes::bind_struct_object(m_lua); m_lua.new_usertype("UEVR_PluginInitializeParam", "uevr_module", &UEVR_PluginInitializeParam::uevr_module, @@ -396,7 +398,9 @@ int ScriptContext::setup_bindings() { "get_property", [](sol::this_state s, uevr::API::UObject* self, const std::wstring& name) -> sol::object { return lua::utility::prop_to_object(s, self, name); }, - "set_property", &lua::utility::set_property, + "set_property", [](sol::this_state s, uevr::API::UObject* self, const std::wstring& name, sol::object value) { + lua::utility::set_property(s, self, name, value); + }, "call", [](sol::this_state s, uevr::API::UObject* self, const std::wstring& name, sol::variadic_args args) -> sol::object { return lua::utility::call_function(s, self, name, args); }, diff --git a/lua-api/lib/src/ScriptUtility.cpp b/lua-api/lib/src/ScriptUtility.cpp index 03fb2f02..9d9c9ed2 100644 --- a/lua-api/lib/src/ScriptUtility.cpp +++ b/lua-api/lib/src/ScriptUtility.cpp @@ -5,6 +5,7 @@ #include #include +#include #include namespace lua::utility { @@ -110,8 +111,9 @@ sol::object prop_to_object(sol::this_state s, void* self, uevr::API::FProperty* } } - // TODO: Return a reflected struct - return sol::make_object(s, sol::lua_nil); + auto struct_object = lua::datatypes::StructObject{struct_data, struct_desc}; + + return sol::make_object(s, struct_object); } case L"ArrayProperty"_fnv: { @@ -156,13 +158,7 @@ sol::object prop_to_object(sol::this_state s, void* self, uevr::API::FProperty* return sol::make_object(s, sol::lua_nil); } -sol::object prop_to_object(sol::this_state s, uevr::API::UObject* self, const std::wstring& name) { - const auto c = self->get_class(); - - if (c == nullptr) { - return sol::make_object(s, sol::lua_nil); - } - +sol::object prop_to_object(sol::this_state s, void* self, uevr::API::UStruct* c, const std::wstring& name) { const auto desc = c->find_property(name.c_str()); if (desc == nullptr) { @@ -179,13 +175,17 @@ sol::object prop_to_object(sol::this_state s, uevr::API::UObject* self, const st return prop_to_object(s, self, desc); } -void set_property(sol::this_state s, uevr::API::UObject* self, const std::wstring& name, sol::object value) { +sol::object prop_to_object(sol::this_state s, uevr::API::UObject* self, const std::wstring& name) { const auto c = self->get_class(); if (c == nullptr) { - throw sol::error("[set_property] Object has no class"); + return sol::make_object(s, sol::lua_nil); } + return prop_to_object(s, self, c, name); +} + +void set_property(sol::this_state s, void* self, uevr::API::UStruct* c, const std::wstring& name, sol::object value) { const auto desc = c->find_property(name.c_str()); if (desc == nullptr) { @@ -238,6 +238,16 @@ void set_property(sol::this_state s, uevr::API::UObject* self, const std::wstrin // NONE } +void set_property(sol::this_state s, uevr::API::UObject* self, const std::wstring& name, sol::object value) { + const auto c = self->get_class(); + + if (c == nullptr) { + throw sol::error("[set_property] Object has no class"); + } + + set_property(s, self, c, name, value); +} + sol::object call_function(sol::this_state s, uevr::API::UObject* self, uevr::API::UFunction* fn, sol::variadic_args args) { const auto fn_args = fn->get_child_properties(); diff --git a/lua-api/lib/src/datatypes/StructObject.cpp b/lua-api/lib/src/datatypes/StructObject.cpp index 071a5e7c..8bb7fb26 100644 --- a/lua-api/lib/src/datatypes/StructObject.cpp +++ b/lua-api/lib/src/datatypes/StructObject.cpp @@ -1,11 +1,36 @@ +#include + +#include #include namespace lua::datatypes { void bind_struct_object(sol::state_view& lua) { lua.new_usertype("StructObject", "get_address", [](StructObject& self) { return (uintptr_t)self.object; }, - "get_struct", [](StructObject& self) { return self.desc; } + "get_struct", [](StructObject& self) { return self.desc; }, + "get_property", [](sol::this_state s, StructObject* self, const std::wstring& name) -> sol::object { + return lua::utility::prop_to_object(s, self->object, self->desc, name); + }, + "set_property", [](sol::this_state s, StructObject* self, const std::wstring& name, sol::object value) { + lua::utility::set_property(s, self->object, self->desc, name, value); + }, + sol::meta_function::index, [](sol::this_state s, StructObject* self, sol::object index_obj) -> sol::object { + if (!index_obj.is()) { + return sol::make_object(s, sol::lua_nil); + } + + const auto name = ::utility::widen(index_obj.as()); + + return lua::utility::prop_to_object(s, self->object, self->desc, name); + }, + sol::meta_function::new_index, [](sol::this_state s, StructObject* self, sol::object index_obj, sol::object value) { + if (!index_obj.is()) { + return; + } + const auto name = ::utility::widen(index_obj.as()); + lua::utility::set_property(s, self->object, self->desc, name, value); + } ); } } \ No newline at end of file