From 952c233592d895ec72c5a187bd9b1b9db386ea93 Mon Sep 17 00:00:00 2001 From: "Drew C." Date: Sun, 1 Mar 2026 17:10:27 -0600 Subject: [PATCH] Rename to FoCAPI --- .gitignore | 1 - CLAUDE.md | 12 +- SWEAW Hooks.sln => FoCAPI.sln | 2 +- SWEAW Hooks.vcxproj => FoCAPI.vcxproj | 15 +- FoCAPI.vcxproj.filters | 65 +++++++++ README.md | 5 +- dllmain.cpp | 2 +- functions/file_io.cpp | 37 +++++ functions/functions.cpp | 13 ++ functions/functions.h | 12 ++ functions/players.cpp | 71 ++++++++++ lua_hook.cpp | 196 +++----------------------- lua_hook.h | 88 +++++------- rvas.h | 76 ++++++++++ 14 files changed, 354 insertions(+), 241 deletions(-) rename SWEAW Hooks.sln => FoCAPI.sln (90%) rename SWEAW Hooks.vcxproj => FoCAPI.vcxproj (90%) create mode 100644 FoCAPI.vcxproj.filters create mode 100644 functions/file_io.cpp create mode 100644 functions/functions.cpp create mode 100644 functions/functions.h create mode 100644 functions/players.cpp create mode 100644 rvas.h diff --git a/.gitignore b/.gitignore index d34e204..a4a79ed 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ powrprof/ .vs/ .claude/ -*.vcxproj.filters *.vcxproj.user # Prerequisites diff --git a/CLAUDE.md b/CLAUDE.md index ad2be12..dc568de 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,4 +1,4 @@ -# SWEaW Hooks +# FoCAPI ## Project Overview @@ -16,4 +16,12 @@ This project is a hook API for Star Wars: Empire at War: Forces of Corruption to ## Empire at War Lua Scripting Engine -The source code for the Lua scripting engine in Empire at War was leaked at: https://github.com/PetroglyphGames/GlyphX-Reference. Use this as a guide for what Lua functions and variables are already available, and how the engine hooks Lua scripting into the rest of the game. No other engine source code is available. \ No newline at end of file +The source code for the Lua scripting engine in Empire at War was leaked at: https://github.com/PetroglyphGames/GlyphX-Reference. Use this as a guide for what Lua functions and variables are already available, and how the engine hooks Lua scripting into the rest of the game. No other engine source code is available. + +## Adding a New Lua Function + +1. Create `functions/.cpp` — implement `L_*` function(s) and `Register_(lua_State* L)` +2. Add `void Register_(lua_State* L);` to `functions/functions.h` +3. Add `Register_(L);` to `functions/functions.cpp` +4. Add new RVAs (if needed) to `rvas.h` in the relevant section, for each supported executable +5. Add `functions\.cpp` to `FoCAPI.vcxproj` and `FoCAPI.vcxproj.filters` diff --git a/SWEAW Hooks.sln b/FoCAPI.sln similarity index 90% rename from SWEAW Hooks.sln rename to FoCAPI.sln index 56a994c..633d1bd 100644 --- a/SWEAW Hooks.sln +++ b/FoCAPI.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.14.36127.28 d17.14 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SWEAW Hooks", "SWEAW Hooks.vcxproj", "{F2C4477F-C9F1-4AF0-A04C-9D6ADD14E783}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FoCAPI", "FoCAPI.vcxproj", "{F2C4477F-C9F1-4AF0-A04C-9D6ADD14E783}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/SWEAW Hooks.vcxproj b/FoCAPI.vcxproj similarity index 90% rename from SWEAW Hooks.vcxproj rename to FoCAPI.vcxproj index 144e66e..2454e1d 100644 --- a/SWEAW Hooks.vcxproj +++ b/FoCAPI.vcxproj @@ -22,7 +22,7 @@ 17.0 Win32Proj {f2c4477f-c9f1-4af0-a04c-9d6add14e783} - SWEAWHooks + FoCAPI 10.0 powrprof @@ -83,7 +83,7 @@ Level3 true - WIN32;_DEBUG;SWEAWHOOKS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;_DEBUG;FOCAPI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use pch.h @@ -100,7 +100,7 @@ true true true - WIN32;NDEBUG;SWEAWHOOKS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;NDEBUG;FOCAPI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use pch.h @@ -115,7 +115,7 @@ Level3 true - _DEBUG;SWEAWHOOKS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + _DEBUG;FOCAPI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true NotUsing pch.h @@ -134,7 +134,7 @@ true true true - NDEBUG;SWEAWHOOKS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + NDEBUG;FOCAPI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true NotUsing pch.h @@ -150,11 +150,16 @@ + + + + + diff --git a/FoCAPI.vcxproj.filters b/FoCAPI.vcxproj.filters new file mode 100644 index 0000000..b686d97 --- /dev/null +++ b/FoCAPI.vcxproj.filters @@ -0,0 +1,65 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {B3D2F8A1-4E7C-4D9A-8F23-1C5A6E2B9D47} + + + {2e9ee1bb-cc3a-49e1-8942-619ea103a1bd} + + + {590318ee-4f40-4183-bc33-5ee14f70c131} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files\Functions + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files\Functions + + + Source Files\Functions + + + Source Files\Functions + + + + + Source Files + + + \ No newline at end of file diff --git a/README.md b/README.md index b41b7fd..176c9b3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# SWEaW Hooks +# FoCAPI A powrprof.dll hook which adds custom Lua functions to Forces of Corruption. @@ -9,4 +9,5 @@ Currently only works with the debug kit `StarWarsI.exe`; `StarWarsG.exe` support ## Functions -- Global `WriteToFile(str a, str b)` - Appends a line of text `b` to the file name `a` in the game directory. \ No newline at end of file +- Global `WriteToFile(str a, str b)` - Appends a line of text `b` to the file name `a` in the game directory. +- Global `Get_All_Players()` - Returns a 1-based Lua table of all active players, iterable with `ipairs()`. Each entry is the same PlayerWrapper type returned by `Find_Player()`. diff --git a/dllmain.cpp b/dllmain.cpp index 35b643c..4035cbf 100644 --- a/dllmain.cpp +++ b/dllmain.cpp @@ -12,7 +12,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"); + OutputDebugStringA("[FoCAPI] WARNING: LuaHook_Init() failed - Lua hooks are not active.\n"); } break; diff --git a/functions/file_io.cpp b/functions/file_io.cpp new file mode 100644 index 0000000..cf39a5e --- /dev/null +++ b/functions/file_io.cpp @@ -0,0 +1,37 @@ +#include "functions.h" +#include "../lua_hook.h" +#include + +// WriteToFile(path, text) - appends text to a file +static int L_WriteToFile(lua_State* L) { + const char* path = pfn_tostring(L, 1); + const char* text = pfn_tostring(L, 2); + + if (!path || !text) { + return 0; + } + + HANDLE hFile = CreateFileA( + path, + GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hFile != INVALID_HANDLE_VALUE) { + DWORD written; + + SetFilePointer(hFile, 0, NULL, FILE_END); + WriteFile(hFile, text, lstrlenA(text), &written, NULL); + WriteFile(hFile, "\n", 1, &written, NULL); + CloseHandle(hFile); + } + + return 0; +} + +void Register_FileIO(lua_State* L) { + register_global(L, "WriteToFile", L_WriteToFile); +} diff --git a/functions/functions.cpp b/functions/functions.cpp new file mode 100644 index 0000000..065519c --- /dev/null +++ b/functions/functions.cpp @@ -0,0 +1,13 @@ +#include "functions.h" + +// To add a new Lua function module: +// 1. Create functions/.cpp with L_* implementation(s) and Register_() +// 2. Declare void Register_(lua_State* L); in functions.h +// 3. Call Register_(L); below +// 4. Add new RVAs (if needed) to rvas.h in the relevant section +// 5. Add functions\.cpp to FoCAPI.vcxproj and .vcxproj.filters + +void Register_All(lua_State* L) { + Register_FileIO(L); + Register_Players(L); +} diff --git a/functions/functions.h b/functions/functions.h new file mode 100644 index 0000000..ec9ed67 --- /dev/null +++ b/functions/functions.h @@ -0,0 +1,12 @@ +#pragma once + +struct lua_State; + +// Registers all custom Lua functions into the given state. +// Called once per lua_open() from Hook_lua_open(). +void Register_All(lua_State* L); + +// Per-module registration functions. +// Each checks its own required function pointer guards before registering. +void Register_FileIO(lua_State* L); +void Register_Players(lua_State* L); diff --git a/functions/players.cpp b/functions/players.cpp new file mode 100644 index 0000000..1bfe856 --- /dev/null +++ b/functions/players.cpp @@ -0,0 +1,71 @@ +#include "functions.h" +#include "../lua_hook.h" +#include + +// 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, "[FoCAPI] Get_All_Players: PlayersByID count = %d\n", count); + pfn_debug_print(msg); + } + + if (count <= 0 || count > 64) { + if (pfn_debug_print) pfn_debug_print("[FoCAPI] Get_All_Players: count out of expected range, aborting\n"); + pfn_newtable(L); + return 1; + } + + if (pfn_debug_print) pfn_debug_print("[FoCAPI] 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, "[FoCAPI] Get_All_Players: script = %p\n", script); + pfn_debug_print(msg); + } + + if (pfn_debug_print) pfn_debug_print("[FoCAPI] Get_All_Players: calling lua_newtable\n"); + pfn_newtable(L); + if (pfn_debug_print) pfn_debug_print("[FoCAPI] Get_All_Players: lua_newtable OK\n"); + + for (int i = 0; i < count; i++) { + if (pfn_debug_print) { + char msg[64]; + wsprintfA(msg, "[FoCAPI] 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("[FoCAPI] Get_All_Players: PlayerWrapper::Create\n"); + void* wrapper = pfn_player_wrapper_create(player, script); + if (pfn_debug_print) { + char msg[128]; + wsprintfA(msg, "[FoCAPI] Get_All_Players: wrapper = %p, player = %p\n", wrapper, player); + pfn_debug_print(msg); + } + if (!wrapper) continue; + + if (pfn_debug_print) pfn_debug_print("[FoCAPI] Get_All_Players: Map_Var_To_Lua\n"); + pfn_map_var_to_lua(L, wrapper); + + if (pfn_debug_print) pfn_debug_print("[FoCAPI] Get_All_Players: lua_rawseti\n"); + pfn_rawseti(L, -2, i + 1); + } + + return 1; +} + +void Register_Players(lua_State* L) { + if (!pfn_map_var_to_lua || !pfn_newtable || !pfn_rawseti) return; + register_global(L, "Get_All_Players", L_Get_All_Players); +} diff --git a/lua_hook.cpp b/lua_hook.cpp index 919313f..bf9b92e 100644 --- a/lua_hook.cpp +++ b/lua_hook.cpp @@ -1,4 +1,5 @@ #include "lua_hook.h" +#include "functions/functions.h" #include "minhook/include/MinHook.h" #include @@ -8,177 +9,28 @@ #pragma comment(lib, "MinHook.x86.lib") #endif -// Opaque Lua state - never dereferenced, just passed around -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 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_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; +fn_lua_open real_lua_open = nullptr; +fn_lua_pushstring pfn_pushstring = nullptr; +fn_lua_pushcclosure pfn_pushcclosure = nullptr; +fn_lua_settable pfn_settable = nullptr; +fn_lua_tostring pfn_tostring = nullptr; +fn_lua_tonumber pfn_tonumber = nullptr; +fn_lua_newtable pfn_newtable = nullptr; +fn_lua_rawseti pfn_rawseti = nullptr; +fn_GetPlayerByIndex pfn_get_player_by_index = nullptr; +void* g_player_list = nullptr; +fn_PlayerWrapperCreate pfn_player_wrapper_create = nullptr; +fn_GetScriptFromState pfn_get_script_from_state = nullptr; +fn_MapVarToLua pfn_map_var_to_lua = nullptr; +fn_DebugPrint pfn_debug_print = nullptr; -// Helper, equivalent of lua_setglobal -static void register_global(lua_State* L, const char* name, lua_CFunction fn) { +void register_global(lua_State* L, const char* name, lua_CFunction fn) { pfn_pushstring(L, name); pfn_pushcclosure(L, fn, 0); pfn_settable(L, LUA_GLOBALSINDEX); } -// ========================= -// Custom Lua file functions -// ========================= - -// WriteToFile(path, text) - appends text to a file -static int L_WriteToFile(lua_State* L) { - const char* path = pfn_tostring(L, 1); - const char* text = pfn_tostring(L, 2); - - if (!path || !text) { - return 0; - } - - HANDLE hFile = CreateFileA( - path, - GENERIC_WRITE, - FILE_SHARE_READ, - NULL, - OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if (hFile != INVALID_HANDLE_VALUE) { - DWORD written; - - SetFilePointer(hFile, 0, NULL, FILE_END); - WriteFile(hFile, text, lstrlenA(text), &written, NULL); - WriteFile(hFile, "\n", 1, &written, NULL); - CloseHandle(hFile); - } - - 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 -// ========================= - // Fired every time the game creates a new Lua state static lua_State* Hook_lua_open() { lua_State* L = real_lua_open(); @@ -187,19 +39,9 @@ static lua_State* Hook_lua_open() { return L; } - // Register custom Lua functions - register_global(L, "WriteToFile", L_WriteToFile); - if (pfn_debug_print) pfn_debug_print("[SWEAW Hooks] Registered WriteToFile Lua function\n"); + Register_All(L); - 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"); - } - } + if (pfn_debug_print) pfn_debug_print("[FoCAPI] Lua state initialized\n"); return L; } @@ -266,4 +108,4 @@ bool LuaHook_Init() { void LuaHook_Shutdown() { MH_DisableHook(MH_ALL_HOOKS); MH_Uninitialize(); -} \ No newline at end of file +} diff --git a/lua_hook.h b/lua_hook.h index 9ba5987..dfcf5cb 100644 --- a/lua_hook.h +++ b/lua_hook.h @@ -1,60 +1,44 @@ #pragma once -#include +#include "rvas.h" -struct LuaRVAs { - uintptr_t lua_open; - uintptr_t lua_pushstring; - 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) -}; +struct lua_State; +typedef int (*lua_CFunction)(lua_State*); -// StarWarsI.exe -- debug kit, PDB available -constexpr LuaRVAs RVAs_StarWarsI = { - 0x12AB790, // lua_open - 0x12AC930, // lua_pushstring - 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 -}; +// 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 double (*fn_lua_tonumber)(lua_State*, int); +typedef void (*fn_lua_newtable)(lua_State*); +typedef void (*fn_lua_rawseti)(lua_State*, int, 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 -// StarWarsG.exe -- client binary, no PDB -constexpr LuaRVAs RVAs_StarWarsG = { - 0x07b8930, // lua_open - 0x07b9540, // lua_pushstring - 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) -}; +// Resolved function pointers (defined in lua_hook.cpp) +extern fn_lua_open real_lua_open; +extern fn_lua_pushstring pfn_pushstring; +extern fn_lua_pushcclosure pfn_pushcclosure; +extern fn_lua_settable pfn_settable; +extern fn_lua_tostring pfn_tostring; +extern fn_lua_tonumber pfn_tonumber; +extern fn_lua_newtable pfn_newtable; +extern fn_lua_rawseti pfn_rawseti; +extern fn_GetPlayerByIndex pfn_get_player_by_index; +extern void* g_player_list; +extern fn_PlayerWrapperCreate pfn_player_wrapper_create; +extern fn_GetScriptFromState pfn_get_script_from_state; +extern fn_MapVarToLua pfn_map_var_to_lua; +extern fn_DebugPrint pfn_debug_print; 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); + bool LuaHook_Init(); -void LuaHook_Shutdown(); \ No newline at end of file +void LuaHook_Shutdown(); diff --git a/rvas.h b/rvas.h new file mode 100644 index 0000000..abd4028 --- /dev/null +++ b/rvas.h @@ -0,0 +1,76 @@ +#pragma once +#include + +struct LuaRVAs { + // --- Lua Core --- + uintptr_t lua_open; + uintptr_t lua_pushstring; + uintptr_t lua_pushcclosure; + uintptr_t lua_settable; + uintptr_t lua_tostring; + uintptr_t lua_tonumber; + uintptr_t lua_newtable; + uintptr_t lua_rawseti; + + // --- Players --- + 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) + + // --- Scripts --- + uintptr_t get_script_from_state; // LuaScriptClass::Get_Script_From_State (static) + uintptr_t map_var_to_lua; // LuaScriptClass::Map_Var_To_Lua (member) + + // --- Debug --- + uintptr_t debug_print; // Debug_Print(char*) +}; + +// StarWarsI.exe -- debug kit, PDB available +constexpr LuaRVAs RVAs_StarWarsI = { + // --- Lua Core --- + 0x12AB790, // lua_open + 0x12AC930, // lua_pushstring + 0x12AC6E0, // lua_pushcclosure + 0x12AD020, // lua_settable + 0x12AD430, // lua_tostring + 0x12AD300, // lua_tonumber + 0x12AC460, // lua_newtable + 0x12ACD70, // lua_rawseti + + // --- Players --- + 0x06FA990, // PlayerListClass::Get_Player_By_Index + 0x1913158, // PlayerList global object + 0x0F12010, // PlayerWrapper::Create + + // --- Scripts --- + 0x0537BB0, // LuaScriptClass::Get_Script_From_State + 0x0536FE0, // LuaScriptClass::Map_Var_To_Lua + + // --- Debug --- + 0x0476AE0, // Debug_Print +}; + +// StarWarsG.exe -- client binary, no PDB +constexpr LuaRVAs RVAs_StarWarsG = { + // --- Lua Core --- + 0x07b8930, // lua_open + 0x07b9540, // lua_pushstring + 0x07b9340, // lua_pushcclosure + 0x07b9a60, // lua_settable + 0x07b9cc0, // lua_tostring + 0, // lua_tonumber (TODO) + 0, // lua_newtable (TODO) + 0, // lua_rawseti (TODO) + + // --- Players --- + 0, // PlayerListClass::Get_Player_By_Index (TODO) + 0, // PlayerList global object (TODO) + 0, // PlayerWrapper::Create (TODO) + + // --- Scripts --- + 0, // LuaScriptClass::Get_Script_From_State (TODO) + 0, // LuaScriptClass::Map_Var_To_Lua (TODO) + + // --- Debug --- + 0, // Debug_Print (TODO) +};