diff --git a/CMakeLists.txt b/CMakeLists.txt index bd34f3b0..6a4cb529 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -597,9 +597,13 @@ set(luavrlib_SOURCES "") list(APPEND luavrlib_SOURCES "lua-api/lib/src/ScriptContext.cpp" "lua-api/lib/src/ScriptState.cpp" + "lua-api/lib/src/ScriptUtility.cpp" + "lua-api/lib/src/datatypes/StructObject.cpp" "lua-api/lib/src/datatypes/Vector.cpp" "lua-api/lib/include/ScriptContext.hpp" "lua-api/lib/include/ScriptState.hpp" + "lua-api/lib/include/ScriptUtility.hpp" + "lua-api/lib/include/datatypes/StructObject.hpp" "lua-api/lib/include/datatypes/Vector.hpp" ) diff --git a/lua-api/lib/include/ScriptUtility.hpp b/lua-api/lib/include/ScriptUtility.hpp new file mode 100644 index 00000000..315c8e2d --- /dev/null +++ b/lua-api/lib/include/ScriptUtility.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +namespace lua::utility { + uevr::API::UScriptStruct* get_vector_struct(); + 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, uevr::API::UObject* self, const std::wstring& name); + 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); + sol::object call_function(sol::this_state s, uevr::API::UObject* self, const std::wstring& name, sol::variadic_args args); +} \ No newline at end of file diff --git a/lua-api/lib/include/datatypes/StructObject.hpp b/lua-api/lib/include/datatypes/StructObject.hpp new file mode 100644 index 00000000..1e6f3f27 --- /dev/null +++ b/lua-api/lib/include/datatypes/StructObject.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +namespace lua::datatypes { + struct StructObject { + StructObject(void* obj, uevr::API::UStruct* def) : object{ obj }, desc{ def } {} + + void* object{ nullptr }; + uevr::API::UStruct* desc{ nullptr }; + }; + + void bind_struct_object(sol::state_view& lua); +} \ No newline at end of file diff --git a/lua-api/lib/include/datatypes/Vector.hpp b/lua-api/lib/include/datatypes/Vector.hpp index 40640e15..30547df3 100644 --- a/lua-api/lib/include/datatypes/Vector.hpp +++ b/lua-api/lib/include/datatypes/Vector.hpp @@ -1,8 +1,13 @@ #pragma once +#define GLM_ENABLE_EXPERIMENTAL + #include #include #include +#include +#include + #include #include diff --git a/lua-api/lib/src/ScriptContext.cpp b/lua-api/lib/src/ScriptContext.cpp index 57d4b9b1..37097ccd 100644 --- a/lua-api/lib/src/ScriptContext.cpp +++ b/lua-api/lib/src/ScriptContext.cpp @@ -8,6 +8,7 @@ #include "datatypes/Vector.hpp" +#include "ScriptUtility.hpp" #include "ScriptContext.hpp" namespace uevr { @@ -155,453 +156,6 @@ void ScriptContext::setup_callback_bindings() { ); } -sol::object call_function(sol::this_state s, uevr::API::UObject* self, uevr::API::UFunction* fn, sol::variadic_args args); - -uevr::API::UScriptStruct* get_vector_struct() { - static auto vector_struct = []() { - const auto modern_class = uevr::API::get()->find_uobject(L"ScriptStruct /Script/CoreUObject.Vector"); - const auto old_class = modern_class == nullptr ? uevr::API::get()->find_uobject(L"ScriptStruct /Script/CoreUObject.Object.Vector") : nullptr; - - return modern_class != nullptr ? modern_class : old_class; - }(); - - return vector_struct; -} - -bool is_ue5() { - static auto cached_result = []() { - const auto c = get_vector_struct(); - - if (c == nullptr) { - return false; - } - - return c->get_struct_size() == sizeof(glm::dvec3); - }(); - - return cached_result; -} - -sol::object prop_to_object(sol::this_state s, void* self, uevr::API::FProperty* desc, bool is_self_temporary = false) { - const auto propc = desc->get_class(); - - if (propc == nullptr) { - return sol::make_object(s, sol::lua_nil); - } - - const auto name_hash = utility::hash(propc->get_fname()->to_string()); - const auto offset = desc->get_offset(); - - switch (name_hash) { - case L"BoolProperty"_fnv: - { - const auto fbp = (uevr::API::FBoolProperty*)desc; - return sol::make_object(s, fbp->get_value_from_object(self)); - } - case L"FloatProperty"_fnv: - return sol::make_object(s, *(float*)((uintptr_t)self + offset)); - case L"DoubleProperty"_fnv: - return sol::make_object(s, *(double*)((uintptr_t)self + offset)); - case L"IntProperty"_fnv: - return sol::make_object(s, *(int32_t*)((uintptr_t)self + offset)); - case L"UIntProperty"_fnv: - case L"UInt32Property"_fnv: - return sol::make_object(s, *(uint32_t*)((uintptr_t)self + offset)); - case L"NameProperty"_fnv: - return sol::make_object(s, *(uevr::API::FName*)((uintptr_t)self + offset)); - case L"ObjectProperty"_fnv: - if (*(uevr::API::UObject**)((uintptr_t)self + offset) == nullptr) { - return sol::make_object(s, sol::lua_nil); - } - - return sol::make_object(s, *(uevr::API::UObject**)((uintptr_t)self + offset)); - case L"ClassProperty"_fnv: - if (*(uevr::API::UClass**)((uintptr_t)self + offset) == nullptr) { - return sol::make_object(s, sol::lua_nil); - } - - return sol::make_object(s, *(uevr::API::UClass**)((uintptr_t)self + offset)); - case L"StructProperty"_fnv: - { - const auto struct_data = (void*)((uintptr_t)self + offset); - const auto struct_desc = ((uevr::API::FStructProperty*)desc)->get_struct(); - - if (struct_desc == nullptr) { - return sol::make_object(s, sol::lua_nil); - } - - /*const auto struct_name_hash = utility::hash(struct_desc->get_fname()->to_string()); - - switch (struct_name_hash) { - case L"Vector"_fnv: - if (is_ue5()) { - return sol::make_object(s, (lua::datatypes::Vector3f*)struct_data); - } - - return sol::make_object(s, (lua::datatypes::Vector3f*)struct_data); - };*/ - - if (struct_desc == get_vector_struct()) { - if (is_ue5()) { - if (is_self_temporary) { - return sol::make_object(s, *(lua::datatypes::Vector3d*)struct_data); - } else { - return sol::make_object(s, (lua::datatypes::Vector3d*)struct_data); - } - } - - if (is_self_temporary) { - return sol::make_object(s, *(lua::datatypes::Vector3f*)struct_data); - } else { - return sol::make_object(s, (lua::datatypes::Vector3f*)struct_data); - } - } - - // TODO: Return a reflected struct - return sol::make_object(s, sol::lua_nil); - } - case L"ArrayProperty"_fnv: - { - const auto inner_prop = ((uevr::API::FArrayProperty*)desc)->get_inner(); - - if (inner_prop == nullptr) { - return sol::make_object(s, sol::lua_nil); - } - - const auto inner_c = inner_prop->get_class(); - - if (inner_c == nullptr) { - return sol::make_object(s, sol::lua_nil); - } - - const auto inner_name_hash = utility::hash(inner_c->get_fname()->to_string()); - - switch (inner_name_hash) { - case "ObjectProperty"_fnv: - { - const auto& arr = *(uevr::API::TArray*)((uintptr_t)self + offset); - - if (arr.data == nullptr || arr.count == 0) { - return sol::make_object(s, sol::lua_nil); - } - - auto lua_arr = std::vector{}; - - for (size_t i = 0; i < arr.count; ++i) { - lua_arr.push_back(arr.data[i]); - } - - return sol::make_object(s, lua_arr); - } - // TODO: Add support for other types - }; - - return sol::make_object(s, sol::lua_nil); - } - }; - - 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); - } - - const auto desc = c->find_property(name.c_str()); - - if (desc == nullptr) { - if (auto fn = c->find_function(name.c_str()); fn != nullptr) { - /*return sol::make_object(s, [self, s, fn](sol::variadic_args args) { - return call_function(s, self, fn, args); - });*/ - return sol::make_object(s, fn); - } - - return sol::make_object(s, sol::lua_nil); - } - - 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) { - const auto c = self->get_class(); - - if (c == nullptr) { - throw sol::error("[set_property] Object has no class"); - } - - const auto desc = c->find_property(name.c_str()); - - if (desc == nullptr) { - throw sol::error(std::format("[set_property] Property '{}' not found", utility::narrow(name))); - } - - const auto propc = desc->get_class(); - - if (propc == nullptr) { - throw sol::error(std::format("[set_property] Property '{}' has no class", utility::narrow(name))); - } - - const auto name_hash = utility::hash(propc->get_fname()->to_string()); - const auto offset = desc->get_offset(); - - switch (name_hash) { - case L"BoolProperty"_fnv: - { - const auto fbp = (uevr::API::FBoolProperty*)desc; - fbp->set_value_in_object(self, value.as()); - return; - } - case L"FloatProperty"_fnv: - //self.get_property(name) = value.as(); - *(float*)((uintptr_t)self + offset) = value.as(); - return; - case L"DoubleProperty"_fnv: - *(double*)((uintptr_t)self + offset) = value.as(); - return; - case L"IntProperty"_fnv: - *(int32_t*)((uintptr_t)self + offset) = value.as(); - return; - case L"UIntProperty"_fnv: - case L"UInt32Property"_fnv: - *(uint32_t*)((uintptr_t)self + offset) = value.as(); - return; - case L"NameProperty"_fnv: - //return sol::make_object(s, self.get_property(name)); - throw sol::error("Setting FName properties is not supported (yet)"); - case L"ObjectProperty"_fnv: - *(uevr::API::UObject**)((uintptr_t)self + offset) = value.as(); - return; - case L"ClassProperty"_fnv: - *(uevr::API::UClass**)((uintptr_t)self + offset) = value.as(); - return; - case L"ArrayProperty"_fnv: - throw sol::error("Setting array properties is not supported (yet)"); - }; - - // NONE -} - -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(); - - if (fn_args == nullptr) { - fn->call(self, nullptr); - return sol::make_object(s, sol::lua_nil); - } - - std::vector params{}; - size_t args_index{0}; - - const auto ps = fn->get_properties_size(); - const auto ma = fn->get_min_alignment(); - - if (ma > 1) { - params.resize(((ps + ma - 1) / ma) * ma); - } else { - params.resize(ps); - } - - params.resize(fn->get_properties_size()); - - uevr::API::FProperty* return_prop{nullptr}; - bool ret_is_bool{false}; - - //std::vector dynamic_data{}; - std::vector dynamic_strings{}; - - for (auto arg_desc = fn_args; arg_desc != nullptr; arg_desc = arg_desc->get_next()) { - const auto arg_c = arg_desc->get_class(); - - if (arg_c == nullptr) { - continue; - } - - const auto arg_c_name = arg_c->get_fname()->to_string(); - - if (!arg_c_name.contains(L"Property")) { - continue; - } - - const auto prop_desc = (uevr::API::FProperty*)arg_desc; - - if (!prop_desc->is_param()) { - continue; - } - - if (prop_desc->is_return_param()) { - return_prop = prop_desc; - - if (arg_c_name == L"BoolProperty") { - ret_is_bool = true; - } - - continue; - } - - const auto arg_hash = utility::hash(arg_c_name); - const auto offset = prop_desc->get_offset(); - - switch (arg_hash) { - case L"BoolProperty"_fnv: - { - const bool arg = args[args_index++].as(); - const auto fbp = (uevr::API::FBoolProperty*)prop_desc; - fbp->set_value_in_object(params.data(), arg); - continue; - } - case L"FloatProperty"_fnv: - { - const float arg = args[args_index++].as(); - *(float*)¶ms[offset] = arg; - continue; - } - case L"DoubleProperty"_fnv: - { - const double arg = args[args_index++].as(); - *(double*)¶ms[offset] = arg; - continue; - } - case L"IntProperty"_fnv: - case L"UIntProperty"_fnv: - case L"UInt32Property"_fnv: - { - const int32_t arg = args[args_index++].as(); - *(int32_t*)¶ms[offset] = arg; - continue; - } - case L"NameProperty"_fnv: - { - const auto arg_obj = args[args_index++]; - - if (arg_obj.is()) { - const auto arg = utility::widen(arg_obj.as()); - *(uevr::API::FName*)¶ms[offset] = uevr::API::FName{arg}; - } else if (arg_obj.is()) { - const auto arg = arg_obj.as(); - *(uevr::API::FName*)¶ms[offset] = uevr::API::FName{arg}; - } else if (arg_obj.is()) { - const auto arg = arg_obj.as(); - *(uevr::API::FName*)¶ms[offset] = arg; - } else { - throw sol::error("Invalid argument type for FName"); - } - - continue; - } - case L"ObjectProperty"_fnv: - { - const auto arg = args[args_index++].as(); - *(uevr::API::UObject**)¶ms[offset] = arg; - continue; - } - case L"ClassProperty"_fnv: - { - const auto arg = args[args_index++].as(); - *(uevr::API::UClass**)¶ms[offset] = arg; - continue; - } - case L"StructProperty"_fnv: - { - const auto arg_obj = args[args_index++]; - const auto struct_desc = ((uevr::API::FStructProperty*)prop_desc)->get_struct(); - - if (struct_desc == nullptr) { - throw sol::error("Struct property has no struct"); - } - - if (struct_desc == get_vector_struct()) { - if (arg_obj.is()) { - const auto arg = arg_obj.as(); - - if (is_ue5()) { - *(lua::datatypes::Vector3d*)¶ms[offset] = arg; - } else { - *(lua::datatypes::Vector3f*)¶ms[offset] = arg; - } - } else if (arg_obj.is()) { - const auto arg = arg_obj.as(); - - if (is_ue5()) { - *(lua::datatypes::Vector3d*)¶ms[offset] = arg; - } else { - *(lua::datatypes::Vector3f*)¶ms[offset] = arg; - } - } else { - throw sol::error("Invalid argument type for FVector"); - } - } - - continue; - } - case L"ArrayProperty"_fnv: - // TODO - throw sol::error("Array properties are not supported (yet)"); - continue; - case L"StrProperty"_fnv: - { - const auto arg_obj = args[args_index++]; - using FString = API::TArray; - - auto& fstr = *(FString*)¶ms[offset]; - - if (arg_obj.is()) { - dynamic_strings.push_back(arg_obj.as()); - - fstr.count = dynamic_strings.back().size() + 1; - fstr.data = (wchar_t*)dynamic_strings.back().c_str(); - } else if (arg_obj.is()) { - dynamic_strings.push_back(utility::widen(arg_obj.as())); - - fstr.count = dynamic_strings.back().size() + 1; - fstr.data = (wchar_t*)dynamic_strings.back().c_str(); - } else if (arg_obj.is()) { - dynamic_strings.push_back(arg_obj.as()); - - fstr.count = dynamic_strings.back().size() + 1; - } else { - throw sol::error("Invalid argument type for FString"); - } - continue; - } - default: - //spdlog::warn("Unknown property type when calling '{}': {}", utility::narrow(fn->get_fname()->to_string()), utility::narrow(arg_c_name)); - API::get()->log_warn(std::format("Unknown property type when calling '{}': {}", utility::narrow(fn->get_fname()->to_string()), utility::narrow(arg_c_name)).c_str()); - }; - } - - fn->call(self, params.data()); - - if (return_prop != nullptr) { - if (ret_is_bool) { - return sol::make_object(s, ((uevr::API::FBoolProperty*)return_prop)->get_value_from_object(params.data())); - } - - return prop_to_object(s, params.data(), return_prop, true); - } - - return sol::make_object(s, sol::lua_nil); -} - -sol::object call_function(sol::this_state s, uevr::API::UObject* self, const std::wstring& name, sol::variadic_args args) { - const auto c = self->get_class(); - - if (c == nullptr) { - return sol::make_object(s, sol::lua_nil); - } - - const auto fn = c->find_function(name.c_str()); - - if (fn == nullptr) { - return sol::make_object(s, sol::lua_nil); - } - - return call_function(s, self, fn, args); -} - int ScriptContext::setup_bindings() { m_lua.registry()["uevr_context"] = this; @@ -840,11 +394,11 @@ int ScriptContext::setup_bindings() { return self.get_property(name); }, "get_property", [](sol::this_state s, uevr::API::UObject* self, const std::wstring& name) -> sol::object { - return prop_to_object(s, self, name); + return lua::utility::prop_to_object(s, self, name); }, - "set_property", &set_property, + "set_property", &lua::utility::set_property, "call", [](sol::this_state s, uevr::API::UObject* self, const std::wstring& name, sol::variadic_args args) -> sol::object { - return call_function(s, self, name, args); + return lua::utility::call_function(s, self, name, args); }, sol::meta_function::index, [](sol::this_state s, uevr::API::UObject* self, sol::object index_obj) -> sol::object { if (!index_obj.is()) { @@ -853,7 +407,7 @@ int ScriptContext::setup_bindings() { const auto name = utility::widen(index_obj.as()); - return prop_to_object(s, self, name); + return lua::utility::prop_to_object(s, self, name); }, sol::meta_function::new_index, [](sol::this_state s, uevr::API::UObject* self, sol::object index_obj, sol::object value) { if (!index_obj.is()) { @@ -861,7 +415,7 @@ int ScriptContext::setup_bindings() { } const auto name = utility::widen(index_obj.as()); - set_property(s, self, name, value); + lua::utility::set_property(s, self, name, value); } ); @@ -885,7 +439,7 @@ int ScriptContext::setup_bindings() { m_lua.new_usertype("UEVR_UFunction", sol::meta_function::call, [](sol::this_state s, uevr::API::UFunction* fn, uevr::API::UObject* obj, sol::variadic_args args) -> sol::object { - return call_function(s, obj, fn, args); + return lua::utility::call_function(s, obj, fn, args); }, sol::base_classes, sol::bases(), "static_class", &uevr::API::UFunction::static_class, diff --git a/lua-api/lib/src/ScriptUtility.cpp b/lua-api/lib/src/ScriptUtility.cpp new file mode 100644 index 00000000..03fb2f02 --- /dev/null +++ b/lua-api/lib/src/ScriptUtility.cpp @@ -0,0 +1,457 @@ +#include +#include +#include + +#include + +#include +#include + +namespace lua::utility { +sol::object call_function(sol::this_state s, uevr::API::UObject* self, uevr::API::UFunction* fn, sol::variadic_args args); + +uevr::API::UScriptStruct* get_vector_struct() { + static auto vector_struct = []() { + const auto modern_class = uevr::API::get()->find_uobject(L"ScriptStruct /Script/CoreUObject.Vector"); + const auto old_class = modern_class == nullptr ? uevr::API::get()->find_uobject(L"ScriptStruct /Script/CoreUObject.Object.Vector") : nullptr; + + return modern_class != nullptr ? modern_class : old_class; + }(); + + return vector_struct; +} + +bool is_ue5() { + static auto cached_result = []() { + const auto c = get_vector_struct(); + + if (c == nullptr) { + return false; + } + + return c->get_struct_size() == sizeof(glm::dvec3); + }(); + + return cached_result; +} + +sol::object prop_to_object(sol::this_state s, void* self, uevr::API::FProperty* desc, bool is_self_temporary) { + const auto propc = desc->get_class(); + + if (propc == nullptr) { + return sol::make_object(s, sol::lua_nil); + } + + const auto name_hash = ::utility::hash(propc->get_fname()->to_string()); + const auto offset = desc->get_offset(); + + switch (name_hash) { + case L"BoolProperty"_fnv: + { + const auto fbp = (uevr::API::FBoolProperty*)desc; + return sol::make_object(s, fbp->get_value_from_object(self)); + } + case L"FloatProperty"_fnv: + return sol::make_object(s, *(float*)((uintptr_t)self + offset)); + case L"DoubleProperty"_fnv: + return sol::make_object(s, *(double*)((uintptr_t)self + offset)); + case L"IntProperty"_fnv: + return sol::make_object(s, *(int32_t*)((uintptr_t)self + offset)); + case L"UIntProperty"_fnv: + case L"UInt32Property"_fnv: + return sol::make_object(s, *(uint32_t*)((uintptr_t)self + offset)); + case L"NameProperty"_fnv: + return sol::make_object(s, *(uevr::API::FName*)((uintptr_t)self + offset)); + case L"ObjectProperty"_fnv: + if (*(uevr::API::UObject**)((uintptr_t)self + offset) == nullptr) { + return sol::make_object(s, sol::lua_nil); + } + + return sol::make_object(s, *(uevr::API::UObject**)((uintptr_t)self + offset)); + case L"ClassProperty"_fnv: + if (*(uevr::API::UClass**)((uintptr_t)self + offset) == nullptr) { + return sol::make_object(s, sol::lua_nil); + } + + return sol::make_object(s, *(uevr::API::UClass**)((uintptr_t)self + offset)); + case L"StructProperty"_fnv: + { + const auto struct_data = (void*)((uintptr_t)self + offset); + const auto struct_desc = ((uevr::API::FStructProperty*)desc)->get_struct(); + + if (struct_desc == nullptr) { + return sol::make_object(s, sol::lua_nil); + } + + /*const auto struct_name_hash = utility::hash(struct_desc->get_fname()->to_string()); + + switch (struct_name_hash) { + case L"Vector"_fnv: + if (is_ue5()) { + return sol::make_object(s, (lua::datatypes::Vector3f*)struct_data); + } + + return sol::make_object(s, (lua::datatypes::Vector3f*)struct_data); + };*/ + + if (struct_desc == get_vector_struct()) { + if (is_ue5()) { + if (is_self_temporary) { + return sol::make_object(s, *(lua::datatypes::Vector3d*)struct_data); + } else { + return sol::make_object(s, (lua::datatypes::Vector3d*)struct_data); + } + } + + if (is_self_temporary) { + return sol::make_object(s, *(lua::datatypes::Vector3f*)struct_data); + } else { + return sol::make_object(s, (lua::datatypes::Vector3f*)struct_data); + } + } + + // TODO: Return a reflected struct + return sol::make_object(s, sol::lua_nil); + } + case L"ArrayProperty"_fnv: + { + const auto inner_prop = ((uevr::API::FArrayProperty*)desc)->get_inner(); + + if (inner_prop == nullptr) { + return sol::make_object(s, sol::lua_nil); + } + + const auto inner_c = inner_prop->get_class(); + + if (inner_c == nullptr) { + return sol::make_object(s, sol::lua_nil); + } + + const auto inner_name_hash = ::utility::hash(inner_c->get_fname()->to_string()); + + switch (inner_name_hash) { + case "ObjectProperty"_fnv: + { + const auto& arr = *(uevr::API::TArray*)((uintptr_t)self + offset); + + if (arr.data == nullptr || arr.count == 0) { + return sol::make_object(s, sol::lua_nil); + } + + auto lua_arr = std::vector{}; + + for (size_t i = 0; i < arr.count; ++i) { + lua_arr.push_back(arr.data[i]); + } + + return sol::make_object(s, lua_arr); + } + // TODO: Add support for other types + }; + + return sol::make_object(s, sol::lua_nil); + } + }; + + 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); + } + + const auto desc = c->find_property(name.c_str()); + + if (desc == nullptr) { + if (auto fn = c->find_function(name.c_str()); fn != nullptr) { + /*return sol::make_object(s, [self, s, fn](sol::variadic_args args) { + return call_function(s, self, fn, args); + });*/ + return sol::make_object(s, fn); + } + + return sol::make_object(s, sol::lua_nil); + } + + 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) { + const auto c = self->get_class(); + + if (c == nullptr) { + throw sol::error("[set_property] Object has no class"); + } + + const auto desc = c->find_property(name.c_str()); + + if (desc == nullptr) { + throw sol::error(std::format("[set_property] Property '{}' not found", ::utility::narrow(name))); + } + + const auto propc = desc->get_class(); + + if (propc == nullptr) { + throw sol::error(std::format("[set_property] Property '{}' has no class", ::utility::narrow(name))); + } + + const auto name_hash = ::utility::hash(propc->get_fname()->to_string()); + const auto offset = desc->get_offset(); + + switch (name_hash) { + case L"BoolProperty"_fnv: + { + const auto fbp = (uevr::API::FBoolProperty*)desc; + fbp->set_value_in_object(self, value.as()); + return; + } + case L"FloatProperty"_fnv: + //self.get_property(name) = value.as(); + *(float*)((uintptr_t)self + offset) = value.as(); + return; + case L"DoubleProperty"_fnv: + *(double*)((uintptr_t)self + offset) = value.as(); + return; + case L"IntProperty"_fnv: + *(int32_t*)((uintptr_t)self + offset) = value.as(); + return; + case L"UIntProperty"_fnv: + case L"UInt32Property"_fnv: + *(uint32_t*)((uintptr_t)self + offset) = value.as(); + return; + case L"NameProperty"_fnv: + //return sol::make_object(s, self.get_property(name)); + throw sol::error("Setting FName properties is not supported (yet)"); + case L"ObjectProperty"_fnv: + *(uevr::API::UObject**)((uintptr_t)self + offset) = value.as(); + return; + case L"ClassProperty"_fnv: + *(uevr::API::UClass**)((uintptr_t)self + offset) = value.as(); + return; + case L"ArrayProperty"_fnv: + throw sol::error("Setting array properties is not supported (yet)"); + }; + + // NONE +} + +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(); + + if (fn_args == nullptr) { + fn->call(self, nullptr); + return sol::make_object(s, sol::lua_nil); + } + + std::vector params{}; + size_t args_index{0}; + + const auto ps = fn->get_properties_size(); + const auto ma = fn->get_min_alignment(); + + if (ma > 1) { + params.resize(((ps + ma - 1) / ma) * ma); + } else { + params.resize(ps); + } + + params.resize(fn->get_properties_size()); + + uevr::API::FProperty* return_prop{nullptr}; + bool ret_is_bool{false}; + + //std::vector dynamic_data{}; + std::vector dynamic_strings{}; + + for (auto arg_desc = fn_args; arg_desc != nullptr; arg_desc = arg_desc->get_next()) { + const auto arg_c = arg_desc->get_class(); + + if (arg_c == nullptr) { + continue; + } + + const auto arg_c_name = arg_c->get_fname()->to_string(); + + if (!arg_c_name.contains(L"Property")) { + continue; + } + + const auto prop_desc = (uevr::API::FProperty*)arg_desc; + + if (!prop_desc->is_param()) { + continue; + } + + if (prop_desc->is_return_param()) { + return_prop = prop_desc; + + if (arg_c_name == L"BoolProperty") { + ret_is_bool = true; + } + + continue; + } + + const auto arg_hash = ::utility::hash(arg_c_name); + const auto offset = prop_desc->get_offset(); + + switch (arg_hash) { + case L"BoolProperty"_fnv: + { + const bool arg = args[args_index++].as(); + const auto fbp = (uevr::API::FBoolProperty*)prop_desc; + fbp->set_value_in_object(params.data(), arg); + continue; + } + case L"FloatProperty"_fnv: + { + const float arg = args[args_index++].as(); + *(float*)¶ms[offset] = arg; + continue; + } + case L"DoubleProperty"_fnv: + { + const double arg = args[args_index++].as(); + *(double*)¶ms[offset] = arg; + continue; + } + case L"IntProperty"_fnv: + case L"UIntProperty"_fnv: + case L"UInt32Property"_fnv: + { + const int32_t arg = args[args_index++].as(); + *(int32_t*)¶ms[offset] = arg; + continue; + } + case L"NameProperty"_fnv: + { + const auto arg_obj = args[args_index++]; + + if (arg_obj.is()) { + const auto arg = ::utility::widen(arg_obj.as()); + *(uevr::API::FName*)¶ms[offset] = uevr::API::FName{arg}; + } else if (arg_obj.is()) { + const auto arg = arg_obj.as(); + *(uevr::API::FName*)¶ms[offset] = uevr::API::FName{arg}; + } else if (arg_obj.is()) { + const auto arg = arg_obj.as(); + *(uevr::API::FName*)¶ms[offset] = arg; + } else { + throw sol::error("Invalid argument type for FName"); + } + + continue; + } + case L"ObjectProperty"_fnv: + { + const auto arg = args[args_index++].as(); + *(uevr::API::UObject**)¶ms[offset] = arg; + continue; + } + case L"ClassProperty"_fnv: + { + const auto arg = args[args_index++].as(); + *(uevr::API::UClass**)¶ms[offset] = arg; + continue; + } + case L"StructProperty"_fnv: + { + const auto arg_obj = args[args_index++]; + const auto struct_desc = ((uevr::API::FStructProperty*)prop_desc)->get_struct(); + + if (struct_desc == nullptr) { + throw sol::error("Struct property has no struct"); + } + + if (struct_desc == get_vector_struct()) { + if (arg_obj.is()) { + const auto arg = arg_obj.as(); + + if (is_ue5()) { + *(lua::datatypes::Vector3d*)¶ms[offset] = arg; + } else { + *(lua::datatypes::Vector3f*)¶ms[offset] = arg; + } + } else if (arg_obj.is()) { + const auto arg = arg_obj.as(); + + if (is_ue5()) { + *(lua::datatypes::Vector3d*)¶ms[offset] = arg; + } else { + *(lua::datatypes::Vector3f*)¶ms[offset] = arg; + } + } else { + throw sol::error("Invalid argument type for FVector"); + } + } + + continue; + } + case L"ArrayProperty"_fnv: + // TODO + throw sol::error("Array properties are not supported (yet)"); + continue; + case L"StrProperty"_fnv: + { + const auto arg_obj = args[args_index++]; + using FString = uevr::API::TArray; + + auto& fstr = *(FString*)¶ms[offset]; + + if (arg_obj.is()) { + dynamic_strings.push_back(arg_obj.as()); + + fstr.count = dynamic_strings.back().size() + 1; + fstr.data = (wchar_t*)dynamic_strings.back().c_str(); + } else if (arg_obj.is()) { + dynamic_strings.push_back(::utility::widen(arg_obj.as())); + + fstr.count = dynamic_strings.back().size() + 1; + fstr.data = (wchar_t*)dynamic_strings.back().c_str(); + } else if (arg_obj.is()) { + dynamic_strings.push_back(arg_obj.as()); + + fstr.count = dynamic_strings.back().size() + 1; + } else { + throw sol::error("Invalid argument type for FString"); + } + continue; + } + default: + //spdlog::warn("Unknown property type when calling '{}': {}", utility::narrow(fn->get_fname()->to_string()), utility::narrow(arg_c_name)); + uevr::API::get()->log_warn(std::format("Unknown property type when calling '{}': {}", ::utility::narrow(fn->get_fname()->to_string()), ::utility::narrow(arg_c_name)).c_str()); + }; + } + + fn->call(self, params.data()); + + if (return_prop != nullptr) { + if (ret_is_bool) { + return sol::make_object(s, ((uevr::API::FBoolProperty*)return_prop)->get_value_from_object(params.data())); + } + + return prop_to_object(s, params.data(), return_prop, true); + } + + return sol::make_object(s, sol::lua_nil); +} + +sol::object call_function(sol::this_state s, uevr::API::UObject* self, const std::wstring& name, sol::variadic_args args) { + const auto c = self->get_class(); + + if (c == nullptr) { + return sol::make_object(s, sol::lua_nil); + } + + const auto fn = c->find_function(name.c_str()); + + if (fn == nullptr) { + return sol::make_object(s, sol::lua_nil); + } + + return call_function(s, self, fn, args); +} +} \ No newline at end of file diff --git a/lua-api/lib/src/datatypes/StructObject.cpp b/lua-api/lib/src/datatypes/StructObject.cpp new file mode 100644 index 00000000..071a5e7c --- /dev/null +++ b/lua-api/lib/src/datatypes/StructObject.cpp @@ -0,0 +1,11 @@ +#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; } + + ); + } +} \ No newline at end of file diff --git a/lua-api/lib/src/datatypes/Vector.cpp b/lua-api/lib/src/datatypes/Vector.cpp index 7ace25df..97400295 100644 --- a/lua-api/lib/src/datatypes/Vector.cpp +++ b/lua-api/lib/src/datatypes/Vector.cpp @@ -1,7 +1,3 @@ -#define GLM_ENABLE_EXPERIMENTAL -#include -#include - #include namespace lua::datatypes {