From f7024acd8b0ad93b6ee4d055a9b18ec75be9bff6 Mon Sep 17 00:00:00 2001 From: "Drew C." Date: Sun, 1 Mar 2026 16:36:37 -0600 Subject: [PATCH] Add Get_All_Players() Lua function --- dllmain.cpp | 1 + lua_hook.cpp | 164 +++++++++++++++++++++++++++++++++++++++++++++++---- lua_hook.h | 27 +++++++++ 3 files changed, 179 insertions(+), 13 deletions(-) diff --git a/dllmain.cpp b/dllmain.cpp index 2af5a1a..35b643c 100644 --- a/dllmain.cpp +++ b/dllmain.cpp @@ -14,6 +14,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved) { if (!LuaHook_Init()) { OutputDebugStringA("[SWEAW Hooks] WARNING: LuaHook_Init() failed - Lua hooks are not active.\n"); } + break; case DLL_PROCESS_DETACH: diff --git a/lua_hook.cpp b/lua_hook.cpp index eb5e124..919313f 100644 --- a/lua_hook.cpp +++ b/lua_hook.cpp @@ -13,18 +13,35 @@ struct lua_State; typedef int (*lua_CFunction)(lua_State*); // Function pointer types -typedef lua_State* (*fn_lua_open)(); -typedef void (*fn_lua_pushstring)(lua_State*, const char*); -typedef void (*fn_lua_pushcclosure)(lua_State*, lua_CFunction, int); -typedef void (*fn_lua_settable)(lua_State*, int); -typedef const char* (*fn_lua_tostring)(lua_State*, int); +typedef lua_State* (*fn_lua_open)(); +typedef void (*fn_lua_pushstring)(lua_State*, const char*); +typedef void (*fn_lua_pushcclosure)(lua_State*, lua_CFunction, int); +typedef void (*fn_lua_settable)(lua_State*, int); +typedef const char* (*fn_lua_tostring)(lua_State*, int); +typedef double (*fn_lua_tonumber)(lua_State*, int); +typedef void* (*fn_GetPlayerByIndex)(void*, int); // PlayerListClass::Get_Player_By_Index +typedef void* (*fn_PlayerWrapperCreate)(void*, void*); // PlayerWrapper::Create(PlayerClass*, LuaScriptClass*) +typedef void* (*fn_GetScriptFromState)(lua_State*); // LuaScriptClass::Get_Script_From_State +typedef void (*fn_MapVarToLua)(lua_State*, void*); // LuaScriptClass::Map_Var_To_Lua (static) +typedef void (*fn_DebugPrint)(const char*); // Debug_Print +typedef void (*fn_lua_newtable)(lua_State*); // lua_newtable(L) +typedef void (*fn_lua_rawseti)(lua_State*, int, int); // lua_rawseti(L, idx, n) // Resolved function pointers -static fn_lua_open real_lua_open = nullptr; -static fn_lua_pushstring pfn_pushstring = nullptr; -static fn_lua_pushcclosure pfn_pushcclosure = nullptr; -static fn_lua_settable pfn_settable = nullptr; -static fn_lua_tostring pfn_tostring = nullptr; +static fn_lua_open real_lua_open = nullptr; +static fn_lua_pushstring pfn_pushstring = nullptr; +static fn_lua_pushcclosure pfn_pushcclosure = nullptr; +static fn_lua_settable pfn_settable = nullptr; +static fn_lua_tostring pfn_tostring = nullptr; +static fn_lua_tonumber pfn_tonumber = nullptr; +static fn_GetPlayerByIndex pfn_get_player_by_index = nullptr; +static void* g_player_list = nullptr; +static fn_PlayerWrapperCreate pfn_player_wrapper_create = nullptr; +static fn_GetScriptFromState pfn_get_script_from_state = nullptr; +static fn_MapVarToLua pfn_map_var_to_lua = nullptr; +static fn_DebugPrint pfn_debug_print = nullptr; +static fn_lua_newtable pfn_newtable = nullptr; +static fn_lua_rawseti pfn_rawseti = nullptr; // Helper, equivalent of lua_setglobal static void register_global(lua_State* L, const char* name, lua_CFunction fn) { @@ -67,6 +84,97 @@ static int L_WriteToFile(lua_State* L) { return 0; } +// Find_Internet_Player(index) - returns a PlayerWrapper for the given internet player index, +// identical in structure to the object returned by Find_Player(). +static int L_Find_Internet_Player(lua_State* L) { + int index = (int)pfn_tonumber(L, 1); + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Find_Internet_Player called\n"); + + if (index < 0) { + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Find_Internet_Player: index must be >= 0\n"); + return 0; + } + + void* player = pfn_get_player_by_index(g_player_list, index); + if (!player) { + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Find_Internet_Player: Get_Player_By_Index returned null\n"); + return 0; + } + + void* script = pfn_get_script_from_state(L); + void* wrapper = pfn_player_wrapper_create(player, script); + if (!wrapper) { + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Find_Internet_Player: PlayerWrapper::Create returned null\n"); + return 0; + } + + pfn_map_var_to_lua(L, wrapper); + return 1; +} + +// Offsets for reading PlayersByID count directly from the PlayerList object. +// PlayersByID (DynamicVectorClass) is at +0x18 within PlayerListClass. +// The active count field is at +0x10 within DynamicVectorClass. +static constexpr int OFFSET_PLAYERS_BY_ID = 0x18; +static constexpr int OFFSET_VECTOR_COUNT = 0x10; + +// Get_All_Players() - returns a 1-based Lua table of PlayerWrappers for all players, +// iterable with ipairs(). Identical wrapper type to Find_Player(). +static int L_Get_All_Players(lua_State* L) { + int count = *(int*)((char*)g_player_list + OFFSET_PLAYERS_BY_ID + OFFSET_VECTOR_COUNT); + + if (pfn_debug_print) { + char msg[64]; + wsprintfA(msg, "[SWEAW Hooks] Get_All_Players: PlayersByID count = %d\n", count); + pfn_debug_print(msg); + } + + if (count <= 0 || count > 64) { + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Get_All_Players: count out of expected range, aborting\n"); + pfn_newtable(L); + return 1; + } + + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Get_All_Players: calling Get_Script_From_State\n"); + void* script = pfn_get_script_from_state(L); + if (pfn_debug_print) { + char msg[64]; + wsprintfA(msg, "[SWEAW Hooks] Get_All_Players: script = %p\n", script); + pfn_debug_print(msg); + } + + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Get_All_Players: calling lua_newtable\n"); + pfn_newtable(L); + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Get_All_Players: lua_newtable OK\n"); + + for (int i = 0; i < count; i++) { + if (pfn_debug_print) { + char msg[64]; + wsprintfA(msg, "[SWEAW Hooks] Get_All_Players: Get_Player_By_Index(%d)\n", i); + pfn_debug_print(msg); + } + void* player = pfn_get_player_by_index(g_player_list, i); + if (!player) continue; + + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Get_All_Players: PlayerWrapper::Create\n"); + void* wrapper = pfn_player_wrapper_create(player, script); + if (pfn_debug_print) { + char msg[128]; + wsprintfA(msg, "[SWEAW Hooks] Get_All_Players: wrapper = %p, player = %p\n", wrapper, player); + pfn_debug_print(msg); + } + if (!wrapper) continue; + + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Get_All_Players: Map_Var_To_Lua\n"); + pfn_map_var_to_lua(L, wrapper); + + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Get_All_Players: lua_rawseti\n"); + pfn_rawseti(L, -2, i + 1); + } + + return 1; +} + // ========================= // Hooks // ========================= @@ -81,6 +189,17 @@ static lua_State* Hook_lua_open() { // Register custom Lua functions register_global(L, "WriteToFile", L_WriteToFile); + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Registered WriteToFile Lua function\n"); + + if (pfn_map_var_to_lua) { + register_global(L, "Find_Internet_Player", L_Find_Internet_Player); + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Registered Find_Internet_Player Lua function\n"); + + if (pfn_newtable && pfn_rawseti) { + register_global(L, "Get_All_Players", L_Get_All_Players); + if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Registered Get_All_Players Lua function\n"); + } + } return L; } @@ -103,10 +222,29 @@ bool LuaHook_Init() { uintptr_t base = (uintptr_t)GetModuleHandleA(nullptr); - pfn_pushstring = (fn_lua_pushstring)(base + rvas->lua_pushstring); + pfn_pushstring = (fn_lua_pushstring)(base + rvas->lua_pushstring); pfn_pushcclosure = (fn_lua_pushcclosure)(base + rvas->lua_pushcclosure); - pfn_settable = (fn_lua_settable)(base + rvas->lua_settable); - pfn_tostring = (fn_lua_tostring)(base + rvas->lua_tostring); + pfn_settable = (fn_lua_settable)(base + rvas->lua_settable); + pfn_tostring = (fn_lua_tostring)(base + rvas->lua_tostring); + + if (rvas->lua_tonumber && rvas->get_player_by_index && rvas->player_list && + rvas->player_wrapper_create && rvas->get_script_from_state && rvas->map_var_to_lua) + { + pfn_tonumber = (fn_lua_tonumber)(base + rvas->lua_tonumber); + pfn_get_player_by_index = (fn_GetPlayerByIndex)(base + rvas->get_player_by_index); + g_player_list = (void*)(base + rvas->player_list); + pfn_player_wrapper_create = (fn_PlayerWrapperCreate)(base + rvas->player_wrapper_create); + pfn_get_script_from_state = (fn_GetScriptFromState)(base + rvas->get_script_from_state); + pfn_map_var_to_lua = (fn_MapVarToLua)(base + rvas->map_var_to_lua); + } + + if (rvas->debug_print) + pfn_debug_print = (fn_DebugPrint)(base + rvas->debug_print); + + if (rvas->lua_newtable && rvas->lua_rawseti) { + pfn_newtable = (fn_lua_newtable)(base + rvas->lua_newtable); + pfn_rawseti = (fn_lua_rawseti)(base + rvas->lua_rawseti); + } void* const target = (void*)(base + rvas->lua_open); diff --git a/lua_hook.h b/lua_hook.h index 077848c..9ba5987 100644 --- a/lua_hook.h +++ b/lua_hook.h @@ -7,6 +7,15 @@ struct LuaRVAs { uintptr_t lua_pushcclosure; uintptr_t lua_settable; uintptr_t lua_tostring; + uintptr_t lua_tonumber; + uintptr_t get_player_by_index; // PlayerListClass::Get_Player_By_Index + uintptr_t player_list; // PlayerList global object (data, not a function) + uintptr_t player_wrapper_create; // PlayerWrapper::Create (static) + 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 debug_print; // Debug_Print(char*) + uintptr_t lua_newtable; // lua_newtable(L) + uintptr_t lua_rawseti; // lua_rawseti(L, idx, n) }; // StarWarsI.exe -- debug kit, PDB available @@ -16,6 +25,15 @@ constexpr LuaRVAs RVAs_StarWarsI = { 0x12AC6E0, // lua_pushcclosure 0x12AD020, // lua_settable 0x12AD430, // lua_tostring + 0x12AD300, // lua_tonumber + 0x06FA990, // PlayerListClass::Get_Player_By_Index + 0x1913158, // PlayerList global object + 0x0F12010, // PlayerWrapper::Create + 0x0537BB0, // LuaScriptClass::Get_Script_From_State + 0x0536FE0, // LuaScriptClass::Map_Var_To_Lua + 0x0476AE0, // Debug_Print + 0x12AC460, // lua_newtable + 0x12ACD70, // lua_rawseti }; // StarWarsG.exe -- client binary, no PDB @@ -25,6 +43,15 @@ constexpr LuaRVAs RVAs_StarWarsG = { 0x07b9340, // lua_pushcclosure 0x07b9a60, // lua_settable 0x07b9cc0, // lua_tostring + 0, // lua_tonumber (TODO) + 0, // PlayerListClass::Get_Player_By_Index (TODO) + 0, // PlayerList global object (TODO) + 0, // PlayerWrapper::Create (TODO) + 0, // LuaScriptClass::Get_Script_From_State (TODO) + 0, // LuaScriptClass::Map_Var_To_Lua (TODO) + 0, // Debug_Print (TODO) + 0, // lua_newtable (TODO) + 0, // lua_rawseti (TODO) }; constexpr int LUA_GLOBALSINDEX = -10001;