Make GPS solver hook node-only

This commit is contained in:
2026-06-26 22:52:11 -05:00
parent 165bb661f1
commit b56937291f
4 changed files with 190 additions and 39 deletions
@@ -0,0 +1,19 @@
2026-06-27 04:46:36.000 +0ms EdgeWeightGPS Main reason=Load handle=0x6ffff0620000 sdk=0x7f3b4558 runtime=2.3.1
2026-06-27 04:46:36.000 +0ms registered Running game-state callbacks
2026-06-27 04:46:36.008 +8ms hook attach GPSQuerySubmit 0x70a42c target=0x14070a42c rva=0x70a42c result=ok original=0x1018c0480
2026-06-27 04:46:36.015 +15ms hook attach GPSQueryResultFetch 0x7094b8 target=0x1407094b8 rva=0x7094b8 result=ok original=0x1018c04e0
2026-06-27 04:46:36.023 +23ms hook attach GPSAuxMultiplier 0x40bb00 target=0x14040bb00 rva=0x40bb00 result=ok original=0x1018c0540
2026-06-27 04:46:36.030 +30ms hook attach GPSNodeMultiplier 0x40bb40 target=0x14040bb40 rva=0x40bb40 result=ok original=0x1018c05a0
2026-06-27 04:46:54.894 +17894ms GameState Running OnEnter app=0x31fb80
2026-06-27 04:46:54.919 +17919ms GameState Running OnUpdate app=0x31fb80 count=0
2026-06-27 04:46:54.926 +17926ms GameState Running OnUpdate app=0x31fb80 count=1
2026-06-27 04:46:54.933 +17933ms GameState Running OnUpdate app=0x31fb80 count=2
2026-06-27 04:46:54.939 +17939ms GameState Running OnUpdate app=0x31fb80 count=3
2026-06-27 04:46:54.946 +17946ms GameState Running OnUpdate app=0x31fb80 count=4
2026-06-27 04:48:02.702 +85702ms hook GPSQuerySubmit 0x70a42c call=3 manager=0x1a1505df0 query=0x794bfa60 query_f00=0/0x0 query_f04=65535/0xffff query_f08=1077413892/0x40380804 query_f0c=1/0x1 query_fcc=5/0x5 query_pos58=(-1569.68,1213.26,17.3737,0) resolveTraceWindowMs=1200 ret_rva=0x8d20d4
2026-06-27 04:48:02.703 +85703ms hook GPSQuerySubmit result call=3 queryId=3 manager_nextIdD4=4/0x4
2026-06-27 04:48:02.703 +85703ms hook GPSQuerySubmit 0x70a42c call=4 manager=0x1a1505df0 query=0x794bfa60 query_f00=0/0x0 query_f04=65535/0xffff query_f08=2052/0x804 query_f0c=0/0x0 query_fcc=5/0x5 query_pos58=(-1569.68,1213.26,17.3737,0) resolveTraceWindowMs=1200 ret_rva=0x8d20d4
2026-06-27 04:48:02.704 +85704ms hook GPSQuerySubmit result call=4 queryId=4 manager_nextIdD4=5/0x5
2026-06-27 04:48:02.723 +85723ms hook GPSNodeMultiplier 0x40bb40 call=0 signatureCount=1 new=1 job=0x18ced5880 node=0x15a3628de0 mode=2 retry=0 flagsC0=0x8000018 c8=0x0 node86=0x0 flags88=0x31 node8c=0x102 node8e=0x2 node90=0x0 node93=0x1 value=1.1 ret_rva=0x40b35d
2026-06-27 04:48:02.724 +85724ms hook GPSAuxMultiplier 0x40bb00 call=0 signatureCount=1 new=1 job=0x18ced5880 node=0x15a3628de0 mode=2 retry=0 flagsC0=0x8000018 c8=0x0 node86=0x0 flags88=0x31 node8c=0x102 node8e=0x2 node90=0x0 node93=0x1 value=4 ret_rva=0x40b5fc
2026-06-27 04:48:02.724 +85724ms hook GPSAuxMultiplier 0x40bb00 call=1 signatureCount=1 new=1 job=0x18ced5880 node=0x15ecd7ab0 mode=2 retry=0 flagsC0=0x8000018 c8=0x0 node86=0x0 flags88=0x3 node8c=0xc node8e=0x8146 node90=0x45 node93=0x0 value=1 ret_rva=0x40bc4a
@@ -0,0 +1,145 @@
Registered crash info file...
InternalVersion: 3.0.5294808 P4CL: 9778208 Stream: //R6.Root/R6.Release
!!!CRASHED!!!
Error Reason: Unhandled exception
Expression: EXCEPTION_ACCESS_VIOLATION (0xC0000005)
Message: The thread attempted to read inaccessible data at 0x8.
File: <Unknown>
Line: 0
"uptimeSeconds":85
"stopThreadID":444
"exceptionCode":0xC0000005
"processID":384
"Engine/CommitFailedErrorCode@1#TID=0":"0"
"ResourceLoaderThrottler/PreviousSpeed@1957442#TID=0":"Flood"
"ResourceLoaderThrottler/CurrentSpeed@1957443#TID=0":"Stream"
"ResourceLoaderThrottler/NumThrottleTokensAcquired@1965886#TID=0":"1"
"ResourceLoaderThrottler/NumThrottleTokensSoftLimit@1965885#TID=0":"2"
"Gpu/RayTracing/Enabled@256#TID=0":"false"
"Configuration/Name@2#TID=0":"FINAL"
"Configuration/Name2@3#TID=0":"FINAL"
"Game/Patch@7#TID=0":"2.31"
"Game/TransformAnimator/Components@1965278#TID=0":"315"
"Game/TransformAnimator/RunningComponents@1965277#TID=0":"271"
"Game/TransformAnimator/AddedRunningComponents@1965272#TID=0":"0"
"Game/TransformAnimator/RemovedRunningAnimations@1965276#TID=0":"0"
"Game/TransformAnimator/RotatingMeshNodes@1965275#TID=0":"120"
"Game/TransformAnimator/AddedRotatingMeshNodes@1965273#TID=0":"0"
"Game/TransformAnimator/RemovedRotatingMeshNodes@1965274#TID=0":"0"
"Game/SessionDesc/WorldName@734904#TID=0":"03_night_city"
"Game/SessionDesc/IsValid@734905#TID=0":"true"
"Game/SessionDesc/IsLoadingSavedSession@734906#TID=0":"true"
"Game/SessionDesc/IsJoiningRemoteSession@734907#TID=0":"false"
"Game/SessionDesc/HostName@734908#TID=0":""
"Game/SessionDesc/GameRulesConfig@734909#TID=0":"None"
"Game/SessionDesc/SpawnLocalPlayer@734910#TID=0":"false"
"Game/SessionDesc/SpawnPoint@734911#TID=0":"Position=[0, 0, 0, 0] Rotation=[Roll:0, Pitch:0, Yaw:0]"
"Game/SessionDesc/SpawnRecordId@734912#TID=0":"<0x0000001C15982ADF>"
"Game/SessionDesc/Gender@734913#TID=0":"None"
"GameSessionDesc/UseSpecifiedStartPoint@734914#TID=0":"false"
"GameSessionDesc/IsSpectator@734915#TID=0":"false"
"GameSessionDesc/SpawnTags@734916#TID=0":""
"Game/SessionDesc/IsStreamingTestRequested@734917#TID=0":"false"
"Game/SessionDesc/IsBenchmark@734918#TID=0":"false"
"Game/GameEffects/RunningEffects@1965644#TID=0":"1"
"Game/GameEffects/AddedEffects@1965643#TID=0":"0"
"Game/GameEffects/TerminatingEffects@1965645#TID=0":"0"
"Game/Interactions/DialogVisualizerTotalCount@1965587#TID=0":"0"
"Game/Interactions/DeviceVisualizerTotalCount@1965588#TID=0":"0"
"Game/Interactions/LootVisualizerTotalCount@1965589#TID=0":"0"
"Game/Interactions/HotSpots/CurrentCount@1965594#TID=0":"401"
"Game/Interactions/HotSpots/MaxCount@1965595#TID=0":"549"
"Game/Interactions/HotSpots/LastFrameAddedCount@1965590#TID=0":"0"
"Game/Interactions/HotSpots/MaxAddedCount@1965591#TID=0":"586"
"Game/Interactions/HotSpots/LastFrameRemovedCount@1965592#TID=0":"0"
"Game/Interactions/HotSpots/MaxRemovedCount@1965593#TID=0":"153"
"Game/Interactions/UniqueLayersCurrentCount@1965596#TID=0":"3258"
"Game/Interactions/UniqueLayersMaxCount@1965597#TID=0":"4763"
"Game/Interactions/EventsLastFrameCount@1965585#TID=0":"0"
"Game/Interactions/EventsMaxCount@1965586#TID=0":"25"
"Game/PlayerStateMachine/numberOfStateMachines@1876614#TID=0":"10"
"Game/TransactionSystem/NumberOfItemsInPlayersInventory@875005#TID=0":"620"
"Game/TransactionSystem/NumberOfItemsInPlayersStash@1100779#TID=0":"813"
"Game/StatsSystem/NumberOfStatsBundles@1964601#TID=0":"2346"
"Game/StatPoolsSystem/MaxNumberOfStatPoolListenersOnObject@1871770#TID=0":"10"
"Game/StatsSystem/MaxNumberOfStatModifiersOfStatTypeOnObject@1872327#TID=0":"99"
"Game/StatsSystem/NameOfMaxNumberOfStatModifiersOnObjectStatType@1872328#TID=0":"StaminaRatio"
"Game/mounting/MountingFacility/numberOfGameplayMounts@1875653#TID=0":"1"
"Game/mounting/MountingFacility/numberOfMountEvents@1875500#TID=0":"0"
"Game/ItemFactorySystemPool/numberOfPrePooledOwners@875089#TID=0":"1"
"Game/ItemFactorySystemPool/numberOfPrePooledItems@734708#TID=0":"0"
"Game/ItemFactorySystemPool/numberOfPostPooledItems@734706#TID=0":"0"
"Game/ItemFactorySystem/numberOfOwnerDatas@875090#TID=0":"1"
"Game/ItemFactorySystem/numberOfItemsWithNoOwner@734705#TID=0":"0"
"Game/ItemFactorySystem/numberOfCachedOwners@875088#TID=0":"1"
"Game/ItemFactorySystem/numberOfCachedItems@1173764#TID=0":"7"
"Game/ItemFactorySystem/numberOfUncachedOwners@1939940#TID=0":"103"
"Game/ItemFactorySystem/numberOfUncachedItems@1940626#TID=0":"125"
"Game/StatPoolsSystem/MaxNumberOfUnassignedStatPoolListeners@1874750#TID=0":"5221"
"Game/StatsSystem/MaxNumberOfStatsListenersOnObject@1874399#TID=0":"207"
"Game/StatsSystem/MaxNumberOfStatsCallbackData@1866328#TID=0":"267"
"Game/mounting/LowLevelSystem/numberOfAssociations@1875321#TID=0":"14"
"Game/ItemFactorySystemLowLevel/numberOfSpawnRequests@1940627#TID=0":"0"
"Game/ItemFactorySystemLowLevel/numberOfReleaseRequests@1910870#TID=0":"0"
"Game/ItemFactorySystemLowLevel/numberOfCancelRequests@734740#TID=0":"0"
"Game/ItemFactorySystemLowLevel/numberOfAppearanceChangeRequests@1890818#TID=0":"0"
"Game/Population/AlwaysSpawned@1965415#TID=0":"18"
"Game/Population/Attached@1965416#TID=0":"216"
"Game/Population/Registered@1965417#TID=0":"4459"
"Game/Population/InBucket@1965418#TID=0":"996"
"Game/Population/VisQueries@1965419#TID=0":"1992"
"Rendering/AsyncCompute@1965829#TID=0":"true"
"Game/LoadingStage@1957441#TID=0":"Finished"
"Session/GameDefinitionName@734695#TID=0":""
"Engine/OOM@4#TID=0":"false"
"GlobalMode/IsClosing@5#TID=0":"false"
"GlobalMode/IsGame@17#TID=0":"true"
"Jobs/InitParam/MaxLatentJobs@8#TID=0":"131072"
"Jobs/InitParam/MaxCriticalPathJobs@9#TID=0":"65536"
"Jobs/InitParam/MaxImmediateJobs@10#TID=0":"2048"
"Jobs/InitParam/WorkerThreadStackSizeKB@11#TID=0":"1024"
"Jobs/InitParam/MaxThreads@12#TID=0":"27"
"Jobs/InitParam/AllJobsCriticalPath@14#TID=0":"false"
"Jobs/InitParam/UseJobDebugger@13#TID=0":"false"
"Jobs/Dispatcher/NumDispatcherThreads@15#TID=0":"11"
"Jobs/Dispatcher/MaxHWConcurrency@16#TID=0":"12"
"Gpu/Device/Name@251#TID=0":"AMD Radeon RX 7900 XT (RADV NAVI31)"
"Gpu/Device/Vendor@252#TID=0":"AMD"
"Gpu/Device/DriverVersion@253#TID=0":"Radeon software 99.10.2"
"Gpu/Device/TotalMemoryMB@250#TID=0":"20464"
"Gpu/Device/UsedMemoryMB@1965887#TID=0":"5610"
"Engine/SafeInit@46167#TID=0":"Finished"
"Engine/IsHeadless@228#TID=0":"false"
"Engine/VersionWatermark@227#TID=0":"3.0.5294808 P4CL: 9778208 Stream: //R6.Root/R6.Release Aug 27 2025 17:30:27 (FINAL) Total memory: 11931475968 bytes [EP1]"
"Engine/InitParams/InteropStartingPort@213#TID=0":"0"
"Engine/InitParams/RenderPreset@214#TID=0":"1"
"Engine/InitParams/QualityLevelName@215#TID=0":"None"
"Engine/InitParams/TextureQualityLevelName@216#TID=0":"High"
"Engine/InitParams/WatchdogTimeoutSecondsOverride@217#TID=0":"0"
"Engine/InitParams/ScriptsSilentCompilation@218#TID=0":"false"
"Engine/InitParams/ScriptsSilentValidation@219#TID=0":"false"
"Engine/InitParams/TweakDBSilentValidation@220#TID=0":"false"
"Engine/InitParams/PvdDumpToFile@221#TID=0":"false"
"Engine/InitParams/ProfilerEnabled@222#TID=0":"false"
"Engine/InitParams/ShowVersionWatermark@223#TID=0":"true"
"Engine/InitParams/WindowCaption@224#TID=0":""
"Engine/PC/SystemName@225#TID=0":"Windows 10 Pro"
"Engine/PC/SystemVersion@226#TID=0":"10.0.19045"
"Engine/Scripts/PrimaryBlobModifiedDate@235#TID=0":"134020895866810433"
"Engine/Scripts/FallbackBlobModifiedDate@236#TID=0":"0"
"Engine/Scripts/BlobPathUsed@237#TID=0":"Loaded"
"Engine/Scripts/ShouldCompileScripts@233#TID=0":"true"
"Engine/Scripts/CompileScriptsSuccess@234#TID=0":"false"
"Engine/Scripts/Loaded@238#TID=0":"true"
"Telemetry/PlaythroughID@851686#TID=0":"69e857a3ebf988d1"
"Telemetry/VisitID@47432#TID=0":"028374c6-ce86-4670-b93e-6d5f15b4f849"
"Streaming/LastObserverPosition@1965625#TID=0":"[-1569, 1213, 18]"
"Streaming/IsLastObserverPositionValid@1965626#TID=0":"true"
"Streaming/IsTeleporting@1965627#TID=0":"false"
"Streaming/DebugLastTeleportDistance@1965628#TID=0":"0.000000"
"Streaming/MountState@851679#TID=0":"Mounted"
"Streaming/Observer/0/LastObserverPosition@1965622#TID=0":"[-1569, 1213, 18]"
"Streaming/Observer/0/LastObserverVelocityOffsetPosition@1965623#TID=0":"[-1569, 1213, 18]"
"Streaming/Observer/0/UseStreamingOcclusion@1965624#TID=0":"false"
"##CrashDump##/DumpCrashDataSeconds":"0"
@@ -0,0 +1,4 @@
Error reason: Unhandled exception
Expression: EXCEPTION_ACCESS_VIOLATION (0xC0000005)
Message: The thread attempted to read inaccessible data at 0x8.
File: <Unknown>(0)
+22 -39
View File
@@ -100,6 +100,8 @@ constexpr bool kEnableVerboseJournalListenerHooks = false;
constexpr bool kEnableVerboseRouteObserverHooks = false; constexpr bool kEnableVerboseRouteObserverHooks = false;
constexpr bool kEnableVerboseMappinRouteState = false; constexpr bool kEnableVerboseMappinRouteState = false;
constexpr bool kEnableGpsMultiplierHooks = true; constexpr bool kEnableGpsMultiplierHooks = true;
constexpr bool kEnableGpsAuxMultiplierHook = false;
constexpr bool kEnableGpsMultiplierSignatureTrace = false;
constexpr bool kEnableGpsCostTablePatch = false; constexpr bool kEnableGpsCostTablePatch = false;
constexpr bool kEnableGpsProviderClassPatch = false; constexpr bool kEnableGpsProviderClassPatch = false;
constexpr bool kEnableGpsProviderClassPatchTrace = false; constexpr bool kEnableGpsProviderClassPatchTrace = false;
@@ -4859,8 +4861,11 @@ float DetourGpsAuxMultiplier(void* aJob, void* aNode)
result = gOriginalGpsAuxMultiplier(aJob, aNode); result = gOriginalGpsAuxMultiplier(aJob, aNode);
} }
LogGpsMultiplierSignature("GPSAuxMultiplier", kGpsAuxMultiplierRva, true, aJob, aNode, result, if (kEnableGpsMultiplierSignatureTrace)
__builtin_return_address(0)); {
LogGpsMultiplierSignature("GPSAuxMultiplier", kGpsAuxMultiplierRva, true, aJob, aNode, result,
__builtin_return_address(0));
}
return result; return result;
} }
@@ -4872,18 +4877,12 @@ float DetourGpsNodeMultiplier(void* aJob, void* aNode)
result = gOriginalGpsNodeMultiplier(aJob, aNode); result = gOriginalGpsNodeMultiplier(aJob, aNode);
} }
const auto vanillaResult = result;
uint32_t mode = 0; uint32_t mode = 0;
uint32_t retry = 0;
uint16_t nodeFlags = 0; uint16_t nodeFlags = 0;
const auto jobAddress = reinterpret_cast<uintptr_t>(aJob); const auto jobAddress = reinterpret_cast<uintptr_t>(aJob);
const auto nodeAddress = reinterpret_cast<uintptr_t>(aNode); const auto nodeAddress = reinterpret_cast<uintptr_t>(aNode);
const auto hasMode = aJob && TryReadMemory(reinterpret_cast<const void*>(jobAddress + 0xC4), mode); const auto hasMode = aJob && TryReadMemory(reinterpret_cast<const void*>(jobAddress + 0xC4), mode);
const auto hasFlags = aNode && TryReadMemory(reinterpret_cast<const void*>(nodeAddress + 0x88), nodeFlags); const auto hasFlags = aNode && TryReadMemory(reinterpret_cast<const void*>(nodeAddress + 0x88), nodeFlags);
if (aJob)
{
TryReadMemory(reinterpret_cast<const void*>(jobAddress + 0x54), retry);
}
if (hasMode && hasFlags && mode == 2 && std::isfinite(result)) if (hasMode && hasFlags && mode == 2 && std::isfinite(result))
{ {
@@ -4891,36 +4890,14 @@ float DetourGpsNodeMultiplier(void* aJob, void* aNode)
if (patchMultiplier != 1.0f) if (patchMultiplier != 1.0f)
{ {
result *= patchMultiplier; result *= patchMultiplier;
constexpr LONG kMaxLoggedCalls = 96;
LONG callCount = -1;
if (InterlockedCompareExchange(&gGpsSolverNodeWeightPatchLogCount, 0, 0) < kMaxLoggedCalls)
{
callCount = InterlockedIncrement(&gGpsSolverNodeWeightPatchLogCount) - 1;
}
if (callCount >= 0 && callCount < kMaxLoggedCalls)
{
std::ostringstream line;
const auto flags = line.flags();
const auto precision = line.precision();
line << "hook GPSNodeMultiplierPatch 0x" << std::hex << kGpsNodeMultiplierRva << std::dec
<< " call=" << callCount << " category=" << TrafficLaneCategory(nodeFlags)
<< " mode=" << mode << " retry=" << retry << " flags88=0x" << std::hex << nodeFlags
<< std::dec << " vanilla=" << std::fixed << std::setprecision(3) << vanillaResult
<< " multiplier=" << patchMultiplier << " result=" << result;
line.flags(flags);
line.precision(precision);
AppendPointerWithRva(line, "job", aJob);
AppendPointerWithRva(line, "node", aNode);
AppendReturnRva(line, __builtin_return_address(0));
LogRed4ext(line.str());
}
} }
} }
LogGpsMultiplierSignature("GPSNodeMultiplier", kGpsNodeMultiplierRva, false, aJob, aNode, vanillaResult, if (kEnableGpsMultiplierSignatureTrace)
__builtin_return_address(0)); {
LogGpsMultiplierSignature("GPSNodeMultiplier", kGpsNodeMultiplierRva, false, aJob, aNode, result,
__builtin_return_address(0));
}
return result; return result;
} }
@@ -5349,9 +5326,12 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
} }
if (kEnableGpsMultiplierHooks) if (kEnableGpsMultiplierHooks)
{ {
AttachProbeHook("GPSAuxMultiplier 0x40bb00", kGpsAuxMultiplierRva, if (kEnableGpsAuxMultiplierHook)
reinterpret_cast<void*>(&DetourGpsAuxMultiplier), {
reinterpret_cast<void**>(&gOriginalGpsAuxMultiplier)); AttachProbeHook("GPSAuxMultiplier 0x40bb00", kGpsAuxMultiplierRva,
reinterpret_cast<void*>(&DetourGpsAuxMultiplier),
reinterpret_cast<void**>(&gOriginalGpsAuxMultiplier));
}
AttachProbeHook("GPSNodeMultiplier 0x40bb40", kGpsNodeMultiplierRva, AttachProbeHook("GPSNodeMultiplier 0x40bb40", kGpsNodeMultiplierRva,
reinterpret_cast<void*>(&DetourGpsNodeMultiplier), reinterpret_cast<void*>(&DetourGpsNodeMultiplier),
reinterpret_cast<void**>(&gOriginalGpsNodeMultiplier)); reinterpret_cast<void**>(&gOriginalGpsNodeMultiplier));
@@ -5532,7 +5512,10 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
} }
if (kEnableGpsMultiplierHooks) if (kEnableGpsMultiplierHooks)
{ {
DetachProbeHook("GPSAuxMultiplier 0x40bb00", kGpsAuxMultiplierRva); if (kEnableGpsAuxMultiplierHook)
{
DetachProbeHook("GPSAuxMultiplier 0x40bb00", kGpsAuxMultiplierRva);
}
DetachProbeHook("GPSNodeMultiplier 0x40bb40", kGpsNodeMultiplierRva); DetachProbeHook("GPSNodeMultiplier 0x40bb40", kGpsNodeMultiplierRva);
} }
if (kEnableRouteUiTraceHooks) if (kEnableRouteUiTraceHooks)