From cd79cd4d87740c8e937e6c337a3202982fa31d7e Mon Sep 17 00:00:00 2001 From: Federico Cecchetto Date: Fri, 1 Oct 2021 23:41:32 +0200 Subject: [PATCH] Fix script function calling + expose lui globals --- src/client/game/structs.hpp | 96 ++++++++++++++++++-- src/client/game/ui_scripting/execution.cpp | 31 +++++-- src/client/game/ui_scripting/execution.hpp | 2 +- src/client/game/ui_scripting/lua/context.cpp | 26 +++++- src/client/game/ui_scripting/types.cpp | 3 +- src/client/game/ui_scripting/value.cpp | 3 +- 6 files changed, 136 insertions(+), 25 deletions(-) diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 59e3c2fd..ca0637f8 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -969,11 +969,11 @@ namespace game TNUMBER = 0x3, TSTRING = 0x4, TTABLE = 0x5, - TFUNCTION = 0x6, + TFUNCTION = 0x6, // idk TUSERDATA = 0x7, TTHREAD = 0x8, - TIFUNCTION = 0x9, - TCFUNCTION = 0xA, + TIFUNCTION = 0x9, // Lua function + TCFUNCTION = 0xA, // C function TUI64 = 0xB, TSTRUCT = 0xC, NUM_TYPE_OBJECTS = 0xE, @@ -985,13 +985,27 @@ namespace game HksValue v; }; + const struct hksInstruction + { + unsigned int code; + }; + + struct ActivationRecord + { + HksObject* m_base; + const hksInstruction* m_returnAddress; + __int16 m_tailCallDepth; + __int16 m_numVarargs; + int m_numExpectedReturns; + }; + struct CallStack { - void* m_records; - void* m_lastrecord; - void* m_current; - const unsigned int* m_current_lua_pc; - const unsigned int* m_hook_return_addr; + ActivationRecord* m_records; + ActivationRecord* m_lastrecord; + ActivationRecord* m_current; + const hksInstruction* m_current_lua_pc; + const hksInstruction* m_hook_return_addr; int m_hook_level; }; @@ -1003,11 +1017,73 @@ namespace game HksObject* bottom; }; - struct lua_State + struct UpValue : ChunkHeader { - char __pad0[24]; + HksObject m_storage; + HksObject* loc; + UpValue* m_next; + }; + + struct CallSite + { + _SETJMP_FLOAT128 m_jumpBuffer[16]; + CallSite* m_prev; + }; + + enum Status + { + NEW = 0x1, + RUNNING = 0x2, + YIELDED = 0x3, + DEAD_ERROR = 0x4, + }; + + enum HksError + { + HKS_NO_ERROR = 0x0, + LUA_ERRSYNTAX = 0xFFFFFFFC, + LUA_ERRFILE = 0xFFFFFFFB, + LUA_ERRRUN = 0xFFFFFF9C, + LUA_ERRMEM = 0xFFFFFF38, + LUA_ERRERR = 0xFFFFFED4, + HKS_THROWING_ERROR = 0xFFFFFE0C, + HKS_GC_YIELD = 0x1, + }; + + struct lua_Debug + { + int event; + const char* name; + const char* namewhat; + const char* what; + const char* source; + int currentline; + int nups; + int nparams; + int ishksfunc; + int linedefined; + int lastlinedefined; + char short_src[512]; + int callstack_level; + int is_tail_call; + }; + + struct lua_State : ChunkHeader + { + void* m_global; CallStack m_callStack; ApiStack m_apistack; + UpValue* pending; + HksObject globals; + HksObject m_cEnv; + CallSite* m_callsites; + int m_numberOfCCalls; + void* m_context; + InternString* m_name; + lua_State* m_nextState; + lua_State* m_nextStateStack; + Status m_status; + HksError m_error; }; using lua_function = int(__fastcall*)(lua_State*); diff --git a/src/client/game/ui_scripting/execution.cpp b/src/client/game/ui_scripting/execution.cpp index 353abbb7..d165e189 100644 --- a/src/client/game/ui_scripting/execution.cpp +++ b/src/client/game/ui_scripting/execution.cpp @@ -18,20 +18,19 @@ namespace ui_scripting value get_return_value(int offset) { const auto state = *game::hks::lua_state; - const auto top = &state->m_apistack.top[-1 - offset]; - return *top; + return state->m_apistack.top[-1 - offset]; } - void call_script_function(const function& function, const arguments& arguments) + arguments call_script_function(const function& function, const arguments& arguments) { const auto state = *game::hks::lua_state; stack_isolation _; - for (auto i = arguments.rbegin(); i != arguments.rend(); ++i) + push_value(function); + for (auto i = arguments.begin(); i != arguments.end(); ++i) { push_value(*i); } - push_value(function); enable_error_hook(); const auto __ = gsl::finally([]() @@ -39,11 +38,27 @@ namespace ui_scripting disable_error_hook(); }); - // Not sure about this - try { - game::hks::vm_call_internal(state, static_cast(arguments.size()), 0, 0); + game::hks::vm_call_internal(state, static_cast(arguments.size()), -1, 0); + std::vector values; + + const auto top = state->m_apistack.top; + const auto base = state->m_apistack.base; + + const auto num = top - base; + + for (auto i = 0; i < num; i++) + { + values.push_back(get_return_value(i)); + } + + if (values.size() == 0) + { + values.push_back({}); + } + + return values; } catch (const std::exception& e) { diff --git a/src/client/game/ui_scripting/execution.hpp b/src/client/game/ui_scripting/execution.hpp index 17a39a70..a2880942 100644 --- a/src/client/game/ui_scripting/execution.hpp +++ b/src/client/game/ui_scripting/execution.hpp @@ -8,7 +8,7 @@ namespace ui_scripting void push_value(const value& value); value get_return_value(int offset); - void call_script_function(const function& function, const arguments& arguments); + arguments call_script_function(const function& function, const arguments& arguments); value get_field(const userdata& self, const value& key); value get_field(const table& self, const value& key); diff --git a/src/client/game/ui_scripting/lua/context.cpp b/src/client/game/ui_scripting/lua/context.cpp index c56dbfe7..4ebd826a 100644 --- a/src/client/game/ui_scripting/lua/context.cpp +++ b/src/client/game/ui_scripting/lua/context.cpp @@ -1047,6 +1047,18 @@ namespace ui_scripting::lua auto table_type = state.new_usertype("table_"); + table_type["get"] = [](const table& table, const sol::this_state s, + const std::string& name) + { + return convert(s, table.get(name)); + }; + + table_type["set"] = [](const table& table, const sol::this_state s, + const std::string& name, const sol::lua_value& value) + { + table.set(name, convert({s, value})); + }; + table_type[sol::meta_function::index] = [](const table& table, const sol::this_state s, const std::string& name) { @@ -1077,7 +1089,9 @@ namespace ui_scripting::lua return result; }; - auto function_type = state.new_usertype("function"); + state["luiglobals"] = table((*::game::hks::lua_state)->globals.v.table); + + auto function_type = state.new_usertype("function_"); function_type[sol::meta_function::call] = [](const function& function, const sol::this_state s, sol::variadic_args va) { @@ -1088,7 +1102,15 @@ namespace ui_scripting::lua arguments.push_back(convert({s, arg})); } - function.call(arguments); + const auto values = function.call(arguments); + std::vector returns; + + for (const auto& value : values) + { + returns.push_back(convert(s, value)); + } + + return sol::as_returns(returns); }; struct player diff --git a/src/client/game/ui_scripting/types.cpp b/src/client/game/ui_scripting/types.cpp index ac2051ad..d72050fd 100644 --- a/src/client/game/ui_scripting/types.cpp +++ b/src/client/game/ui_scripting/types.cpp @@ -92,7 +92,6 @@ namespace ui_scripting arguments function::call(const arguments& arguments) const { - call_script_function(*this, arguments); - return {}; + return call_script_function(*this, arguments); } } diff --git a/src/client/game/ui_scripting/value.cpp b/src/client/game/ui_scripting/value.cpp index f34ccba7..0a117d32 100644 --- a/src/client/game/ui_scripting/value.cpp +++ b/src/client/game/ui_scripting/value.cpp @@ -259,8 +259,7 @@ namespace ui_scripting template <> bool value::is() const { - return this->get_raw().t == game::hks::TIFUNCTION - || this->get_raw().t == game::hks::TCFUNCTION; + return this->get_raw().t == game::hks::TIFUNCTION; } template <>