From 414f0c9a7ebbaf30a549999e49d952b9afc973e8 Mon Sep 17 00:00:00 2001 From: Maximilian Wittfeld Date: Tue, 11 Feb 2025 19:36:53 +0100 Subject: [PATCH] tweak(gta-five-net): network synchronised scene id hacks --- .../src/state/ServerGameState.cpp | 21 +-- .../src/NetworkSynchronisedSceneHacks.cpp | 147 ++++++++++++++++++ 2 files changed, 155 insertions(+), 13 deletions(-) create mode 100644 code/components/gta-net-five/src/NetworkSynchronisedSceneHacks.cpp diff --git a/code/components/citizen-server-impl/src/state/ServerGameState.cpp b/code/components/citizen-server-impl/src/state/ServerGameState.cpp index b28187af46..edf327f24a 100644 --- a/code/components/citizen-server-impl/src/state/ServerGameState.cpp +++ b/code/components/citizen-server-impl/src/state/ServerGameState.cpp @@ -5747,12 +5747,11 @@ struct CNetworkPtFXEvent struct CRequestNetworkSyncedSceneEvent { - uint16_t sceneId; + uint32_t sceneId; // Increased from uint16_t, see "NetworkSynchronisedSceneHacks.cpp" void Parse(rl::MessageBufferView& buffer) { - // FIXME: Scene ID length-hack workaround, see `CStartNetworkSyncedSceneEvent`. - sceneId = buffer.Read(8) | (buffer.Read(5) << 8); + sceneId = buffer.Read(32); } inline std::string GetName() @@ -5839,7 +5838,7 @@ struct CStartNetworkSyncedSceneEvent }; public: - uint16_t sceneId; + uint32_t sceneId; // Increased from uint16_t, see "NetworkSynchronisedSceneHacks.cpp" uint32_t startTime; bool isActive; @@ -5873,9 +5872,7 @@ struct CStartNetworkSyncedSceneEvent void Parse(rl::MessageBufferView& buffer) { - // FIXME: Synced scene IDs are 13 bits in length, but since it's not an object ID, it's conflicting - // with our length-hack logic... We're working around this issue by reading these 13 bits in two parts. - sceneId = buffer.Read(8) | (buffer.Read(5) << 8); + sceneId = buffer.Read(32); startTime = buffer.Read(32); @@ -5958,13 +5955,12 @@ struct CStartNetworkSyncedSceneEvent struct CUpdateNetworkSyncedSceneEvent { - uint16_t sceneId; + uint32_t sceneId; // Increased from uint16_t, see "NetworkSynchronisedSceneHacks.cpp" float rate; void Parse(rl::MessageBufferView& buffer) { - // FIXME: Scene ID length-hack workaround, see `CStartNetworkSyncedSceneEvent`. - sceneId = buffer.Read(8) | (buffer.Read(5) << 8); + sceneId = buffer.Read(32); rate = (buffer.Read(8) / 255.0f) * 2.0f; } @@ -5979,12 +5975,11 @@ struct CUpdateNetworkSyncedSceneEvent struct CStopNetworkSyncedSceneEvent { - uint16_t sceneId; + uint32_t sceneId; // Increased from uint16_t, see "NetworkSynchronisedSceneHacks.cpp" void Parse(rl::MessageBufferView& buffer) { - // FIXME: Scene ID length-hack workaround, see `CStartNetworkSyncedSceneEvent`. - sceneId = buffer.Read(8) | (buffer.Read(5) << 8); + sceneId = buffer.Read(32); } inline std::string GetName() diff --git a/code/components/gta-net-five/src/NetworkSynchronisedSceneHacks.cpp b/code/components/gta-net-five/src/NetworkSynchronisedSceneHacks.cpp new file mode 100644 index 0000000000..9606ff3f06 --- /dev/null +++ b/code/components/gta-net-five/src/NetworkSynchronisedSceneHacks.cpp @@ -0,0 +1,147 @@ +#include "StdInc.h" + +#include "CrossBuildRuntime.h" +#include "Hooking.h" +#include "NetGameEvent.h" + +#include + +template +static int GetServerId(const rlGamerInfo& platformData) +{ + return (platformData.peerAddress.localAddr().ip.addr & 0xFFFF) ^ 0xFEED; +} + +static int DoGetServerId(CNetGamePlayer* player) +{ + if (xbr::IsGameBuildOrGreater<2824>()) + { + return GetServerId(*player->GetGamerInfo<2824>()); + } + + if (xbr::IsGameBuildOrGreater<2372>()) + { + return GetServerId(*player->GetGamerInfo<2372>()); + } + + if (xbr::IsGameBuildOrGreater<2060>()) + { + return GetServerId(*player->GetGamerInfo<2060>()); + } + + return GetServerId(*player->GetGamerInfo<1604>()); +} + +static constexpr char pattern[] = "\x41\xB8\x0D\x00\x00\x00"; +static auto FindPattern(const uintptr_t startAddress) +{ + auto address = reinterpret_cast(startAddress); + + while (true) + { + assert(*address != 0xE9); + + if (memcmp(address, pattern, sizeof(pattern) - 1) == 0) + { + return reinterpret_cast(address); + } + + ++address; + } +} + +static uint32_t GetSceneIdOffset(CNetGamePlayer* player) +{ + return (DoGetServerId(player) - 1) * 64; +} + +static HookFunction hookFunction([]() +{ + // StartScene - Serializer + { + //Write + hook::put(hook::get_pattern("41 B8 ? ? ? ? 48 8B C8 C6 44 24 ? ? E8 ? ? ? ? 48 8B 7C 24", 2), 32); + + //Read + hook::put(hook::get_pattern("41 B8 ? ? ? ? 48 8B C8 48 8B D6", 2), 32); + } + + // Request-/StopScene - Serializer + { + const auto cCRequestNetworkSyncedSceneEvent_vtable = hook::get_address(hook::get_pattern("48 8D 05 ? ? ? ? 89 5E ? 48 8B 5C 24 ? 48 89 06 8A 47", 3)); + + // Write + uintptr_t target = cCRequestNetworkSyncedSceneEvent_vtable[5]; + + hook::put(FindPattern(target) + 2, 32); + + // Read + target = cCRequestNetworkSyncedSceneEvent_vtable[6]; + + hook::put(FindPattern(target) + 2, 32); + } + + // UpdateScene - Serializer + { + const auto cCUpdateNetworkSyncedSceneEvent_vtable = hook::get_address(hook::get_pattern("48 8D 05 ? ? ? ? F3 0F 11 77 ? 0F 28 74 24", 3)); + + // Write + uintptr_t target = cCUpdateNetworkSyncedSceneEvent_vtable[5]; + target = target + 5 + *reinterpret_cast(target + 1); + + hook::put(FindPattern(target) + 2, 32); + + // Read + target = cCUpdateNetworkSyncedSceneEvent_vtable[6]; + target = target + 5 + *reinterpret_cast(target + 1); + + hook::put(FindPattern(target) + 2, 32); + } + + // CClonedSynchronizedSceneInfo - Serializer + { + const auto cClonedSynchronizedSceneInfo_vtable = hook::get_address(hook::get_pattern("48 8D 05 ? ? ? ? E9 ? ? ? ? 48 8B 0D ? ? ? ? 45 33 C9 4D 8B C6 BA ? ? ? ? E8 ? ? ? ? 48 85 C0 0F 84 ? ? ? ? 48 8B C8 E8 ? ? ? ? E9 ? ? ? ? 48 8B 0D ? ? ? ? 45 33 C9 4D 8B C6 BA", 3)); + + int vtableIdx = 24; + + if (xbr::IsGameBuildOrGreater<2802>()) + { + vtableIdx = 30; + } + + hook::put(cClonedSynchronizedSceneInfo_vtable[vtableIdx] + 0x1F + 3, 32); + } + + // CNetworkSynchronizedScenes - Scene Allocator + { + static struct : jitasm::Frontend + { + intptr_t retAddress; + + void Init(const intptr_t ret) + { + this->retAddress = ret; + } + + void InternalMain() override + { + mov(rcx, rax); + mov(rax, reinterpret_cast(&GetSceneIdOffset)); + call(rax); + mov(ebp, eax); + + mov(rax, retAddress); + jmp(rax); + } + } patchStub; + + auto location = hook::get_pattern("0F B6 68 ? C1 E5"); + + const auto ret = reinterpret_cast(location) + 7; + + patchStub.Init(ret); + + hook::nop(location, 7); + hook::jump_rcx(location, patchStub.GetCode()); + } +});