diff --git a/src/overlay/Overlay.cpp b/src/overlay/Overlay.cpp index 5e0d5ec1..ea73ecfe 100644 --- a/src/overlay/Overlay.cpp +++ b/src/overlay/Overlay.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "imgui_impl_dx12.h" #include "imgui_impl_win32.h" @@ -152,7 +153,19 @@ LRESULT APIENTRY Overlay::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP return CallWindowProc(s_pOverlay->m_wndProc, hwnd, uMsg, wParam, lParam); } -using TScriptCall = void*(uint8_t*, uint8_t**, REDString*, void*); +struct ScriptContext +{ +}; + +struct ScriptStack +{ + uint8_t* m_code; + uint8_t pad[0x28]; + void* unk30; + void* unk38; + ScriptContext* m_context; +}; +static_assert(offsetof(ScriptStack, m_context) == 0x40); TScriptCall** GetScriptCallArray() { @@ -162,23 +175,109 @@ TScriptCall** GetScriptCallArray() return reinterpret_cast(finalLocation); } - -void* Overlay::HookLog(uintptr_t apThis, uint8_t** apStack) +void Overlay::HookLog(ScriptContext* apContext, ScriptStack* apStack, void*, void*) { - REDString result(""); - apStack[6] = nullptr; - apStack[7] = nullptr; - auto stack = *(*apStack)++; - GetScriptCallArray()[stack](apStack[8], apStack, &result, nullptr); - ++(*apStack); + REDString text(""); + apStack->unk30 = nullptr; + apStack->unk38 = nullptr; + auto opcode = *(apStack->m_code++); + GetScriptCallArray()[opcode](apStack->m_context, apStack, &text, nullptr); + apStack->m_code++; // skip ParamEnd - Get().Log(result.ToString()); + Get().Log(text.ToString()); - result.Destroy(); + text.Destroy(); +} +const char* GetChannelStr(uint64_t hash) +{ + switch (hash) + { +#define HASH_CASE(x) case RED4ext::FNV1a(x): return x + HASH_CASE("AI"); + HASH_CASE("AICover"); + HASH_CASE("ASSERT"); + HASH_CASE("Damage"); + HASH_CASE("DevelopmentManager"); + HASH_CASE("Device"); + HASH_CASE("Items"); + HASH_CASE("ItemManager"); + HASH_CASE("Puppet"); + HASH_CASE("Scanner"); + HASH_CASE("Stats"); + HASH_CASE("StatPools"); + HASH_CASE("Strike"); + HASH_CASE("TargetManager"); + HASH_CASE("Test"); + HASH_CASE("UI"); + HASH_CASE("Vehicles"); +#undef HASH_CASE + } return nullptr; } +void Overlay::HookLogChannel(ScriptContext* apContext, ScriptStack* apStack, void*, void*) +{ + uint8_t opcode; + + uint64_t channel_hash = 0; + apStack->unk30 = nullptr; + apStack->unk38 = nullptr; + opcode = *(apStack->m_code++); + GetScriptCallArray()[opcode](apStack->m_context, apStack, &channel_hash, nullptr); + + REDString text(""); + apStack->unk30 = nullptr; + apStack->unk38 = nullptr; + opcode = *(apStack->m_code++); + GetScriptCallArray()[opcode](apStack->m_context, apStack, &text, nullptr); + + apStack->m_code++; // skip ParamEnd + + auto channel_str = GetChannelStr(channel_hash); + std::string channel = channel_str == nullptr + ? "?" + std::to_string(channel_hash) + : std::string(channel_str); + Get().Log("[" + channel + "] " +text.ToString()); + + text.Destroy(); +} + +void Overlay::HookTDBIDToStringDEBUG(ScriptContext* apContext, ScriptStack* apStack, void* result, void*) +{ + uint8_t opcode; + +#pragma pack(push,1) + struct TDBID + { + uint32_t hash; + uint8_t unk4; + uint16_t unk5; + uint8_t unk7; + }; +#pragma pack(pop) + static_assert(sizeof(TDBID) == 8); + + TDBID tdbid_value{}; + apStack->unk30 = nullptr; + apStack->unk38 = nullptr; + opcode = *(apStack->m_code++); + GetScriptCallArray()[opcode](apStack->m_context, apStack, &tdbid_value, nullptr); + apStack->m_code++; // skip ParamEnd + + if (result) + { + std::string tdbid_debug = (tdbid_value.unk5 == 0 && tdbid_value.unk7 == 0) + ? fmt::format("", + tdbid_value.hash, tdbid_value.unk4) + : fmt::format("", + tdbid_value.hash, tdbid_value.unk4, tdbid_value.unk5, tdbid_value.unk7); + REDString s(tdbid_debug.c_str()); + ((REDString*)result)->Copy(&s); + s.Destroy(); + } +} + void Overlay::Toggle() { struct Singleton @@ -215,4 +314,3 @@ void Overlay::Log(const std::string& acpText) Overlay::Overlay() = default; Overlay::~Overlay() = default; - diff --git a/src/overlay/Overlay.h b/src/overlay/Overlay.h index d6d6d207..d91f18fe 100644 --- a/src/overlay/Overlay.h +++ b/src/overlay/Overlay.h @@ -9,10 +9,14 @@ #include "reverse/Engine.h" +struct ScriptContext; +struct ScriptStack; +struct REDString; + using TPresentD3D12 = long(IDXGISwapChain3* pSwapChain, UINT SyncInterval, UINT Flags); using TSetMousePosition = BOOL(void* apThis, HWND Wnd, long X, long Y); using TClipToCenter = HWND(CGameEngine::UnkC0* apThis); -using TLog = void*(uintptr_t a1, uint8_t** a2); +using TScriptCall = void(ScriptContext*, ScriptStack*, void*, void*); struct Image; struct Overlay @@ -49,8 +53,10 @@ struct Overlay static BOOL SetMousePosition(void* apThis, HWND Wnd, long X, long Y); static BOOL ClipToCenter(CGameEngine::UnkC0* apThis); static LRESULT APIENTRY WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - static void* HookLog(uintptr_t apThis, uint8_t** apStack); - + static void HookLog(ScriptContext* apContext, ScriptStack* apStack, void*, void*); + static void HookLogChannel(ScriptContext* apContext, ScriptStack* apStack, void*, void*); + static void HookTDBIDToStringDEBUG(ScriptContext* apContext, ScriptStack* apStack, void*, void*); + private: Overlay(); @@ -61,7 +67,9 @@ struct Overlay ID3D12DescriptorHeap* m_pd3dSrvDescHeap; ID3D12GraphicsCommandList* m_pd3dCommandList; TClipToCenter* m_realClipToCenter{nullptr}; - TLog* m_realLog{nullptr}; + TScriptCall* m_realLog{nullptr}; + TScriptCall* m_realLogChannel{ nullptr }; + TScriptCall* m_realTDBIDToStringDEBUG{ nullptr }; HWND m_hwnd; WNDPROC m_wndProc{nullptr}; bool m_enabled{ false }; diff --git a/src/overlay/Overlay_Hooks.cpp b/src/overlay/Overlay_Hooks.cpp index ac605de9..aba934ac 100644 --- a/src/overlay/Overlay_Hooks.cpp +++ b/src/overlay/Overlay_Hooks.cpp @@ -40,6 +40,58 @@ void Overlay::EarlyHooks(Image* apImage) else spdlog::info("\tLog function hook complete!"); } + + pLocation = FindSignature({ + 0x48, 0x89, 0x5C, 0x24, 0x08, 0x48, 0x89, 0x74, + 0x24, 0x18, 0x57, 0x48, 0x83, 0xEC, 0x40, 0x48, + 0x8B, 0x02, 0x48, 0x8D, 0x3D, 0xCC, 0xCC, 0xCC, + 0xCC, 0x33, 0xF6, 0x4C, 0x8D, 0x44, 0x24, 0x58, + 0x48, 0x89, 0x74, 0x24, 0x58, 0x45, 0x33, 0xC9, + 0x48, 0x89, 0x72, 0x30, 0x48, 0x8B, 0xDA, 0x48, + 0x89, 0x72, 0x38, 0x0F, 0xB6, 0x08, 0x48, 0xFF, + 0xC0, 0x48, 0x89, 0x02, 0x8B, 0xC1, 0x48, 0x8B, + 0x4A, 0x40, 0xFF, 0x14, 0xC7, 0xE8, 0xCC, 0xCC, + 0xCC, 0xCC, 0x48, 0x8B, 0xD0 + }); + + if (pLocation) + { + if (MH_CreateHook(pLocation, &HookLogChannel, reinterpret_cast(&m_realLogChannel)) != MH_OK || MH_EnableHook(pLocation) != MH_OK) + { + spdlog::error("\tCould not hook LogChannel function!"); + } + else + spdlog::info("\LogChannel function hook complete!"); + } + + pLocation = FindSignature({ + 0x48, 0xBF, 0x58, 0xD1, 0x78, 0xA0, 0x18, 0x09, + 0xBA, 0xEC, 0x75, 0x16, 0x48, 0x8D, 0x15, 0xCC, + 0xCC, 0xCC, 0xCC, 0x48, 0x8B, 0xCF, 0xE8, 0xCC, + 0xCC, 0xCC, 0xCC, 0xC6, 0x05, 0xCC, 0xCC, 0xCC, + 0xCC, 0x01, 0x41, 0x8B, 0x06, 0x39, 0x05, 0xCC, + 0xCC, 0xCC, 0xCC, 0x7F + }); + + if (pLocation) + { + pLocation = &pLocation[45] + static_cast(pLocation[44]); + pLocation = FindSignature(pLocation, pLocation + 45, { + 0x48, 0x8D, 0x0D, 0xCC, 0xCC, 0xCC, 0xCC, 0xE8, + 0xCC, 0xCC, 0xCC, 0xCC, 0x83, 0x3D, 0xCC, 0xCC, + 0xCC, 0xCC, 0xFF, 0x75, 0xCC, 0x48, 0x8D, 0x05, + }); + if (pLocation) + { + pLocation = &pLocation[28] + *reinterpret_cast(&pLocation[24]); + if (MH_CreateHook(pLocation, &HookTDBIDToStringDEBUG, reinterpret_cast(&m_realTDBIDToStringDEBUG)) != MH_OK || MH_EnableHook(pLocation) != MH_OK) + { + spdlog::error("\tCould not hook TDBID::ToStringDEBUG function!"); + } + else + spdlog::info("\tTDBID::ToStringDEBUG function hook complete!"); + } + } } long Overlay::PresentD3D12(IDXGISwapChain3* pSwapChain, UINT SyncInterval, UINT Flags) diff --git a/src/reverse/REDString.cpp b/src/reverse/REDString.cpp index a16e4818..5e1acadb 100644 --- a/src/reverse/REDString.cpp +++ b/src/reverse/REDString.cpp @@ -28,6 +28,22 @@ REDString::REDString(const char* acpData) RealStringCtor(this, acpData); } +REDString* REDString::Copy(REDString* other) +{ + static uint8_t* CopyCaller = FindSignature({ + 0x40, 0x53, 0x48, 0x83, 0xEC, 0x20, 0x48, 0x8B, + 0xCA, 0x49, 0x8B, 0xD8, 0xE8, 0xCC, 0xCC, 0xCC, + 0xCC, 0x48, 0x8B, 0xD0, 0x48, 0x8B, 0xCB, 0xE8, + 0xCC, 0xCC, 0xCC, 0xCC, 0xB0, 0x01, 0x48, 0x83, + 0xC4, 0x20, 0x5B, 0xC3 + }); + using TStringCopy = REDString*(REDString*, REDString*); + static TStringCopy* RealStringCopy = reinterpret_cast( + &CopyCaller[28] + *reinterpret_cast(&CopyCaller[24])); + + return RealStringCopy(this, other); +} + void REDString::Destroy() { using TStringDtor = void(REDString*); diff --git a/src/reverse/REDString.h b/src/reverse/REDString.h index cc0a67f9..39dffd7a 100644 --- a/src/reverse/REDString.h +++ b/src/reverse/REDString.h @@ -7,6 +7,7 @@ struct REDString { REDString(); REDString(const char* acpData); + REDString* Copy(REDString* other); void Destroy(); char* ToString()