diff --git a/docs/red4ext-logging-shim.md b/docs/red4ext-logging-shim.md index b2be1a7..45f4004 100644 --- a/docs/red4ext-logging-shim.md +++ b/docs/red4ext-logging-shim.md @@ -1,6 +1,7 @@ # RED4ext logging shim -`EdgeWeightGPS` is a minimal RED4ext plugin used to verify a native logging foothold without changing gameplay data. +`EdgeWeightGPS` is a RED4ext plugin used to probe native GPS/mappin code paths +without changing gameplay data. It writes `EdgeWeightGPS.log` beside the installed DLL: @@ -12,11 +13,19 @@ Current behavior: - Logs plugin load/unload. - Logs the RED4ext plugin handle and SDK pointer value passed to `Main`. -- Does not call game RTTI or register script functions. +- Registers Running game-state callbacks so route tests can be timestamped. +- Hooks selected native wrappers and cores around `GPSSystem`, mappin tracking, + world-map mappin selection, and map path framing. +- Resolves the native mappin system when one of those paths fires, logs relevant + vtable slot addresses, and temporarily hooks the route-adjacent slots. -Planned next step: +Current route-probe focus: -- Build a richer RTTI/hooking variant with an MSVC-compatible Windows toolchain or a narrower hand-written SDK surface. The upstream RED4ext SDK headers build under MinGW for loader-only use, but the full SDK/static library currently pulls in generated native/GPU structures with MSVC layout assumptions. +- `FrameMappinPath` wrapper/core: `0x27c4314`, `0x27bc1ec` +- `SetSelectedMappin` wrappers/core: `0x27c4a38`, `0x27c4944`, + `0x27c49c4`, `0x27c1684` +- `TrackCustomPositionMappin` wrapper/core: `0x27c4aac`, `0x27c2318` +- mappin-system slots `0x1f0`, `0x280`, and `0x2f0` Build and install from the Fedora toolbox: diff --git a/docs/traffic-system-debrief.md b/docs/traffic-system-debrief.md index 3027d37..06ef3b8 100644 --- a/docs/traffic-system-debrief.md +++ b/docs/traffic-system-debrief.md @@ -73,7 +73,7 @@ selection. ## Mappin Tracking Handoff -The current native lead is the script/native mappin tracking path: +The first native lead was the script/native mappin tracking path: ```text TrackMappin string rva: 0x2e82c30 @@ -98,16 +98,45 @@ the supplied mappin handle is null: - non-null tracked mappin: call resolved system vtable slot `0x220` - null tracked mappin: call resolved system vtable slot `0x228` -That looks exactly like "set tracked mappin" versus "clear tracked mappin". The -installed RED4ext probe now resolves this system at runtime, logs the concrete -vtable addresses for slots `0x220`, `0x228`, `0x250`, `0x2e0`, `0x368`, and -`0x3a8`, and attaches temporary hooks to slots `0x220` and `0x228`. The next -in-game route-plotting run should therefore give directly disassemblable RVAs -for the concrete mappin-system methods that receive the tracked destination. +That looks exactly like "set tracked mappin" versus "clear tracked mappin". +However, a clean live test disproved it as the normal world-map route plotting +path: `TrackMappin`, `TrackMappinCore`, and +`SetMappinTrackingAlternative` did not fire while plotting three map routes. `SetMappinTrackingAlternative` parses two script arguments and calls vtable slot `0x418` on its receiver. It is probably related to alternate tracking behavior, -but static disassembly has not yet shown it to be the main route planner. +but static disassembly and live logging have not shown it to be the main route +planner. + +## World-Map Mappin Selection Lead + +The next native lead is the world-map mappin controller block around +`0x1427c4314`. These functions are still mappin-facing, but they are closer to +selection, framing, and custom-position route display than the script helper +above: + +```text +FrameMappinPath wrapper rva: 0x27c4314 +FrameMappinPath core rva: 0x27bc1ec +SetSelectedMappin wrapper rva: 0x27c4a38 +SetSelectedMappin by-id wrapper rva: 0x27c4944 +SetSelectedMappin by-position wrapper rva: 0x27c49c4 +SetSelectedMappin core rva: 0x27c1684 +TrackCustomPositionMappin wrapper rva: 0x27c4aac +TrackCustomPositionMappin core rva: 0x27c2318 +UntrackCustomPositionMappin wrapper rva: 0x27c4ba0 +Mappin system resolver rva: 0x02bb840 +``` + +`FrameMappinPath` calls the resolved mappin-system vtable slot `0x280`. +`TrackCustomPositionMappin` calls slot `0x2f0` to create a custom-position +mappin/route handle and slot `0x1f0` to update an existing one. Those calls are +currently the most route-like native behavior found in static disassembly. + +The installed RED4ext probe now logs the wrappers and cores listed above. When +one of them can resolve the mappin system, it also logs concrete vtable RVAs for +slots `0x1f0`, `0x220`, `0x228`, `0x250`, `0x280`, `0x2e0`, `0x2f0`, `0x368`, +and `0x3a8`, then attaches temporary hooks to the route-adjacent slots. ## The High-Level Shape diff --git a/red4ext/EdgeWeightGPS/src/Main.cpp b/red4ext/EdgeWeightGPS/src/Main.cpp index 9f69316..3c82a59 100644 --- a/red4ext/EdgeWeightGPS/src/Main.cpp +++ b/red4ext/EdgeWeightGPS/src/Main.cpp @@ -92,12 +92,24 @@ namespace constexpr uint32_t kGameStateRunning = 2; constexpr uintptr_t kGpsSystemTickRva = 0x0E6B62C; constexpr uintptr_t kMappinSystemResolverRva = 0x02BB840; +constexpr uintptr_t kFrameMappinPathWrapperRva = 0x27C4314; +constexpr uintptr_t kFrameMappinPathCoreRva = 0x27BC1EC; +constexpr uintptr_t kSetSelectedMappinWrapperRva = 0x27C4A38; +constexpr uintptr_t kSetSelectedMappinByIdWrapperRva = 0x27C4944; +constexpr uintptr_t kSetSelectedMappinByPositionWrapperRva = 0x27C49C4; +constexpr uintptr_t kSetSelectedMappinCoreRva = 0x27C1684; +constexpr uintptr_t kTrackCustomPositionMappinWrapperRva = 0x27C4AAC; +constexpr uintptr_t kTrackCustomPositionMappinCoreRva = 0x27C2318; +constexpr uintptr_t kUntrackCustomPositionMappinWrapperRva = 0x27C4BA0; constexpr uintptr_t kTrackMappinWrapperRva = 0x27C4AB4; constexpr uintptr_t kTrackMappinCoreRva = 0x27C11D0; constexpr uintptr_t kSetMappinTrackingAlternativeWrapperRva = 0x1246794; +constexpr uintptr_t kMappinUpdateCustomPositionSlotOffset = 0x1F0; constexpr uintptr_t kMappinSetTrackedSlotOffset = 0x220; constexpr uintptr_t kMappinClearTrackedSlotOffset = 0x228; +constexpr uintptr_t kMappinFramePathSlotOffset = 0x280; constexpr uintptr_t kMappinPositionQuerySlotOffset = 0x2E0; +constexpr uintptr_t kMappinCreateCustomPositionSlotOffset = 0x2F0; constexpr uintptr_t kMappinReleaseQuerySlotOffset = 0x368; constexpr uintptr_t kMappinActiveRouteSlotOffset = 0x3A8; @@ -108,20 +120,35 @@ const RED4ext::v1::Sdk* gSdk = nullptr; uint32_t gUpdateLogCount = 0; bool gScannedExecutable = false; uint32_t gGpsTickLogCount = 0; +uint32_t gFrameMappinPathWrapperLogCount = 0; +uint32_t gFrameMappinPathCoreLogCount = 0; +uint32_t gSetSelectedMappinWrapperLogCount = 0; +uint32_t gSetSelectedMappinByIdWrapperLogCount = 0; +uint32_t gSetSelectedMappinByPositionWrapperLogCount = 0; +uint32_t gSetSelectedMappinCoreLogCount = 0; +uint32_t gTrackCustomPositionMappinWrapperLogCount = 0; +uint32_t gTrackCustomPositionMappinCoreLogCount = 0; +uint32_t gUntrackCustomPositionMappinWrapperLogCount = 0; uint32_t gTrackMappinWrapperLogCount = 0; uint32_t gTrackMappinCoreLogCount = 0; uint32_t gSetMappinTrackingAlternativeLogCount = 0; uint32_t gMappinSystemSlotLogCount = 0; +uint32_t gMappinUpdateCustomPositionLogCount = 0; uint32_t gMappinSetTrackedLogCount = 0; uint32_t gMappinClearTrackedLogCount = 0; +uint32_t gMappinFramePathLogCount = 0; uint32_t gMappinPositionQueryLogCount = 0; +uint32_t gMappinCreateCustomPositionLogCount = 0; uint32_t gMappinReleaseQueryLogCount = 0; uint32_t gMappinActiveRouteLogCount = 0; uint64_t gLogStartTick = 0; uint64_t gLogFrequency = 0; void* gMappinSetTrackedTarget = nullptr; void* gMappinClearTrackedTarget = nullptr; +void* gMappinUpdateCustomPositionTarget = nullptr; +void* gMappinFramePathTarget = nullptr; void* gMappinPositionQueryTarget = nullptr; +void* gMappinCreateCustomPositionTarget = nullptr; void* gMappinReleaseQueryTarget = nullptr; void* gMappinActiveRouteTarget = nullptr; bool gMappinSlotHookAttachAttempted = false; @@ -129,19 +156,37 @@ bool gMappinSlotHookAttachAttempted = false; using ProbeFunc = void (*)(void* aThis, void* a2, void* a3, void* a4); using ScriptNativeVoidFunc = void (*)(void* aThis, void* aStack, void* aResult); using MappinSystemResolverFunc = void* (*)(void* aThis); +using FrameMappinPathCoreFunc = void (*)(void* aThis, uint32_t aPathKind, void* a3, void* aPathRect); +using SetSelectedMappinCoreFunc = void (*)(void* aThis, void* aMappinHandle); +using TrackCustomPositionMappinCoreFunc = void (*)(void* aThis); using TrackMappinCoreFunc = void (*)(void* aThis, void* aMappinHandle); +using MappinUpdateCustomPositionFunc = void (*)(void* aSystem, void* aHandle, void* aPositionData); using MappinSetTrackedFunc = void (*)(void* aSystem, void* aMappinId); using MappinClearTrackedFunc = void (*)(void* aSystem); +using MappinFramePathFunc = void (*)(void* aSystem, uint32_t aPathKind, void* aResult); using MappinPositionQueryFunc = void* (*)(void* aSystem, void* a2, void* a3, void* a4, void* a5); +using MappinCreateCustomPositionFunc = void* (*)(void* aSystem, void* aName, void* aParams, void* aPositionData); using MappinReleaseQueryFunc = void (*)(void* aSystem, void* aHandle); using MappinActiveRouteFunc = void* (*)(void* aSystem); ProbeFunc gOriginalGpsSystemTick = nullptr; +ScriptNativeVoidFunc gOriginalFrameMappinPathWrapper = nullptr; +FrameMappinPathCoreFunc gOriginalFrameMappinPathCore = nullptr; +ScriptNativeVoidFunc gOriginalSetSelectedMappinWrapper = nullptr; +ScriptNativeVoidFunc gOriginalSetSelectedMappinByIdWrapper = nullptr; +ScriptNativeVoidFunc gOriginalSetSelectedMappinByPositionWrapper = nullptr; +SetSelectedMappinCoreFunc gOriginalSetSelectedMappinCore = nullptr; +ScriptNativeVoidFunc gOriginalTrackCustomPositionMappinWrapper = nullptr; +TrackCustomPositionMappinCoreFunc gOriginalTrackCustomPositionMappinCore = nullptr; +ScriptNativeVoidFunc gOriginalUntrackCustomPositionMappinWrapper = nullptr; ScriptNativeVoidFunc gOriginalTrackMappinWrapper = nullptr; TrackMappinCoreFunc gOriginalTrackMappinCore = nullptr; ScriptNativeVoidFunc gOriginalSetMappinTrackingAlternativeWrapper = nullptr; +MappinUpdateCustomPositionFunc gOriginalMappinUpdateCustomPosition = nullptr; MappinSetTrackedFunc gOriginalMappinSetTracked = nullptr; MappinClearTrackedFunc gOriginalMappinClearTracked = nullptr; +MappinFramePathFunc gOriginalMappinFramePath = nullptr; MappinPositionQueryFunc gOriginalMappinPositionQuery = nullptr; +MappinCreateCustomPositionFunc gOriginalMappinCreateCustomPosition = nullptr; MappinReleaseQueryFunc gOriginalMappinReleaseQuery = nullptr; MappinActiveRouteFunc gOriginalMappinActiveRoute = nullptr; @@ -270,6 +315,32 @@ void LogScriptNativeCall(const char* aName, uint32_t aCount, void* aThis, void* LogRed4ext(line.str()); } +void LogFrameMappinPathCoreCall(uint32_t aCount, void* aThis, uint32_t aPathKind, void* a3, void* aPathRect) +{ + std::ostringstream line; + line << "hook FrameMappinPathCore call=" << aCount << " this=" << aThis << " pathKind=" << aPathKind + << " a3=" << a3 << " pathRect=" << aPathRect; + AppendReturnRva(line, __builtin_return_address(0)); + LogRed4ext(line.str()); +} + +void LogSetSelectedMappinCoreCall(uint32_t aCount, void* aThis, void* aMappinHandle) +{ + std::ostringstream line; + line << "hook SetSelectedMappinCore call=" << aCount << " this=" << aThis + << " mappinHandle=" << aMappinHandle; + AppendReturnRva(line, __builtin_return_address(0)); + LogRed4ext(line.str()); +} + +void LogTrackCustomPositionMappinCoreCall(uint32_t aCount, void* aThis) +{ + std::ostringstream line; + line << "hook TrackCustomPositionMappinCore call=" << aCount << " this=" << aThis; + AppendReturnRva(line, __builtin_return_address(0)); + LogRed4ext(line.str()); +} + void LogTrackMappinCoreCall(uint32_t aCount, void* aThis, void* aMappinHandle) { std::ostringstream line; @@ -293,10 +364,13 @@ void LogMappinSystemSlots(uint32_t aCount, void* aSystem, void* aVtable) line << "mappin-system slots call=" << aCount; AppendPointerWithRva(line, "system", aSystem); AppendPointerWithRva(line, "vtable", aVtable); + AppendPointerWithRva(line, "slot1f0", readSlot(kMappinUpdateCustomPositionSlotOffset)); AppendPointerWithRva(line, "slot220", readSlot(kMappinSetTrackedSlotOffset)); AppendPointerWithRva(line, "slot228", readSlot(kMappinClearTrackedSlotOffset)); AppendPointerWithRva(line, "slot250", readSlot(0x250)); + AppendPointerWithRva(line, "slot280", readSlot(kMappinFramePathSlotOffset)); AppendPointerWithRva(line, "slot2e0", readSlot(kMappinPositionQuerySlotOffset)); + AppendPointerWithRva(line, "slot2f0", readSlot(kMappinCreateCustomPositionSlotOffset)); AppendPointerWithRva(line, "slot368", readSlot(kMappinReleaseQuerySlotOffset)); AppendPointerWithRva(line, "slot3a8", readSlot(kMappinActiveRouteSlotOffset)); LogRed4ext(line.str()); @@ -476,6 +550,154 @@ void DetourGpsSystemTick(void* aThis, void* a2, void* a3, void* a4) } } +void DetourFrameMappinPathWrapper(void* aThis, void* aStack, void* aResult) +{ + if (gFrameMappinPathWrapperLogCount < 64) + { + LogScriptNativeCall("FrameMappinPathWrapper", gFrameMappinPathWrapperLogCount, aThis, aStack, aResult); + ++gFrameMappinPathWrapperLogCount; + } + + InspectAndHookMappinSystem(aThis); + + if (gOriginalFrameMappinPathWrapper) + { + gOriginalFrameMappinPathWrapper(aThis, aStack, aResult); + } +} + +void DetourFrameMappinPathCore(void* aThis, uint32_t aPathKind, void* a3, void* aPathRect) +{ + if (gFrameMappinPathCoreLogCount < 64) + { + LogFrameMappinPathCoreCall(gFrameMappinPathCoreLogCount, aThis, aPathKind, a3, aPathRect); + ++gFrameMappinPathCoreLogCount; + } + + InspectAndHookMappinSystem(aThis); + + if (gOriginalFrameMappinPathCore) + { + gOriginalFrameMappinPathCore(aThis, aPathKind, a3, aPathRect); + } +} + +void DetourSetSelectedMappinWrapper(void* aThis, void* aStack, void* aResult) +{ + if (gSetSelectedMappinWrapperLogCount < 64) + { + LogScriptNativeCall("SetSelectedMappinWrapper", gSetSelectedMappinWrapperLogCount, aThis, aStack, aResult); + ++gSetSelectedMappinWrapperLogCount; + } + + InspectAndHookMappinSystem(aThis); + + if (gOriginalSetSelectedMappinWrapper) + { + gOriginalSetSelectedMappinWrapper(aThis, aStack, aResult); + } +} + +void DetourSetSelectedMappinByIdWrapper(void* aThis, void* aStack, void* aResult) +{ + if (gSetSelectedMappinByIdWrapperLogCount < 64) + { + LogScriptNativeCall("SetSelectedMappinByIdWrapper", gSetSelectedMappinByIdWrapperLogCount, aThis, aStack, + aResult); + ++gSetSelectedMappinByIdWrapperLogCount; + } + + InspectAndHookMappinSystem(aThis); + + if (gOriginalSetSelectedMappinByIdWrapper) + { + gOriginalSetSelectedMappinByIdWrapper(aThis, aStack, aResult); + } +} + +void DetourSetSelectedMappinByPositionWrapper(void* aThis, void* aStack, void* aResult) +{ + if (gSetSelectedMappinByPositionWrapperLogCount < 64) + { + LogScriptNativeCall("SetSelectedMappinByPositionWrapper", gSetSelectedMappinByPositionWrapperLogCount, aThis, + aStack, aResult); + ++gSetSelectedMappinByPositionWrapperLogCount; + } + + InspectAndHookMappinSystem(aThis); + + if (gOriginalSetSelectedMappinByPositionWrapper) + { + gOriginalSetSelectedMappinByPositionWrapper(aThis, aStack, aResult); + } +} + +void DetourSetSelectedMappinCore(void* aThis, void* aMappinHandle) +{ + if (gSetSelectedMappinCoreLogCount < 64) + { + LogSetSelectedMappinCoreCall(gSetSelectedMappinCoreLogCount, aThis, aMappinHandle); + ++gSetSelectedMappinCoreLogCount; + } + + InspectAndHookMappinSystem(aThis); + + if (gOriginalSetSelectedMappinCore) + { + gOriginalSetSelectedMappinCore(aThis, aMappinHandle); + } +} + +void DetourTrackCustomPositionMappinWrapper(void* aThis, void* aStack, void* aResult) +{ + if (gTrackCustomPositionMappinWrapperLogCount < 64) + { + LogScriptNativeCall("TrackCustomPositionMappinWrapper", gTrackCustomPositionMappinWrapperLogCount, aThis, + aStack, aResult); + ++gTrackCustomPositionMappinWrapperLogCount; + } + + InspectAndHookMappinSystem(aThis); + + if (gOriginalTrackCustomPositionMappinWrapper) + { + gOriginalTrackCustomPositionMappinWrapper(aThis, aStack, aResult); + } +} + +void DetourTrackCustomPositionMappinCore(void* aThis) +{ + if (gTrackCustomPositionMappinCoreLogCount < 64) + { + LogTrackCustomPositionMappinCoreCall(gTrackCustomPositionMappinCoreLogCount, aThis); + ++gTrackCustomPositionMappinCoreLogCount; + } + + InspectAndHookMappinSystem(aThis); + + if (gOriginalTrackCustomPositionMappinCore) + { + gOriginalTrackCustomPositionMappinCore(aThis); + } +} + +void DetourUntrackCustomPositionMappinWrapper(void* aThis, void* aStack, void* aResult) +{ + if (gUntrackCustomPositionMappinWrapperLogCount < 64) + { + LogScriptNativeCall("UntrackCustomPositionMappinWrapper", gUntrackCustomPositionMappinWrapperLogCount, aThis, + aStack, aResult); + ++gUntrackCustomPositionMappinWrapperLogCount; + } + + InspectAndHookMappinSystem(aThis); + + if (gOriginalUntrackCustomPositionMappinWrapper) + { + gOriginalUntrackCustomPositionMappinWrapper(aThis, aStack, aResult); + } +} + void DetourTrackMappinWrapper(void* aThis, void* aStack, void* aResult) { if (gTrackMappinWrapperLogCount < 64) @@ -521,6 +743,26 @@ void DetourSetMappinTrackingAlternativeWrapper(void* aThis, void* aStack, void* } } +void DetourMappinUpdateCustomPosition(void* aSystem, void* aHandle, void* aPositionData) +{ + if (gMappinUpdateCustomPositionLogCount < 32) + { + std::ostringstream line; + line << "hook MappinSystem::UpdateCustomPosition slot1f0 call=" << gMappinUpdateCustomPositionLogCount; + AppendPointerWithRva(line, "system", aSystem); + AppendPointerWithRva(line, "handle", aHandle); + AppendPointerWithRva(line, "positionData", aPositionData); + AppendReturnRva(line, __builtin_return_address(0)); + LogRed4ext(line.str()); + ++gMappinUpdateCustomPositionLogCount; + } + + if (gOriginalMappinUpdateCustomPosition) + { + gOriginalMappinUpdateCustomPosition(aSystem, aHandle, aPositionData); + } +} + void DetourMappinSetTracked(void* aSystem, void* aMappinId) { if (gMappinSetTrackedLogCount < 64) @@ -558,6 +800,26 @@ void DetourMappinClearTracked(void* aSystem) } } +void DetourMappinFramePath(void* aSystem, uint32_t aPathKind, void* aResult) +{ + if (gMappinFramePathLogCount < 32) + { + std::ostringstream line; + line << "hook MappinSystem::FramePath slot280 call=" << gMappinFramePathLogCount + << " pathKind=" << aPathKind; + AppendPointerWithRva(line, "system", aSystem); + AppendPointerWithRva(line, "result", aResult); + AppendReturnRva(line, __builtin_return_address(0)); + LogRed4ext(line.str()); + ++gMappinFramePathLogCount; + } + + if (gOriginalMappinFramePath) + { + gOriginalMappinFramePath(aSystem, aPathKind, aResult); + } +} + void* DetourMappinPositionQuery(void* aSystem, void* a2, void* a3, void* a4, void* a5) { const auto shouldLog = gMappinPositionQueryLogCount < 32; @@ -592,6 +854,39 @@ void* DetourMappinPositionQuery(void* aSystem, void* a2, void* a3, void* a4, voi return result; } +void* DetourMappinCreateCustomPosition(void* aSystem, void* aName, void* aParams, void* aPositionData) +{ + const auto shouldLog = gMappinCreateCustomPositionLogCount < 32; + if (shouldLog) + { + std::ostringstream line; + line << "hook MappinSystem::CreateCustomPosition slot2f0 call=" << gMappinCreateCustomPositionLogCount; + AppendPointerWithRva(line, "system", aSystem); + AppendPointerWithRva(line, "name", aName); + AppendPointerWithRva(line, "params", aParams); + AppendPointerWithRva(line, "positionData", aPositionData); + AppendReturnRva(line, __builtin_return_address(0)); + LogRed4ext(line.str()); + ++gMappinCreateCustomPositionLogCount; + } + + void* result = nullptr; + if (gOriginalMappinCreateCustomPosition) + { + result = gOriginalMappinCreateCustomPosition(aSystem, aName, aParams, aPositionData); + } + + if (shouldLog) + { + std::ostringstream line; + line << "hook MappinSystem::CreateCustomPosition slot2f0 result"; + AppendPointerWithRva(line, "value", result); + LogRed4ext(line.str()); + } + + return result; +} + void DetourMappinReleaseQuery(void* aSystem, void* aHandle) { if (gMappinReleaseQueryLogCount < 32) @@ -733,26 +1028,41 @@ void InspectAndHookMappinSystem(void* aThis) } gMappinSlotHookAttachAttempted = true; + gMappinUpdateCustomPositionTarget = + *reinterpret_cast(reinterpret_cast(vtable) + kMappinUpdateCustomPositionSlotOffset); gMappinSetTrackedTarget = *reinterpret_cast(reinterpret_cast(vtable) + kMappinSetTrackedSlotOffset); gMappinClearTrackedTarget = *reinterpret_cast(reinterpret_cast(vtable) + kMappinClearTrackedSlotOffset); + gMappinFramePathTarget = + *reinterpret_cast(reinterpret_cast(vtable) + kMappinFramePathSlotOffset); gMappinPositionQueryTarget = *reinterpret_cast(reinterpret_cast(vtable) + kMappinPositionQuerySlotOffset); + gMappinCreateCustomPositionTarget = + *reinterpret_cast(reinterpret_cast(vtable) + kMappinCreateCustomPositionSlotOffset); gMappinReleaseQueryTarget = *reinterpret_cast(reinterpret_cast(vtable) + kMappinReleaseQuerySlotOffset); gMappinActiveRouteTarget = *reinterpret_cast(reinterpret_cast(vtable) + kMappinActiveRouteSlotOffset); + AttachAbsoluteHook("MappinSystem::UpdateCustomPosition slot1f0", gMappinUpdateCustomPositionTarget, + reinterpret_cast(&DetourMappinUpdateCustomPosition), + reinterpret_cast(&gOriginalMappinUpdateCustomPosition)); AttachAbsoluteHook("MappinSystem::SetTracked slot220", gMappinSetTrackedTarget, reinterpret_cast(&DetourMappinSetTracked), reinterpret_cast(&gOriginalMappinSetTracked)); AttachAbsoluteHook("MappinSystem::ClearTracked slot228", gMappinClearTrackedTarget, reinterpret_cast(&DetourMappinClearTracked), reinterpret_cast(&gOriginalMappinClearTracked)); + AttachAbsoluteHook("MappinSystem::FramePath slot280", gMappinFramePathTarget, + reinterpret_cast(&DetourMappinFramePath), + reinterpret_cast(&gOriginalMappinFramePath)); AttachAbsoluteHook("MappinSystem::PositionQuery slot2e0", gMappinPositionQueryTarget, reinterpret_cast(&DetourMappinPositionQuery), reinterpret_cast(&gOriginalMappinPositionQuery)); + AttachAbsoluteHook("MappinSystem::CreateCustomPosition slot2f0", gMappinCreateCustomPositionTarget, + reinterpret_cast(&DetourMappinCreateCustomPosition), + reinterpret_cast(&gOriginalMappinCreateCustomPosition)); AttachAbsoluteHook("MappinSystem::ReleaseQuery slot368", gMappinReleaseQueryTarget, reinterpret_cast(&DetourMappinReleaseQuery), reinterpret_cast(&gOriginalMappinReleaseQuery)); @@ -834,6 +1144,33 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e AttachProbeHook("GPSSystem/Tick", kGpsSystemTickRva, reinterpret_cast(&DetourGpsSystemTick), reinterpret_cast(&gOriginalGpsSystemTick)); + AttachProbeHook("FrameMappinPathWrapper", kFrameMappinPathWrapperRva, + reinterpret_cast(&DetourFrameMappinPathWrapper), + reinterpret_cast(&gOriginalFrameMappinPathWrapper)); + AttachProbeHook("FrameMappinPathCore", kFrameMappinPathCoreRva, + reinterpret_cast(&DetourFrameMappinPathCore), + reinterpret_cast(&gOriginalFrameMappinPathCore)); + AttachProbeHook("SetSelectedMappinWrapper", kSetSelectedMappinWrapperRva, + reinterpret_cast(&DetourSetSelectedMappinWrapper), + reinterpret_cast(&gOriginalSetSelectedMappinWrapper)); + AttachProbeHook("SetSelectedMappinByIdWrapper", kSetSelectedMappinByIdWrapperRva, + reinterpret_cast(&DetourSetSelectedMappinByIdWrapper), + reinterpret_cast(&gOriginalSetSelectedMappinByIdWrapper)); + AttachProbeHook("SetSelectedMappinByPositionWrapper", kSetSelectedMappinByPositionWrapperRva, + reinterpret_cast(&DetourSetSelectedMappinByPositionWrapper), + reinterpret_cast(&gOriginalSetSelectedMappinByPositionWrapper)); + AttachProbeHook("SetSelectedMappinCore", kSetSelectedMappinCoreRva, + reinterpret_cast(&DetourSetSelectedMappinCore), + reinterpret_cast(&gOriginalSetSelectedMappinCore)); + AttachProbeHook("TrackCustomPositionMappinWrapper", kTrackCustomPositionMappinWrapperRva, + reinterpret_cast(&DetourTrackCustomPositionMappinWrapper), + reinterpret_cast(&gOriginalTrackCustomPositionMappinWrapper)); + AttachProbeHook("TrackCustomPositionMappinCore", kTrackCustomPositionMappinCoreRva, + reinterpret_cast(&DetourTrackCustomPositionMappinCore), + reinterpret_cast(&gOriginalTrackCustomPositionMappinCore)); + AttachProbeHook("UntrackCustomPositionMappinWrapper", kUntrackCustomPositionMappinWrapperRva, + reinterpret_cast(&DetourUntrackCustomPositionMappinWrapper), + reinterpret_cast(&gOriginalUntrackCustomPositionMappinWrapper)); AttachProbeHook("TrackMappinWrapper", kTrackMappinWrapperRva, reinterpret_cast(&DetourTrackMappinWrapper), reinterpret_cast(&gOriginalTrackMappinWrapper)); @@ -847,12 +1184,24 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e if (aReason == RED4ext::v1::EMainReason::Unload) { DetachProbeHook("GPSSystem/Tick", kGpsSystemTickRva); + DetachProbeHook("FrameMappinPathWrapper", kFrameMappinPathWrapperRva); + DetachProbeHook("FrameMappinPathCore", kFrameMappinPathCoreRva); + DetachProbeHook("SetSelectedMappinWrapper", kSetSelectedMappinWrapperRva); + DetachProbeHook("SetSelectedMappinByIdWrapper", kSetSelectedMappinByIdWrapperRva); + DetachProbeHook("SetSelectedMappinByPositionWrapper", kSetSelectedMappinByPositionWrapperRva); + DetachProbeHook("SetSelectedMappinCore", kSetSelectedMappinCoreRva); + DetachProbeHook("TrackCustomPositionMappinWrapper", kTrackCustomPositionMappinWrapperRva); + DetachProbeHook("TrackCustomPositionMappinCore", kTrackCustomPositionMappinCoreRva); + DetachProbeHook("UntrackCustomPositionMappinWrapper", kUntrackCustomPositionMappinWrapperRva); DetachProbeHook("TrackMappinWrapper", kTrackMappinWrapperRva); DetachProbeHook("TrackMappinCore", kTrackMappinCoreRva); DetachProbeHook("SetMappinTrackingAlternativeWrapper", kSetMappinTrackingAlternativeWrapperRva); + DetachAbsoluteHook("MappinSystem::UpdateCustomPosition slot1f0", gMappinUpdateCustomPositionTarget); DetachAbsoluteHook("MappinSystem::SetTracked slot220", gMappinSetTrackedTarget); DetachAbsoluteHook("MappinSystem::ClearTracked slot228", gMappinClearTrackedTarget); + DetachAbsoluteHook("MappinSystem::FramePath slot280", gMappinFramePathTarget); DetachAbsoluteHook("MappinSystem::PositionQuery slot2e0", gMappinPositionQueryTarget); + DetachAbsoluteHook("MappinSystem::CreateCustomPosition slot2f0", gMappinCreateCustomPositionTarget); DetachAbsoluteHook("MappinSystem::ReleaseQuery slot368", gMappinReleaseQueryTarget); DetachAbsoluteHook("MappinSystem::ActiveRoute slot3a8", gMappinActiveRouteTarget); }