Disable unstable traffic scorer hook

This commit is contained in:
2026-06-26 20:49:47 -05:00
parent eebd857f41
commit d68a8745f0
6 changed files with 287 additions and 14 deletions
+86 -9
View File
@@ -708,13 +708,96 @@ The patch targets the EP1 traffic resource because Phantom Liberty is installed.
On a non-PL install, the basegame archive resource would need to be patched
instead.
## Native Async Traffic Route Pipeline
The later RED4ext probes moved the active lead away from journal/mappin fanout
and into the native async traffic route pipeline.
The useful runtime path is:
```text
GPS query dispatch 0x70a570
traffic request enqueue 0x8d17d8
traffic result take 0x709d5c
route-record conversion 0x44a398
route postprocess 0x44830c
```
`0x8d17d8` enqueues work into the traffic route service. `0x709d5c` later takes
the finished result from the service result table, and `0x44830c` postprocesses
the traffic result into the path object consumed by the game. Route records
captured at this stage matched `worldTrafficLanePersistent.nodeRefHash` values
from `all.traffic_persistent`, which confirms that the displayed/player GPS path
is backed by the traffic lane graph even though `maxSpeed` and connection
probability patches did not affect route choice.
Static disassembly found a small traffic candidate scorer at `0x8d46cc`:
```text
score ~= sqrt(candidate + 0x08)
+ 2 * abs(candidate_z-ish - reference_z-ish)
```
It reads lane flags from `[candidate_lane + 0x88]` and branches on
`query + 0x41`:
- `query41 != 0`: pavement lanes (`0x0008`) get a vanilla `+20.0` penalty.
- `query41 == 0`: road-flagged lanes (`0x0010`) get a vanilla `*1.75`
penalty and caller `0x8d4630` applies an additional geometry normalization.
Only two direct callers reach this scorer:
```text
0x8d4568 -> 0x8d46cc
0x8d466f -> 0x8d46cc
```
Both iterate 0x30-byte candidate records and keep the lowest score. This makes
`0x8d46cc` a bounded candidate/projection selector, not the full city-wide graph
search loop.
An experimental hook multiplied the returned score by lane flag:
- highway: `0.35`
- road: `0.70`
- GPSOnly: `1.35`
- pavement: `2.75`
- other: `1.50`
Live logging proved the hook was attached and the corrected mode check was
active:
```text
pavement query41=1 base=37.854 multiplier=2.750 result=104.099
road query41=1 base=23.986 multiplier=0.700 result=16.790
highway query41=1 base=39.640 multiplier=0.350 result=13.874
```
However, that detour crashed during the load-time GPS warmup. The crash report
was an access violation reading `0x71`, and the crash reproduced until the
RED4ext plugin was disabled. The hook is therefore disabled by default in source
(`kEnableGpsTrafficEdgeWeightPatch = false`) and the local installed DLL is
renamed to `EdgeWeightGPS.dll.disabled`.
The main takeaway is still valuable: traffic lane flags are available in native
route-side code, and `0x8d46cc` is an excellent landmark. It is not yet a safe
playable patch point. The next native work should avoid a full detour of this
hot scorer and instead look for either:
- the broader search/expansion loop that feeds candidates into this selector
- an inline patch around the vanilla constants/branches if the selector proves
sufficient
- a safer result-stage rewrite only if upstream weighting cannot be patched
without desynchronizing the planner and renderer
## Future Improvements
Better versions of this mod could:
- hook the native destination-tracking handoff after the concrete mappin-system
method is identified
- trace the downstream GPS update that consumes the tracked mappin
- identify the broader async traffic route search/expansion loop around the
`0x8d25xx` to `0x8d49xx` cluster
- replace the crashing `0x8d46cc` detour with a narrower inline patch or a
safer caller-side hook
- locate any native or baked edge-cost data not exposed in RTTI
- inspect `GPSOnly` connector lanes if a later native trace proves they are
consumed by the player GPS
@@ -722,9 +805,3 @@ Better versions of this mod could:
- generate a diff report of every changed lane with flags, length, speed, and
graph component
- ship multiple archives only if a data patch is proven to affect routing
The next practical runtime step is no longer broad map/mappin logging. The
installed RED4ext shim now hooks `JournalManager.TrackEntry` directly and dumps
the listener array that native `TrackEntry` calls through. A short route-plotting
run should identify which native listener consumes tracked quest/objective
changes; that listener is the next focused static-disassembly target.