Add live-tunable GPS solver highway weight
This commit is contained in:
+46
-11
@@ -2,6 +2,41 @@
|
||||
|
||||
Current date/time context: 2026-06-26, local timezone America/Chicago.
|
||||
|
||||
## 2026-06-26 Confirmed Solver-Cost Patch
|
||||
|
||||
- We have unequivocally found the player GPS route-cost lever.
|
||||
- The crashing RED4ext detour on `0x40bb40` has been replaced by an inline
|
||||
patch at the road-tail block `0x40bb98`. The patch preserves vanilla
|
||||
`node+0x93` behavior, checks `node+0x88 & 0x4000` for `Highway`, and then
|
||||
multiplies highway lane cost by a tunable float.
|
||||
- This inline patch avoids the register-clobber crash from the C++ detour.
|
||||
Static disassembly showed the optimized caller reusing volatile state after
|
||||
calling the tiny vanilla multiplier helper.
|
||||
- The proof build used highway multiplier `0.35` and visibly changed player
|
||||
map routes. It also caused over-aggressive behavior, including a bad custom
|
||||
pin hairpin around the city-center roundabout, proving the hook is real but
|
||||
that `0.35` is too low.
|
||||
- The vanilla A/B build disabled only the inline multiplier patch and restored
|
||||
obviously different route choices. User confirmed the custom pin returned to
|
||||
the straight city-center roundabout route, while the `0.35` build took the
|
||||
wrong hairpin.
|
||||
- Current installed build enables the inline patch with default highway
|
||||
multiplier `0.80` and polls
|
||||
`red4ext/plugins/EdgeWeightGPS/solver_weights.bin` every 500 ms. The file is
|
||||
exactly one little-endian float32 highway multiplier.
|
||||
- The inline patch is deliberately broad across the vanilla road-tail branch:
|
||||
reaching `0x40bb98` already means vanilla selected road-style modes `0/2/4`,
|
||||
so we do not hard-gate on `solver+0xc4 == 2`. This avoids creating a manual
|
||||
drive/autodrive disparity. Pedestrian mode `1` uses a different vanilla
|
||||
branch and is not changed by this road-tail patch.
|
||||
- Preset writer:
|
||||
`tools/write_solver_weights.py`. Preset binaries live in
|
||||
`presets/solver_weights/`: `vanilla`, `mild`, `default`, `strong`,
|
||||
`proof-highway-cheap`, and `highway-expensive`.
|
||||
- Evidence logs:
|
||||
`logs/EdgeWeightGPS_inline_highway035_changed_routes_1449.log` and
|
||||
`logs/EdgeWeightGPS_vanilla_ab_2120.log`.
|
||||
|
||||
## 2026-06-26 Static Update
|
||||
|
||||
- Installed RED4ext state is safe: the game plugin directory contains
|
||||
@@ -110,19 +145,19 @@ Important caveat:
|
||||
- Older DLLs are preserved disabled as:
|
||||
`Cyberpunk 2077/red4ext/plugins/EdgeWeightGPS/EdgeWeightGPS.dll.disabled`
|
||||
and `EdgeWeightGPS.dd1423b.dll.disabled`.
|
||||
- Source defaults now enable the full async solver multiplier hook:
|
||||
`kEnableGpsMultiplierHooks = true`.
|
||||
- The current behavior patch is deliberately narrow and diagnostic:
|
||||
`DetourGpsNodeMultiplier` hooks native `0x40bb40`, applies only when
|
||||
`job+0xc4 == 2` (driving route mode), reads lane/node flags from
|
||||
`node+0x88`, and multiplies vanilla node edge cost by highway `0.35`,
|
||||
GPSOnly `1.10`, pavement `1.25`, and all other flags `1.0`.
|
||||
- `0x40bb00` auxiliary/reverse multiplier is hooked only for signature logging;
|
||||
it is not patched yet.
|
||||
- Source defaults enable the inline road-tail patch:
|
||||
`kEnableGpsNodeMultiplierInlinePatch = true`.
|
||||
- Source defaults do not enable the old full-function detour:
|
||||
`kEnableGpsMultiplierHooks = false`.
|
||||
- Current behavior patch is the inline `0x40bb98` code-cave patch. It preserves
|
||||
vanilla road cost except for highway lanes, whose cost is multiplied by the
|
||||
current `solver_weights.bin` float. Installed default is `0.80`.
|
||||
- `solver_weights.bin` lives beside the DLL and is hot-polled every 500 ms.
|
||||
- The plugin log was truncated immediately before installing this build.
|
||||
- Latest archived test log:
|
||||
`logs/EdgeWeightGPS_spatial_inversion_no_route_change_1845.log`.
|
||||
- Game is cold as of the latest user message.
|
||||
`logs/EdgeWeightGPS_vanilla_ab_2120.log`.
|
||||
- A cold restart is required after installing a new DLL; changing
|
||||
`solver_weights.bin` after that is hot-reloaded.
|
||||
|
||||
## 2026-06-26 Full Async Solver Findings
|
||||
|
||||
|
||||
@@ -66,12 +66,22 @@ Current behavior:
|
||||
|
||||
Active build note:
|
||||
|
||||
- The currently installed build is disabled on disk:
|
||||
`EdgeWeightGPS.dll.disabled`. There is no active `EdgeWeightGPS.dll` in the
|
||||
game plugin directory.
|
||||
- Source defaults are still read-only for route behavior. They disable provider
|
||||
class multiplier overrides and the spatial edge-cost patch, while keeping GPS
|
||||
query lifecycle tracing available for probe builds.
|
||||
- The currently installed build is active as
|
||||
`red4ext/plugins/EdgeWeightGPS/EdgeWeightGPS.dll`.
|
||||
- Source defaults enable the stable inline solver-cost patch at `0x40bb98`
|
||||
(`kEnableGpsNodeMultiplierInlinePatch = true`) and keep the old full-function
|
||||
`0x40bb40` C++ detour disabled (`kEnableGpsMultiplierHooks = false`).
|
||||
- The inline patch preserves vanilla road cost except for highway lanes in the
|
||||
road-tail branch. Highway lanes are multiplied by the live value in
|
||||
`solver_weights.bin`, defaulting to `0.80`.
|
||||
- The patch is intentionally not hard-gated on `solver+0xc4 == 2`; the vanilla
|
||||
branch already limits it to road-style modes `0/2/4`, which keeps manual
|
||||
drive and autodrive-like callers from diverging while leaving pedestrian mode
|
||||
`1` alone.
|
||||
- `solver_weights.bin` lives beside the DLL and is exactly one little-endian
|
||||
float32. The plugin polls it every 500 ms from the Running game-state update.
|
||||
`tools/write_solver_weights.py` writes the installed file or generates preset
|
||||
binaries under `presets/solver_weights/`.
|
||||
- The async route-job hooks are split behind `kEnableGpsRouteJobLifecycleHooks`
|
||||
and are disabled in the active probe; this keeps the log focused on
|
||||
`0x70a42c` submissions, `0x7094b8` result records, and local
|
||||
|
||||
@@ -980,32 +980,62 @@ the original symptom: the solver is weighted enough to avoid obviously invalid
|
||||
surfaces, but it has no strong reason to stay on highway corridors for long
|
||||
vehicle trips.
|
||||
|
||||
The current RED4ext prototype therefore hooks `0x40bb40` and only changes
|
||||
driving-mode calls (`solver/job + 0xc4 == 2`). It reads flags from
|
||||
`node+0x88`, leaves vanilla results intact for ordinary roads and unknown
|
||||
surfaces, and applies this diagnostic multiplier set:
|
||||
The first RED4ext prototype tried to hook `0x40bb40` as a normal C++ detour.
|
||||
That found the correct function but crashed during load-time GPS warmup because
|
||||
the optimized caller expects the tiny vanilla helper not to disturb volatile
|
||||
register state used immediately afterward.
|
||||
|
||||
The stable prototype now patches inline at the road-tail block `0x40bb98`
|
||||
instead. Reaching that block already means the vanilla function selected one of
|
||||
the road-style modes `0/2/4`; pedestrian mode `1` uses a different branch. The
|
||||
patch preserves vanilla `node+0x93` behavior, checks `node+0x88 & 0x4000`, and
|
||||
applies an extra multiplier only for highway lanes.
|
||||
|
||||
The proof multiplier was:
|
||||
|
||||
```text
|
||||
Highway 0.35
|
||||
GPSOnly 1.10
|
||||
Pavement 1.25
|
||||
Other 1.00
|
||||
```
|
||||
|
||||
`0x40bb00` is currently hooked only for signature logging. If the node
|
||||
multiplier test moves routes but produces weird reverse/turnaround behavior,
|
||||
the next step is to tune or gate the auxiliary multiplier as well.
|
||||
Live A/B testing confirmed this is the decisive world-map route-cost lever.
|
||||
With `0.35`, routes visibly changed and a custom pin around the city-center
|
||||
roundabout took an obviously bad highway/ramp hairpin. With the inline patch
|
||||
disabled, the same route returned to the straight vanilla path through the
|
||||
roundabout.
|
||||
|
||||
The current installed build uses a default highway multiplier of `0.80` and
|
||||
hot-reloads `solver_weights.bin` from the plugin directory. The file is exactly
|
||||
one little-endian float32. `tools/write_solver_weights.py` writes the installed
|
||||
file and can generate named presets:
|
||||
|
||||
```text
|
||||
vanilla 1.00
|
||||
mild 0.90
|
||||
default 0.80
|
||||
strong 0.70
|
||||
proof-highway-cheap 0.35
|
||||
highway-expensive 3.00
|
||||
```
|
||||
|
||||
The patch intentionally does not hard-gate on `solver+0xc4 == 2`, because
|
||||
autodrive-like local vehicle navigation may use another road-style mode. Since
|
||||
the patch lives in the vanilla road-tail branch, it applies to road-style modes
|
||||
`0/2/4` and still leaves pedestrian mode `1` alone.
|
||||
|
||||
`0x40bb00` is not patched yet. If tuned highway weights still produce
|
||||
reverse/turnaround artifacts, inspect or patch that auxiliary multiplier so
|
||||
reverse/special progress branches receive a compatible policy.
|
||||
|
||||
## Future Improvements
|
||||
|
||||
Better versions of this mod could:
|
||||
|
||||
- tune the `0x40bb40` solver multiplier after live A/B testing confirms visible
|
||||
route changes
|
||||
- tune the `0x40bb98` inline highway multiplier from the current `0.80` default
|
||||
using live `solver_weights.bin` presets
|
||||
- inspect and, if needed, patch `0x40bb00` so reverse/special progress branches
|
||||
receive the same road-class policy as forward expansion
|
||||
- add a tiny live-tuning file for the solver multipliers, similar to the earlier
|
||||
`spatial_weights.bin`, once the hook is confirmed stable
|
||||
- extend `solver_weights.bin` beyond one highway float only if GPSOnly/pavement
|
||||
tuning becomes necessary
|
||||
- replace the crashing `0x8d46cc` detour with a narrower inline patch or a
|
||||
safer caller-side hook
|
||||
- decode enough of the `VAND` graph to join navigation points to traffic lane
|
||||
|
||||
Reference in New Issue
Block a user