diff --git a/functions/game_object_type.cpp b/functions/game_object_type.cpp index 5c91e48..ae80ea7 100644 --- a/functions/game_object_type.cpp +++ b/functions/game_object_type.cpp @@ -54,12 +54,10 @@ static void* Lua_Get_Display_Name(void* this_wrapper, void* /*script*/, void* /* std::string narrow(narrow_len, '\0'); WideCharToMultiByte(CP_UTF8, 0, wdata, wlen, &narrow[0], narrow_len, nullptr, nullptr); - // 5. Create a LuaString (LuaValue, 0x78 bytes) and return it. - void* lua_value = ::operator new(0x78); + // 5. Create a LuaString (LuaValue) and return it. + void* lua_value = CreateLuaValueString(narrow); if (!lua_value) return nullptr; - memset(lua_value, 0, 0x78); - pfn_lua_value_ctor(lua_value, &narrow); return pfn_return_variable(this_wrapper, lua_value); } @@ -70,7 +68,7 @@ void Register_GOTMembers(void* wrapper) return; if (!pfn_get_text_name_id || !pfn_game_text_get || !g_the_game_text) return; - if (!pfn_lua_value_ctor || !pfn_return_variable) + if (!pfn_return_variable) return; // Allocate a LuaMemberFunctionWrapper (0x88 bytes). diff --git a/lua_hook.cpp b/lua_hook.cpp index 0dfefe8..a2951c0 100644 --- a/lua_hook.cpp +++ b/lua_hook.cpp @@ -2,6 +2,12 @@ #include "functions/functions.h" #include #include +#include +#include + +// Cached during init for CreateLuaValueString +static const LuaRVAs* g_rvas = nullptr; +static uintptr_t g_base = 0; // Resolved function pointers fn_lua_open real_lua_open = nullptr; @@ -22,7 +28,6 @@ fn_RemoveTutorialText pfn_remove_tutorial_text = nullptr; void* g_command_bar = nullptr; fn_DebugPrint pfn_debug_print = nullptr; fn_RegisterMember pfn_register_member = nullptr; -fn_LuaValueCtor pfn_lua_value_ctor = nullptr; fn_ReturnVariable pfn_return_variable = nullptr; fn_GotWrapperCtor real_got_wrapper_ctor = nullptr; fn_LmfwCtor pfn_lmfw_ctor = nullptr; @@ -36,6 +41,24 @@ void register_global(lua_State* L, const char* name, lua_CFunction fn) { pfn_settable(L, LUA_GLOBALSINDEX); } +void* CreateLuaValueString(const std::string& str) { + if (!g_rvas || !g_rvas->lua_value_string_vftable) + return nullptr; + + void* obj = ::operator new(g_rvas->lua_value_string_size); + if (!obj) + return nullptr; + memset(obj, 0, g_rvas->lua_value_string_size); + + // Set the vftable pointer + *(uintptr_t*)obj = g_base + g_rvas->lua_value_string_vftable; + + // Placement-new the string into the member offset + new ((char*)obj + g_rvas->lua_value_string_offset) std::string(str); + + return obj; +} + // Fired every time the game constructs a GameObjectTypeWrapper static void* Hook_GOTWrapperCtor(void* this_wrapper) { void* result = real_got_wrapper_ctor(this_wrapper); @@ -73,6 +96,8 @@ bool LuaHook_Init() { return false; uintptr_t base = (uintptr_t)GetModuleHandleA(nullptr); + g_rvas = rvas; + g_base = base; pfn_pushstring = (fn_lua_pushstring)(base + rvas->lua_pushstring); pfn_pushcclosure = (fn_lua_pushcclosure)(base + rvas->lua_pushcclosure); @@ -101,8 +126,6 @@ bool LuaHook_Init() { if (rvas->register_member) pfn_register_member = (fn_RegisterMember)(base + rvas->register_member); - if (rvas->lua_value_ctor) - pfn_lua_value_ctor = (fn_LuaValueCtor)(base + rvas->lua_value_ctor); if (rvas->return_variable) pfn_return_variable = (fn_ReturnVariable)(base + rvas->return_variable); @@ -138,7 +161,7 @@ bool LuaHook_Init() { if (rvas->got_wrapper_ctor && rvas->got_lmfw_ctor && pfn_register_member && pfn_lmfw_ctor && pfn_get_text_name_id && pfn_game_text_get && g_the_game_text && - pfn_lua_value_ctor && pfn_return_variable) + rvas->lua_value_string_vftable && pfn_return_variable) { void* got_ctor_target = (void*)(base + rvas->got_wrapper_ctor); if (MH_CreateHook(got_ctor_target, &Hook_GOTWrapperCtor, (void**)&real_got_wrapper_ctor) == MH_OK) { diff --git a/lua_hook.h b/lua_hook.h index 5bfe20a..18d8070 100644 --- a/lua_hook.h +++ b/lua_hook.h @@ -1,5 +1,6 @@ #pragma once #include "rvas.h" +#include struct lua_State; typedef int (*lua_CFunction)(lua_State*); @@ -22,7 +23,6 @@ typedef void (*fn_RemoveTutorialText)(void*, const char*); typedef void (*fn_DebugPrint)(const char*); // Debug_Print // Scripting internals (LuaUserVar) -- usable by any wrapper module typedef void (*fn_RegisterMember)(void* uservar, const char* name, void* fn_ptr); // LuaUserVar::Register_Member -typedef void (*fn_LuaValueCtor)(void* lua_value, void* basic_string_ptr); // LuaValue<>::LuaValue<>(basic_string<>*) typedef void* (*fn_ReturnVariable)(void* uservar, void* lua_var); // LuaUserVar::Return_Variable(LuaVar*) -> LuaTable* // Game Object Type Wrapper internals typedef void* (*fn_GotWrapperCtor)(void* this_wrapper); // GameObjectTypeWrapper::GameObjectTypeWrapper() @@ -49,7 +49,6 @@ extern fn_RemoveTutorialText pfn_remove_tutorial_text; extern void* g_command_bar; extern fn_DebugPrint pfn_debug_print; extern fn_RegisterMember pfn_register_member; -extern fn_LuaValueCtor pfn_lua_value_ctor; extern fn_ReturnVariable pfn_return_variable; extern fn_GotWrapperCtor real_got_wrapper_ctor; extern fn_LmfwCtor pfn_lmfw_ctor; @@ -62,5 +61,9 @@ constexpr int LUA_GLOBALSINDEX = -10001; // Equivalent of lua_setglobal — registers a C function in the Lua global table void register_global(lua_State* L, const char* name, lua_CFunction fn); +// Creates a LuaValue> from a std::string. +// Reproduces the inlined constructor pattern using per-executable layout constants. +void* CreateLuaValueString(const std::string& str); + bool LuaHook_Init(); void LuaHook_Shutdown(); diff --git a/rvas.h b/rvas.h index 9fade65..60faef5 100644 --- a/rvas.h +++ b/rvas.h @@ -16,7 +16,9 @@ struct LuaRVAs { uintptr_t get_script_from_state; // LuaScriptClass::Get_Script_From_State (static) uintptr_t map_var_to_lua; // LuaScriptClass::Map_Var_To_Lua (member) uintptr_t register_member; // LuaUserVar::Register_Member(char*, LuaVar*) - uintptr_t lua_value_ctor; // LuaValue<>::LuaValue<>(basic_string<>*) + uintptr_t lua_value_string_vftable; // LuaValue>::vftable + size_t lua_value_string_size; // allocation size of LuaValue> + size_t lua_value_string_offset; // offset of basic_string member within LuaValue uintptr_t return_variable; // LuaUserVar::Return_Variable(LuaVar*) // --- TheGameText --- @@ -58,7 +60,9 @@ constexpr LuaRVAs RVAs_StarWarsI = { 0x0537BB0, // LuaScriptClass::Get_Script_From_State 0x0536FE0, // LuaScriptClass::Map_Var_To_Lua 0x0046f51, // LuaUserVar::Register_Member - 0x004df5e, // LuaValue<>::LuaValue<> + 0x1453310, // LuaValue>::vftable + 0x78, // LuaValue> allocation size + 0x58, // basic_string member offset within LuaValue 0x0058887, // LuaUserVar::Return_Variable // --- TheGameText --- @@ -99,13 +103,15 @@ constexpr LuaRVAs RVAs_StarWarsG = { // --- Scripts --- 0x0245790, // LuaScriptClass::Get_Script_From_State 0x0247700, // LuaScriptClass::Map_Var_To_Lua - 0, // LuaUserVar::Register_Member -- not mapped - 0, // LuaString::LuaString -- not mapped - 0, // LuaUserVar::Return_Variable -- not mapped + 0x024be40, // LuaUserVar::Register_Member + 0x0855a98, // LuaValue>::vftable + 0x30, // LuaValue> allocation size + 0x10, // basic_string member offset within LuaValue + 0x0256d40, // LuaUserVar::Return_Variable // --- TheGameText --- - 0, // TheGameText global object - 0, // GameTextClass::Get + 0x0a7bc58, // TheGameText global object + 0x01fa680, // GameTextClass::Get // --- Players --- 0x0294bc0, // PlayerListClass::Get_Player_By_Index @@ -118,7 +124,7 @@ constexpr LuaRVAs RVAs_StarWarsG = { 0x02ff290, // CommandBarClass::Remove_Tutorial_Text // --- Game Object Type Wrapper --- - 0, // GameObjectTypeWrapper::GameObjectTypeWrapper() -- not mapped + 0x0604a10, // GameObjectTypeWrapper::GameObjectTypeWrapper() 0, // GameObjectTypeClass::Get_Text_Name_ID() -- not mapped 0, // LuaMemberFunctionWrapper::ctor -- not mapped