Use inline ctors for GameObjectTypeWrapper, LuaMemberFunctionWrapper
This commit is contained in:
@@ -8,6 +8,19 @@
|
||||
// SmartPtr stores the raw pointer as its first member.
|
||||
static constexpr int OFFSET_OBJECT = 0x70;
|
||||
|
||||
// MSVC std::string layout (x64, MSVC 14.0+).
|
||||
// Used to read the std::string at a known field offset within GameObjectTypeClass.
|
||||
struct MSVCString {
|
||||
union {
|
||||
char buf[16]; // SSO buffer (up to 15 chars + null)
|
||||
char* ptr; // heap pointer when capacity > 15
|
||||
};
|
||||
size_t size;
|
||||
size_t capacity; // <= 15 means SSO, > 15 means heap
|
||||
|
||||
const char* c_str() const { return (capacity <= 15) ? buf : ptr; }
|
||||
};
|
||||
|
||||
// MSVC std::wstring layout (x64, MSVC 14.0+).
|
||||
// Used to read the wstring* returned by GameTextClass::Get.
|
||||
struct MSVCWString {
|
||||
@@ -31,11 +44,10 @@ static void* Lua_Get_Display_Name(void* this_wrapper, void* /*script*/, void* /*
|
||||
if (!got_class)
|
||||
return nullptr;
|
||||
|
||||
// 2. Get the text ID string (e.g. "TEXT_UNIT_X_WING") via Get_Text_Name_ID.
|
||||
// The game's function constructs a std::string into our buffer via copy-ctor.
|
||||
// Assumes shared CRT (both DLL and game link to vcruntime140.dll dynamically).
|
||||
std::string text_id;
|
||||
pfn_get_text_name_id(got_class, &text_id);
|
||||
// 2. Read the TextNameID string directly from the GameObjectTypeClass field.
|
||||
// Get_Text_Name_ID() is always inlined by the compiler, so we use the field offset.
|
||||
MSVCString* text_name = (MSVCString*)((char*)got_class + g_text_name_id_offset);
|
||||
std::string text_id(text_name->c_str(), text_name->size);
|
||||
|
||||
// 3. Resolve the localized display name via TheGameText.Get(text_id, false).
|
||||
// Returns a pointer to an internal wstring (the translated text).
|
||||
@@ -64,26 +76,36 @@ static void* Lua_Get_Display_Name(void* this_wrapper, void* /*script*/, void* /*
|
||||
|
||||
void Register_GOTMembers(void* wrapper)
|
||||
{
|
||||
if (!pfn_lmfw_ctor || !pfn_register_member)
|
||||
if (!pfn_lua_uservar_ctor || !pfn_register_member)
|
||||
return;
|
||||
if (!pfn_get_text_name_id || !pfn_game_text_get || !g_the_game_text)
|
||||
if (!g_text_name_id_offset || !pfn_game_text_get || !g_the_game_text)
|
||||
return;
|
||||
if (!pfn_return_variable)
|
||||
if (!pfn_return_variable || !g_rvas || !g_rvas->lmfw_vftable)
|
||||
return;
|
||||
|
||||
// Allocate a LuaMemberFunctionWrapper<GameObjectTypeWrapper> (0x88 bytes).
|
||||
void* lmfw = ::operator new(0x88);
|
||||
const LuaRVAs* rvas = g_rvas;
|
||||
|
||||
// Allocate a LuaMemberFunctionWrapper<GameObjectTypeWrapper>.
|
||||
void* lmfw = ::operator new(rvas->lmfw_alloc_size);
|
||||
if (!lmfw) return;
|
||||
memset(lmfw, 0, 0x88);
|
||||
memset(lmfw, 0, rvas->lmfw_alloc_size);
|
||||
|
||||
// Build the 16-byte pointer-to-member-function structure.
|
||||
// Initialize the LuaUserVar base class.
|
||||
pfn_lua_uservar_ctor(lmfw, 0, false);
|
||||
|
||||
// Set the LuaMemberFunctionWrapper<> vftable.
|
||||
*(uintptr_t*)lmfw = g_base + rvas->lmfw_vftable;
|
||||
|
||||
// Write the 16-byte pointer-to-member-function (PMF) into the MemberFunction field.
|
||||
// MSVC x64 multiple-inheritance PMF: [8-byte func addr][8-byte this-adjustment].
|
||||
// this-adjustment is 0 (our function expects the full GameObjectTypeWrapper*).
|
||||
alignas(8) uint8_t pmf[16] = {};
|
||||
*(uintptr_t*)pmf = (uintptr_t)&Lua_Get_Display_Name;
|
||||
memcpy((char*)lmfw + rvas->lmfw_pmf_offset, pmf, 16);
|
||||
|
||||
// Construct the LuaMemberFunctionWrapper via the game's ctor.
|
||||
pfn_lmfw_ctor(lmfw, wrapper, pmf, false);
|
||||
// Set the Object (wrapper pointer) and UseMaps flag.
|
||||
*(void**)((char*)lmfw + rvas->lmfw_object_offset) = wrapper;
|
||||
*(bool*)((char*)lmfw + rvas->lmfw_usemaps_offset) = false;
|
||||
|
||||
// Register as a member callable via wrapper.Get_Display_Name()
|
||||
pfn_register_member(wrapper, "Get_Display_Name", lmfw);
|
||||
|
||||
Reference in New Issue
Block a user