From 751e2175f77d5993a6bdac0168a3e184c784e083 Mon Sep 17 00:00:00 2001 From: Jacob Babor Date: Sat, 20 Jun 2026 13:00:35 -0500 Subject: [PATCH] Track GPS query status lifecycle --- docs/red4ext-logging-shim.md | 29 ++- red4ext/EdgeWeightGPS/src/Main.cpp | 333 ++++++++++++++++++++++------- 2 files changed, 283 insertions(+), 79 deletions(-) diff --git a/docs/red4ext-logging-shim.md b/docs/red4ext-logging-shim.md index e15eddc..1640584 100644 --- a/docs/red4ext-logging-shim.md +++ b/docs/red4ext-logging-shim.md @@ -53,9 +53,14 @@ Current behavior: native registration cluster: `0x29bd128` (`RunGPSQuery` body), `0x29bd254` (`UpdateGPSQuery` body), `0x70a42c` (shared query submitter), `0x70a570` (low-level query dispatch), - and `0x7094b8` (query result/path fetch). + `0x7094b8` (query result/path fetch), and `0xaa5704` (query status check). - Logs query endpoints, returned query IDs, shared submitter return RVAs, query - state fields, result-fetch success, and summarized path buffers/point counts. + state fields, status values, result-fetch success, and summarized path + buffers/point counts. +- The active probe now records query IDs returned from `0x70a42c` and always + logs result/status polling for those tracked IDs. Startup polling of query + IDs `0`/`1` is sampled only briefly so it cannot exhaust the route-click log + budget. - Resolves the native mappin system when one of those paths fires, logs relevant vtable slot addresses, and temporarily hooks the route-adjacent slots. @@ -79,7 +84,7 @@ Current route-probe focus: classified as journal metadata) - route-build candidate called by the bridge: `0x5625a4` - GPS query lifecycle: `0x29bd128`, `0x29bd254`, `0x70a42c`, `0x70a570`, - `0x7094b8` + `0x7094b8`, `0xaa5704` Quest/objective pins did not fire the mappin tracking hooks in live tests. The REDscript decompile shows that those pins call `JournalManager.TrackEntry` @@ -134,6 +139,24 @@ Current static lead: so return RVAs and query IDs are important for separating map GPS from traffic or AI path requests. +Latest GPS-query finding: + +- During a controlled route test, the normal world-map GPS path did not call + the script-native `RunGPSQuery`/`UpdateGPSQuery` bodies. +- Each deliberate quest/custom route click called the shared submitter + `0x70a42c` from return RVA `0x8d20d4`, then returned query IDs `3`, `4`, `5`, + and `6` for the three quest routes plus the custom pin. +- Each submitted route produced three `0x70a570` dispatches: current/player + position, a nearby snapped/lane position, then the destination position. +- The dense log stream immediately after Space-to-Continue was repeated + `0x7094b8` result polling for startup query IDs `0`/`1`, matching the HUD / + minimap route initialization delay. The next probe tracks submitted IDs so + route-click completion can be captured without being drowned by startup + polling. +- Static disassembly confirms `0xaa5704` takes `(manager, queryId)` and returns + a small status code; one caller checks for value `1` as the completed-query + state. + Build and install from the Fedora toolbox: ```bash diff --git a/red4ext/EdgeWeightGPS/src/Main.cpp b/red4ext/EdgeWeightGPS/src/Main.cpp index fff5a86..e919d74 100644 --- a/red4ext/EdgeWeightGPS/src/Main.cpp +++ b/red4ext/EdgeWeightGPS/src/Main.cpp @@ -92,6 +92,9 @@ struct Sdk namespace { constexpr uint32_t kGameStateRunning = 2; +constexpr bool kEnableVerboseJournalListenerHooks = false; +constexpr bool kEnableVerboseRouteObserverHooks = false; +constexpr bool kEnableVerboseMappinRouteState = false; constexpr uintptr_t kGpsSystemTickRva = 0x0E6B62C; constexpr uintptr_t kJournalTrackEntryImplRva = 0x05944FC; constexpr uintptr_t kJournalListenerArrayOffset = 0x210; @@ -146,6 +149,7 @@ constexpr uintptr_t kUpdateGpsQueryBodyRva = 0x29BD254; constexpr uintptr_t kGpsQuerySubmitRva = 0x070A42C; constexpr uintptr_t kGpsQueryDispatchRva = 0x070A570; constexpr uintptr_t kGpsQueryResultFetchRva = 0x07094B8; +constexpr uintptr_t kGpsQueryStatusRva = 0x0AA5704; HMODULE gModule = nullptr; std::mutex gLogMutex; @@ -205,6 +209,7 @@ uint32_t gUpdateGpsQueryBodyLogCount = 0; uint32_t gGpsQuerySubmitLogCount = 0; uint32_t gGpsQueryDispatchLogCount = 0; uint32_t gGpsQueryResultFetchLogCount = 0; +uint32_t gGpsQueryStatusLogCount = 0; uint64_t gLogStartTick = 0; uint64_t gLogFrequency = 0; void* gMappinSetTrackedTarget = nullptr; @@ -219,6 +224,21 @@ void* gObserver1ServiceRouteLookupTarget = nullptr; bool gMappinSlotHookAttachAttempted = false; bool gObserver1ServiceRouteLookupHookAttachAttempted = false; +struct TrackedGpsQuery +{ + bool active = false; + uint32_t id = 0; + void* manager = nullptr; + uintptr_t submitReturnRva = 0; + uint32_t submitCall = 0; + uint32_t resultFetchCalls = 0; + uint32_t statusCalls = 0; +}; + +std::mutex gTrackedGpsQueryMutex; +std::array gTrackedGpsQueries{}; +uint32_t gTrackedGpsQueryNext = 0; + using ProbeFunc = void (*)(void* aThis, void* a2, void* a3, void* a4); using JournalTrackEntryFunc = void (*)(void* aThis, void* aEntryHandle); using ScriptNativeVoidFunc = void (*)(void* aThis, void* aStack, void* aResult); @@ -253,6 +273,7 @@ using UpdateGpsQueryBodyFunc = bool (*)(void* aThis, uint32_t aQueryId, void* aO using GpsQuerySubmitFunc = int32_t (*)(void* aManager, void* aQuery); using GpsQueryDispatchFunc = void (*)(void* aRuntimeQuery, void* aTargetPosition, void* aArg3, void* aArg4); using GpsQueryResultFetchFunc = bool (*)(void* aManager, uint32_t aQueryId, void* aOutPath); +using GpsQueryStatusFunc = int32_t (*)(void* aManager, uint32_t aQueryId); ProbeFunc gOriginalGpsSystemTick = nullptr; JournalTrackEntryFunc gOriginalJournalTrackEntry = nullptr; ScriptNativeVoidFunc gOriginalFrameMappinPathWrapper = nullptr; @@ -303,6 +324,7 @@ UpdateGpsQueryBodyFunc gOriginalUpdateGpsQueryBody = nullptr; GpsQuerySubmitFunc gOriginalGpsQuerySubmit = nullptr; GpsQueryDispatchFunc gOriginalGpsQueryDispatch = nullptr; GpsQueryResultFetchFunc gOriginalGpsQueryResultFetch = nullptr; +GpsQueryStatusFunc gOriginalGpsQueryStatus = nullptr; std::filesystem::path GetLogPath() { @@ -390,6 +412,17 @@ bool IsInImage(const void* aPointer) return imageBase && imageEnd && address >= imageBase && address < imageEnd; } +bool TryGetImageRva(const void* aPointer, uintptr_t& aRva) +{ + if (!IsInImage(aPointer)) + { + return false; + } + + aRva = reinterpret_cast(aPointer) - GetImageBase(); + return true; +} + void AppendPointerWithRva(std::ostringstream& aLine, const char* aLabel, const void* aPointer) { aLine << " " << aLabel << "=" << aPointer; @@ -710,6 +743,81 @@ void AppendPathBufferSummary(std::ostringstream& aLine, const char* aPrefix, voi } } +void TrackGpsQuery(uint32_t aQueryId, void* aManager, uintptr_t aSubmitReturnRva, uint32_t aSubmitCall) +{ + if (aQueryId == UINT32_MAX) + { + return; + } + + std::lock_guard lock(gTrackedGpsQueryMutex); + + for (auto& query : gTrackedGpsQueries) + { + if (query.active && query.id == aQueryId && query.manager == aManager) + { + query.submitReturnRva = aSubmitReturnRva; + query.submitCall = aSubmitCall; + return; + } + } + + auto& query = gTrackedGpsQueries[gTrackedGpsQueryNext++ % gTrackedGpsQueries.size()]; + query.active = true; + query.id = aQueryId; + query.manager = aManager; + query.submitReturnRva = aSubmitReturnRva; + query.submitCall = aSubmitCall; + query.resultFetchCalls = 0; + query.statusCalls = 0; +} + +bool NoteTrackedGpsQueryResultFetch(uint32_t aQueryId, void* aManager, TrackedGpsQuery& aSnapshot, + uint32_t& aPerQueryCall) +{ + std::lock_guard lock(gTrackedGpsQueryMutex); + + for (auto& query : gTrackedGpsQueries) + { + if (!query.active || query.id != aQueryId || query.manager != aManager) + { + continue; + } + + aPerQueryCall = query.resultFetchCalls++; + aSnapshot = query; + return true; + } + + return false; +} + +bool NoteTrackedGpsQueryStatus(uint32_t aQueryId, void* aManager, TrackedGpsQuery& aSnapshot, + uint32_t& aPerQueryCall) +{ + std::lock_guard lock(gTrackedGpsQueryMutex); + + for (auto& query : gTrackedGpsQueries) + { + if (!query.active || query.id != aQueryId || query.manager != aManager) + { + continue; + } + + aPerQueryCall = query.statusCalls++; + aSnapshot = query; + return true; + } + + return false; +} + +void AppendTrackedGpsQuery(std::ostringstream& aLine, const TrackedGpsQuery& aQuery) +{ + aLine << " submitCall=" << aQuery.submitCall << " submitRetRva=0x" << std::hex << aQuery.submitReturnRva + << std::dec; +} + void AppendRouteRefFields(std::ostringstream& aLine, const char* aPrefix, void* aRouteRef) { AppendPointerWithRva(aLine, aPrefix, aRouteRef); @@ -730,6 +838,11 @@ void AppendRouteRefFields(std::ostringstream& aLine, const char* aPrefix, void* void LogMappinRouteCollections(const char* aName, uint32_t aCount, void* aSystem) { + if (!kEnableVerboseMappinRouteState) + { + return; + } + if (!aSystem) { return; @@ -1133,7 +1246,6 @@ void DetourJournalTrackEntry(void* aThis, void* aEntryHandle) AppendReturnRva(line, __builtin_return_address(0)); LogRed4ext(line.str()); - LogJournalListeners(callCount, aThis); ++gJournalTrackEntryLogCount; } @@ -1906,6 +2018,10 @@ int32_t DetourGpsQuerySubmit(void* aManager, void* aQuery) { constexpr uint32_t kMaxCalls = 128; + const auto returnAddress = __builtin_return_address(0); + uintptr_t returnRva = 0; + TryGetImageRva(returnAddress, returnRva); + const auto callCount = gGpsQuerySubmitLogCount; const auto shouldLog = callCount < kMaxCalls; if (shouldLog) @@ -1920,7 +2036,7 @@ int32_t DetourGpsQuerySubmit(void* aManager, void* aQuery) AppendUint32Field(line, "query_f0c", aQuery, 0x0C); AppendUint32Field(line, "query_fcc", aQuery, 0xCC); AppendVector4Field(line, "query_pos58", aQuery, 0x58); - AppendReturnRva(line, __builtin_return_address(0)); + AppendReturnRva(line, returnAddress); LogRed4ext(line.str()); ++gGpsQuerySubmitLogCount; } @@ -1931,6 +2047,11 @@ int32_t DetourGpsQuerySubmit(void* aManager, void* aQuery) result = gOriginalGpsQuerySubmit(aManager, aQuery); } + if (result >= 0) + { + TrackGpsQuery(static_cast(result), aManager, returnRva, callCount); + } + if (shouldLog) { std::ostringstream line; @@ -1969,20 +2090,11 @@ void DetourGpsQueryDispatch(void* aRuntimeQuery, void* aTargetPosition, void* aA bool DetourGpsQueryResultFetch(void* aManager, uint32_t aQueryId, void* aOutPath) { - constexpr uint32_t kMaxCalls = 128; + constexpr uint32_t kMaxUntrackedSamples = 32; + constexpr uint32_t kMaxTrackedSamplesPerQuery = 24; - const auto callCount = gGpsQueryResultFetchLogCount; - const auto shouldLog = callCount < kMaxCalls; - if (shouldLog) - { - std::ostringstream line; - line << "hook GPSQueryResultFetch 0x7094b8 call=" << callCount << " queryId=" << aQueryId; - AppendPointerWithRva(line, "manager", aManager); - AppendPointerWithRva(line, "outPath", aOutPath); - AppendReturnRva(line, __builtin_return_address(0)); - LogRed4ext(line.str()); - ++gGpsQueryResultFetchLogCount; - } + const auto callCount = gGpsQueryResultFetchLogCount++; + const auto returnAddress = __builtin_return_address(0); bool result = false; if (gOriginalGpsQueryResultFetch) @@ -1990,10 +2102,25 @@ bool DetourGpsQueryResultFetch(void* aManager, uint32_t aQueryId, void* aOutPath result = gOriginalGpsQueryResultFetch(aManager, aQueryId, aOutPath); } + TrackedGpsQuery trackedQuery{}; + uint32_t perQueryCall = 0; + const auto isTracked = NoteTrackedGpsQueryResultFetch(aQueryId, aManager, trackedQuery, perQueryCall); + const auto shouldLog = (isTracked && (perQueryCall < kMaxTrackedSamplesPerQuery || result)) || + (!isTracked && callCount < kMaxUntrackedSamples && aQueryId < 2); + if (shouldLog) { std::ostringstream line; - line << "hook GPSQueryResultFetch result call=" << callCount << " value=" << static_cast(result); + line << "hook GPSQueryResultFetch 0x7094b8 call=" << callCount << " queryId=" << aQueryId + << " tracked=" << static_cast(isTracked) << " perQueryCall=" << perQueryCall + << " value=" << static_cast(result); + if (isTracked) + { + AppendTrackedGpsQuery(line, trackedQuery); + } + AppendPointerWithRva(line, "manager", aManager); + AppendPointerWithRva(line, "outPath", aOutPath); + AppendReturnRva(line, returnAddress); AppendPathBufferSummary(line, "outPath", aOutPath); LogRed4ext(line.str()); } @@ -2001,6 +2128,44 @@ bool DetourGpsQueryResultFetch(void* aManager, uint32_t aQueryId, void* aOutPath return result; } +int32_t DetourGpsQueryStatus(void* aManager, uint32_t aQueryId) +{ + constexpr uint32_t kMaxUntrackedSamples = 32; + constexpr uint32_t kMaxTrackedSamplesPerQuery = 24; + + const auto callCount = gGpsQueryStatusLogCount++; + const auto returnAddress = __builtin_return_address(0); + + int32_t result = 0; + if (gOriginalGpsQueryStatus) + { + result = gOriginalGpsQueryStatus(aManager, aQueryId); + } + + TrackedGpsQuery trackedQuery{}; + uint32_t perQueryCall = 0; + const auto isTracked = NoteTrackedGpsQueryStatus(aQueryId, aManager, trackedQuery, perQueryCall); + const auto shouldLog = (isTracked && (perQueryCall < kMaxTrackedSamplesPerQuery || result != 0)) || + (!isTracked && callCount < kMaxUntrackedSamples && aQueryId < 2); + + if (shouldLog) + { + std::ostringstream line; + line << "hook GPSQueryStatus 0xaa5704 call=" << callCount << " queryId=" << aQueryId + << " tracked=" << static_cast(isTracked) << " perQueryCall=" << perQueryCall + << " value=" << result; + if (isTracked) + { + AppendTrackedGpsQuery(line, trackedQuery); + } + AppendPointerWithRva(line, "manager", aManager); + AppendReturnRva(line, returnAddress); + LogRed4ext(line.str()); + } + + return result; +} + void AttachProbeHook(const char* aName, uintptr_t aRva, void* aDetour, void** aOriginal) { if (!gSdk || !gSdk->hooking || !gSdk->hooking->Attach) @@ -2324,38 +2489,44 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e AttachProbeHook("GPSQueryResultFetch 0x7094b8", kGpsQueryResultFetchRva, reinterpret_cast(&DetourGpsQueryResultFetch), reinterpret_cast(&gOriginalGpsQueryResultFetch)); + AttachProbeHook("GPSQueryStatus 0xaa5704", kGpsQueryStatusRva, + reinterpret_cast(&DetourGpsQueryStatus), + reinterpret_cast(&gOriginalGpsQueryStatus)); AttachProbeHook("GPSSystem/Tick", kGpsSystemTickRva, reinterpret_cast(&DetourGpsSystemTick), reinterpret_cast(&gOriginalGpsSystemTick)); AttachProbeHook("JournalManager::TrackEntry impl", kJournalTrackEntryImplRva, reinterpret_cast(&DetourJournalTrackEntry), reinterpret_cast(&gOriginalJournalTrackEntry)); - AttachProbeHook("JournalListener::Objective vt28", kJournalListenerObjectiveVt28Rva, - reinterpret_cast(&DetourJournalListenerObjectiveVt28), - reinterpret_cast(&gOriginalJournalListenerObjectiveVt28)); - AttachProbeHook("JournalListener::Objective vt30", kJournalListenerObjectiveVt30Rva, - reinterpret_cast(&DetourJournalListenerObjectiveVt30), - reinterpret_cast(&gOriginalJournalListenerObjectiveVt30)); - AttachProbeHook("JournalListener::Route vt28", kJournalListenerRouteVt28Rva, - reinterpret_cast(&DetourJournalListenerRouteVt28), - reinterpret_cast(&gOriginalJournalListenerRouteVt28)); - AttachProbeHook("JournalListener::Route vt30", kJournalListenerRouteVt30Rva, - reinterpret_cast(&DetourJournalListenerRouteVt30), - reinterpret_cast(&gOriginalJournalListenerRouteVt30)); - AttachProbeHook("JournalListener::RouteAlt vt28", kJournalListenerRouteAltVt28Rva, - reinterpret_cast(&DetourJournalListenerRouteAltVt28), - reinterpret_cast(&gOriginalJournalListenerRouteAltVt28)); - AttachProbeHook("JournalListener::RouteAlt vt30", kJournalListenerRouteAltVt30Rva, - reinterpret_cast(&DetourJournalListenerRouteAltVt30), - reinterpret_cast(&gOriginalJournalListenerRouteAltVt30)); - AttachProbeHook("JournalListener::UI vt28", kJournalListenerUiVt28Rva, - reinterpret_cast(&DetourJournalListenerUiVt28), - reinterpret_cast(&gOriginalJournalListenerUiVt28)); - AttachProbeHook("JournalListener::UI vt30", kJournalListenerUiVt30Rva, - reinterpret_cast(&DetourJournalListenerUiVt30), - reinterpret_cast(&gOriginalJournalListenerUiVt30)); - AttachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva, - reinterpret_cast(&DetourJournalListenerTrackerVt28), - reinterpret_cast(&gOriginalJournalListenerTrackerVt28)); + if (kEnableVerboseJournalListenerHooks) + { + AttachProbeHook("JournalListener::Objective vt28", kJournalListenerObjectiveVt28Rva, + reinterpret_cast(&DetourJournalListenerObjectiveVt28), + reinterpret_cast(&gOriginalJournalListenerObjectiveVt28)); + AttachProbeHook("JournalListener::Objective vt30", kJournalListenerObjectiveVt30Rva, + reinterpret_cast(&DetourJournalListenerObjectiveVt30), + reinterpret_cast(&gOriginalJournalListenerObjectiveVt30)); + AttachProbeHook("JournalListener::Route vt28", kJournalListenerRouteVt28Rva, + reinterpret_cast(&DetourJournalListenerRouteVt28), + reinterpret_cast(&gOriginalJournalListenerRouteVt28)); + AttachProbeHook("JournalListener::Route vt30", kJournalListenerRouteVt30Rva, + reinterpret_cast(&DetourJournalListenerRouteVt30), + reinterpret_cast(&gOriginalJournalListenerRouteVt30)); + AttachProbeHook("JournalListener::RouteAlt vt28", kJournalListenerRouteAltVt28Rva, + reinterpret_cast(&DetourJournalListenerRouteAltVt28), + reinterpret_cast(&gOriginalJournalListenerRouteAltVt28)); + AttachProbeHook("JournalListener::RouteAlt vt30", kJournalListenerRouteAltVt30Rva, + reinterpret_cast(&DetourJournalListenerRouteAltVt30), + reinterpret_cast(&gOriginalJournalListenerRouteAltVt30)); + AttachProbeHook("JournalListener::UI vt28", kJournalListenerUiVt28Rva, + reinterpret_cast(&DetourJournalListenerUiVt28), + reinterpret_cast(&gOriginalJournalListenerUiVt28)); + AttachProbeHook("JournalListener::UI vt30", kJournalListenerUiVt30Rva, + reinterpret_cast(&DetourJournalListenerUiVt30), + reinterpret_cast(&gOriginalJournalListenerUiVt30)); + AttachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva, + reinterpret_cast(&DetourJournalListenerTrackerVt28), + reinterpret_cast(&gOriginalJournalListenerTrackerVt28)); + } AttachProbeHook("JournalRouteBridge::Update candidate", kJournalRouteBridgeRva, reinterpret_cast(&DetourJournalRouteBridge), reinterpret_cast(&gOriginalJournalRouteBridge)); @@ -2374,24 +2545,27 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e AttachProbeHook("RouteBuildCandidate 0x5625a4", kRouteBuildCandidateRva, reinterpret_cast(&DetourRouteBuildCandidate), reinterpret_cast(&gOriginalRouteBuildCandidate)); - AttachProbeHook("RouteObserver0::Activate slot48", kRouteObserver0ActivateRva, - reinterpret_cast(&DetourRouteObserver0Activate), - reinterpret_cast(&gOriginalRouteObserver0Activate)); - AttachProbeHook("RouteObserver1::Activate slot48", kRouteObserver1ActivateRva, - reinterpret_cast(&DetourRouteObserver1Activate), - reinterpret_cast(&gOriginalRouteObserver1Activate)); - AttachProbeHook("RouteObserver23::Activate slot48", kRouteObserver23ActivateRva, - reinterpret_cast(&DetourRouteObserver23Activate), - reinterpret_cast(&gOriginalRouteObserver23Activate)); - AttachProbeHook("RouteObserver0::Deactivate slot50", kRouteObserver0DeactivateRva, - reinterpret_cast(&DetourRouteObserver0Deactivate), - reinterpret_cast(&gOriginalRouteObserver0Deactivate)); - AttachProbeHook("RouteObserver1::Deactivate slot50", kRouteObserver1DeactivateRva, - reinterpret_cast(&DetourRouteObserver1Deactivate), - reinterpret_cast(&gOriginalRouteObserver1Deactivate)); - AttachProbeHook("RouteObserver23::Deactivate slot50", kRouteObserver23DeactivateRva, - reinterpret_cast(&DetourRouteObserver23Deactivate), - reinterpret_cast(&gOriginalRouteObserver23Deactivate)); + if (kEnableVerboseRouteObserverHooks) + { + AttachProbeHook("RouteObserver0::Activate slot48", kRouteObserver0ActivateRva, + reinterpret_cast(&DetourRouteObserver0Activate), + reinterpret_cast(&gOriginalRouteObserver0Activate)); + AttachProbeHook("RouteObserver1::Activate slot48", kRouteObserver1ActivateRva, + reinterpret_cast(&DetourRouteObserver1Activate), + reinterpret_cast(&gOriginalRouteObserver1Activate)); + AttachProbeHook("RouteObserver23::Activate slot48", kRouteObserver23ActivateRva, + reinterpret_cast(&DetourRouteObserver23Activate), + reinterpret_cast(&gOriginalRouteObserver23Activate)); + AttachProbeHook("RouteObserver0::Deactivate slot50", kRouteObserver0DeactivateRva, + reinterpret_cast(&DetourRouteObserver0Deactivate), + reinterpret_cast(&gOriginalRouteObserver0Deactivate)); + AttachProbeHook("RouteObserver1::Deactivate slot50", kRouteObserver1DeactivateRva, + reinterpret_cast(&DetourRouteObserver1Deactivate), + reinterpret_cast(&gOriginalRouteObserver1Deactivate)); + AttachProbeHook("RouteObserver23::Deactivate slot50", kRouteObserver23DeactivateRva, + reinterpret_cast(&DetourRouteObserver23Deactivate), + reinterpret_cast(&gOriginalRouteObserver23Deactivate)); + } AttachProbeHook("FrameMappinPathWrapper", kFrameMappinPathWrapperRva, reinterpret_cast(&DetourFrameMappinPathWrapper), reinterpret_cast(&gOriginalFrameMappinPathWrapper)); @@ -2436,29 +2610,36 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e DetachProbeHook("GPSQuerySubmit 0x70a42c", kGpsQuerySubmitRva); DetachProbeHook("GPSQueryDispatch 0x70a570", kGpsQueryDispatchRva); DetachProbeHook("GPSQueryResultFetch 0x7094b8", kGpsQueryResultFetchRva); + DetachProbeHook("GPSQueryStatus 0xaa5704", kGpsQueryStatusRva); DetachProbeHook("GPSSystem/Tick", kGpsSystemTickRva); DetachProbeHook("JournalManager::TrackEntry impl", kJournalTrackEntryImplRva); - DetachProbeHook("JournalListener::Objective vt28", kJournalListenerObjectiveVt28Rva); - DetachProbeHook("JournalListener::Objective vt30", kJournalListenerObjectiveVt30Rva); - DetachProbeHook("JournalListener::Route vt28", kJournalListenerRouteVt28Rva); - DetachProbeHook("JournalListener::Route vt30", kJournalListenerRouteVt30Rva); - DetachProbeHook("JournalListener::RouteAlt vt28", kJournalListenerRouteAltVt28Rva); - DetachProbeHook("JournalListener::RouteAlt vt30", kJournalListenerRouteAltVt30Rva); - DetachProbeHook("JournalListener::UI vt28", kJournalListenerUiVt28Rva); - DetachProbeHook("JournalListener::UI vt30", kJournalListenerUiVt30Rva); - DetachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva); + if (kEnableVerboseJournalListenerHooks) + { + DetachProbeHook("JournalListener::Objective vt28", kJournalListenerObjectiveVt28Rva); + DetachProbeHook("JournalListener::Objective vt30", kJournalListenerObjectiveVt30Rva); + DetachProbeHook("JournalListener::Route vt28", kJournalListenerRouteVt28Rva); + DetachProbeHook("JournalListener::Route vt30", kJournalListenerRouteVt30Rva); + DetachProbeHook("JournalListener::RouteAlt vt28", kJournalListenerRouteAltVt28Rva); + DetachProbeHook("JournalListener::RouteAlt vt30", kJournalListenerRouteAltVt30Rva); + DetachProbeHook("JournalListener::UI vt28", kJournalListenerUiVt28Rva); + DetachProbeHook("JournalListener::UI vt30", kJournalListenerUiVt30Rva); + DetachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva); + } DetachProbeHook("JournalRouteBridge::Update candidate", kJournalRouteBridgeRva); DetachProbeHook("MappinSystem::RouteEventEnqueue slot240", kMappinRouteEventEnqueueRva); DetachProbeHook("MappinRouteEvent::Handle", kMappinRouteEventHandlerRva); DetachProbeHook("MappinSystem::RouteActivate", kMappinRouteActivateRva); DetachProbeHook("MappinSystem::RouteDeactivate", kMappinRouteDeactivateRva); DetachProbeHook("RouteBuildCandidate 0x5625a4", kRouteBuildCandidateRva); - DetachProbeHook("RouteObserver0::Activate slot48", kRouteObserver0ActivateRva); - DetachProbeHook("RouteObserver1::Activate slot48", kRouteObserver1ActivateRva); - DetachProbeHook("RouteObserver23::Activate slot48", kRouteObserver23ActivateRva); - DetachProbeHook("RouteObserver0::Deactivate slot50", kRouteObserver0DeactivateRva); - DetachProbeHook("RouteObserver1::Deactivate slot50", kRouteObserver1DeactivateRva); - DetachProbeHook("RouteObserver23::Deactivate slot50", kRouteObserver23DeactivateRva); + if (kEnableVerboseRouteObserverHooks) + { + DetachProbeHook("RouteObserver0::Activate slot48", kRouteObserver0ActivateRva); + DetachProbeHook("RouteObserver1::Activate slot48", kRouteObserver1ActivateRva); + DetachProbeHook("RouteObserver23::Activate slot48", kRouteObserver23ActivateRva); + DetachProbeHook("RouteObserver0::Deactivate slot50", kRouteObserver0DeactivateRva); + DetachProbeHook("RouteObserver1::Deactivate slot50", kRouteObserver1DeactivateRva); + DetachProbeHook("RouteObserver23::Deactivate slot50", kRouteObserver23DeactivateRva); + } DetachProbeHook("FrameMappinPathWrapper", kFrameMappinPathWrapperRva); DetachProbeHook("FrameMappinPathCore", kFrameMappinPathCoreRva); DetachProbeHook("SetSelectedMappinWrapper", kSetSelectedMappinWrapperRva);