From fcceb474b275fe38d033074f44148338ef2fa0eb Mon Sep 17 00:00:00 2001 From: praydog Date: Sat, 12 Oct 2024 11:26:43 -0700 Subject: [PATCH] Lua: Add UObject:DANGEROUS_call_member_virtual(args...) --- lua-api/lib/src/ScriptContext.cpp | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/lua-api/lib/src/ScriptContext.cpp b/lua-api/lib/src/ScriptContext.cpp index 26ebb541..6bf39850 100644 --- a/lua-api/lib/src/ScriptContext.cpp +++ b/lua-api/lib/src/ScriptContext.cpp @@ -465,6 +465,54 @@ int ScriptContext::setup_bindings() { "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); }, + "DANGEROUS_call_member_virtual", [](sol::this_state s, uevr::API::UObject* self, size_t index, sol::variadic_args args) -> sol::object { + if (args.size() > 3) { + throw sol::error("DANGEROUS_call_member_virtual: Too many arguments (max 3)"); + } + + if (index > 1000) { // Yeah right + throw sol::error("DANGEROUS_call_member_virtual: Index too high"); + } + + void* args_ptr[3]{}; + + for (size_t i = 0; i < args.size(); ++i) { + if (args[i].is()) { + args_ptr[i] = nullptr; + continue; + } + + // Only support basic arguments for now until we can test this more + if (args[i].is()) { + args_ptr[i] = args[i].as(); + } else { + // We dont support floats for now because we'd need to JIT the function call + throw sol::error("DANGEROUS_call_member_virtual: Invalid argument type"); + } + } + + void* result{}; + using fn_t = void*(*)(uevr::API::UObject*, void*, void*, void*); + const auto vtable = *(void***)self; + if (vtable == nullptr) { + throw sol::error("DANGEROUS_call_member_virtual: Object has no vtable"); + } + + const auto fn = (fn_t)vtable[index]; + if (fn == nullptr) { + throw sol::error("DANGEROUS_call_member_virtual: Function not found in vtable"); + } + + try { + // We need to wrap this in a try-catch block because who knows what the function does + result = fn(self, args_ptr[0], args_ptr[1], args_ptr[2]); + } catch (...) { + throw sol::error("DANGEROUS_call_member_virtual: Exception thrown"); + return sol::make_object(s, sol::lua_nil); + } + + return sol::make_object(s, result); // TODO: convert? + }, sol::meta_function::index, [](sol::this_state s, uevr::API::UObject* self, sol::object index_obj) -> sol::object { if (!index_obj.is()) { return sol::make_object(s, sol::lua_nil);