diff --git a/red4ext/EdgeWeightGPS/src/Main.cpp b/red4ext/EdgeWeightGPS/src/Main.cpp index 5d49d44..98935db 100644 --- a/red4ext/EdgeWeightGPS/src/Main.cpp +++ b/red4ext/EdgeWeightGPS/src/Main.cpp @@ -101,9 +101,10 @@ constexpr bool kEnableGpsProviderClassPatch = false; constexpr bool kEnableGpsProviderClassPatchTrace = false; constexpr bool kEnableGpsTraceHooks = true; constexpr bool kEnableGpsQueryLifecycleHooks = true; +constexpr bool kEnableGpsAsyncTrafficProbe = true; constexpr bool kEnableGpsRouteJobLifecycleHooks = false; constexpr bool kEnableGpsRouteJobStartTrace = false; -constexpr bool kEnableGpsLocalSearchHooks = true; +constexpr bool kEnableGpsLocalSearchHooks = false; constexpr bool kEnableRouteUiTraceHooks = false; constexpr uintptr_t kGpsSystemTickRva = 0x0E6B62C; constexpr uintptr_t kJournalTrackEntryImplRva = 0x05944FC; @@ -162,6 +163,8 @@ constexpr uintptr_t kGpsQueryResultFetchRva = 0x07094B8; constexpr uintptr_t kGpsQueryStatusRva = 0x0AA5704; constexpr uintptr_t kGpsMapRouteSubmitReturnRva = 0x08D20D4; constexpr uintptr_t kGpsDispatchAdvanceRva = 0x08D17D8; +constexpr uintptr_t kGpsTrafficResultTakeRva = 0x0709D5C; +constexpr uintptr_t kGpsRoutePostprocessRva = 0x044830C; constexpr uintptr_t kGpsAsyncWorkerTickRva = 0x0126B28; constexpr uintptr_t kGpsRouteJobStartRva = 0x0818928; constexpr uintptr_t kGpsRouteJobPollRva = 0x0883CD8; @@ -263,6 +266,8 @@ uint32_t gGpsQueryDispatchLogCount = 0; uint32_t gGpsQueryResultFetchLogCount = 0; uint32_t gGpsQueryStatusLogCount = 0; uint32_t gGpsDispatchAdvanceLogCount = 0; +uint32_t gGpsTrafficResultTakeLogCount = 0; +uint32_t gGpsRoutePostprocessLogCount = 0; uint32_t gGpsAsyncWorkerTickLogCount = 0; uint32_t gGpsRouteJobStartLogCount = 0; uint32_t gGpsRouteJobPollLogCount = 0; @@ -415,6 +420,9 @@ using GpsQueryResultFetchFunc = bool (*)(void* aManager, uint32_t aQueryId, void using GpsQueryStatusFunc = int32_t (*)(void* aManager, uint32_t aQueryId); using GpsDispatchAdvanceFunc = void (*)(void* aRouteSystem, void* aRuntimeQuery, void* aOutTicket, void* aTargetPosition, void* aSourcePosition); +using GpsTrafficResultTakeFunc = void* (*)(void* aTrafficService, void* aOutResult, uint32_t aTicket, + void* aOutMeta); +using GpsRoutePostprocessFunc = void (*)(void* aOutPath, void* aTrafficResult, void* aRouteRecords, float aScale); using GpsAsyncWorkerTickFunc = void (*)(void* aRouteSystem); using GpsRouteJobStartFunc = bool (*)(void* aRouteSystem, void* aActiveEntry, float aDelta, void* aOutLocal); using GpsRouteJobPollFunc = bool (*)(void* aRouteSystem, void* aActiveEntry); @@ -482,6 +490,8 @@ GpsQueryDispatchFunc gOriginalGpsQueryDispatch = nullptr; GpsQueryResultFetchFunc gOriginalGpsQueryResultFetch = nullptr; GpsQueryStatusFunc gOriginalGpsQueryStatus = nullptr; GpsDispatchAdvanceFunc gOriginalGpsDispatchAdvance = nullptr; +GpsTrafficResultTakeFunc gOriginalGpsTrafficResultTake = nullptr; +GpsRoutePostprocessFunc gOriginalGpsRoutePostprocess = nullptr; GpsAsyncWorkerTickFunc gOriginalGpsAsyncWorkerTick = nullptr; GpsRouteJobStartFunc gOriginalGpsRouteJobStart = nullptr; GpsRouteJobPollFunc gOriginalGpsRouteJobPoll = nullptr; @@ -2164,6 +2174,44 @@ void AppendRouteOutputPointerSummary(std::ostringstream& aLine, const char* aPre } } +void AppendTrafficResultSummary(std::ostringstream& aLine, const char* aPrefix, void* aResult) +{ + const auto prefix = std::string(aPrefix); + AppendPointerWithRva(aLine, prefix.c_str(), aResult); + if (!aResult) + { + return; + } + + AppendUint32Field(aLine, (prefix + "_count0c").c_str(), aResult, 0x0C); + AppendPointerField(aLine, (prefix + "_records10").c_str(), aResult, 0x10); + AppendUint32Field(aLine, (prefix + "_u2c").c_str(), aResult, 0x2C); + AppendUint32Field(aLine, (prefix + "_u30").c_str(), aResult, 0x30); + AppendUint32Field(aLine, (prefix + "_u34").c_str(), aResult, 0x34); + + uint32_t count = 0; + auto* records = ReadPointerField(aResult, 0x10); + if (TryReadUint32FieldValue(aResult, 0x0C, count) && records) + { + const auto sampleCount = std::min(count, 4); + AppendBytesPointer(aLine, (prefix + "_records10_raw").c_str(), records, + static_cast(sampleCount) * 0x10); + } +} + +void AppendTrafficResultHolderSummary(std::ostringstream& aLine, const char* aPrefix, void* aOut) +{ + const auto prefix = std::string(aPrefix); + AppendPointerWithRva(aLine, prefix.c_str(), aOut); + if (!aOut) + { + return; + } + + auto* value = ReadPointerField(aOut, 0x00); + AppendTrafficResultSummary(aLine, (prefix + "_value").c_str(), value); +} + void TrackGpsQuery(uint32_t aQueryId, void* aManager, uintptr_t aSubmitReturnRva, uint32_t aSubmitCall) { if (aQueryId == UINT32_MAX) @@ -3642,6 +3690,75 @@ void DetourGpsDispatchAdvance(void* aRouteSystem, void* aRuntimeQuery, void* aOu } } +void* DetourGpsTrafficResultTake(void* aTrafficService, void* aOutResult, uint32_t aTicket, void* aOutMeta) +{ + constexpr uint32_t kMaxCalls = 128; + + const auto callCount = NextGpsAsyncLogCall(gGpsTrafficResultTakeLogCount); + const auto shouldLog = callCount < kMaxCalls; + if (shouldLog) + { + std::ostringstream line; + line << "hook GPSTrafficResultTake 0x709d5c call=" << callCount << " ticket=" << aTicket; + AppendPointerWithRva(line, "trafficService", aTrafficService); + AppendTrafficResultHolderSummary(line, "outResultBefore", aOutResult); + AppendPointerWithRva(line, "outMeta", aOutMeta); + AppendBytesPointer(line, "outMeta_raw10_before", aOutMeta, 0x10); + AppendReturnRva(line, __builtin_return_address(0)); + LogRed4ext(line.str()); + } + + void* result = nullptr; + if (gOriginalGpsTrafficResultTake) + { + result = gOriginalGpsTrafficResultTake(aTrafficService, aOutResult, aTicket, aOutMeta); + } + + if (shouldLog) + { + std::ostringstream line; + line << "hook GPSTrafficResultTake result call=" << callCount; + AppendPointerWithRva(line, "value", result); + AppendTrafficResultHolderSummary(line, "outResultAfter", aOutResult); + AppendPointerWithRva(line, "outMeta", aOutMeta); + AppendBytesPointer(line, "outMeta_raw10_after", aOutMeta, 0x10); + LogRed4ext(line.str()); + } + + return result; +} + +void DetourGpsRoutePostprocess(void* aOutPath, void* aTrafficResult, void* aRouteRecords, float aScale) +{ + constexpr uint32_t kMaxCalls = 128; + + const auto callCount = NextGpsAsyncLogCall(gGpsRoutePostprocessLogCount); + const auto shouldLog = callCount < kMaxCalls; + if (shouldLog) + { + std::ostringstream line; + line << "hook GPSRoutePostprocess 0x44830c call=" << callCount << " scale=" << aScale; + AppendPointerWithRva(line, "outPath", aOutPath); + AppendTrafficResultSummary(line, "trafficResult", aTrafficResult); + AppendPointerWithRva(line, "routeRecords", aRouteRecords); + AppendReturnRva(line, __builtin_return_address(0)); + LogRed4ext(line.str()); + } + + if (gOriginalGpsRoutePostprocess) + { + gOriginalGpsRoutePostprocess(aOutPath, aTrafficResult, aRouteRecords, aScale); + } + + if (shouldLog) + { + std::ostringstream line; + line << "hook GPSRoutePostprocess result call=" << callCount; + AppendGpsResultObjectSummary(line, "outPath", aOutPath); + LogRed4ext(line.str()); + } +} + void DetourGpsAsyncWorkerTick(void* aRouteSystem) { constexpr uint32_t kMaxCalls = 192; @@ -4538,6 +4655,18 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e reinterpret_cast(&DetourGpsQueryStatus), reinterpret_cast(&gOriginalGpsQueryStatus)); } + if (kEnableGpsAsyncTrafficProbe) + { + AttachProbeHook("GPSDispatchAdvance 0x8d17d8", kGpsDispatchAdvanceRva, + reinterpret_cast(&DetourGpsDispatchAdvance), + reinterpret_cast(&gOriginalGpsDispatchAdvance)); + AttachProbeHook("GPSTrafficResultTake 0x709d5c", kGpsTrafficResultTakeRva, + reinterpret_cast(&DetourGpsTrafficResultTake), + reinterpret_cast(&gOriginalGpsTrafficResultTake)); + AttachProbeHook("GPSRoutePostprocess 0x44830c", kGpsRoutePostprocessRva, + reinterpret_cast(&DetourGpsRoutePostprocess), + reinterpret_cast(&gOriginalGpsRoutePostprocess)); + } if (kEnableGpsRouteJobLifecycleHooks) { AttachProbeHook("GPSDispatchAdvance 0x8d17d8", kGpsDispatchAdvanceRva, @@ -4718,6 +4847,12 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e DetachProbeHook("GPSQueryResultFetch 0x7094b8", kGpsQueryResultFetchRva); DetachProbeHook("GPSQueryStatus 0xaa5704", kGpsQueryStatusRva); } + if (kEnableGpsAsyncTrafficProbe) + { + DetachProbeHook("GPSDispatchAdvance 0x8d17d8", kGpsDispatchAdvanceRva); + DetachProbeHook("GPSTrafficResultTake 0x709d5c", kGpsTrafficResultTakeRva); + DetachProbeHook("GPSRoutePostprocess 0x44830c", kGpsRoutePostprocessRva); + } if (kEnableGpsRouteJobLifecycleHooks) { DetachProbeHook("GPSDispatchAdvance 0x8d17d8", kGpsDispatchAdvanceRva);