Files
2077-gps-mod/docs/compaction-handoff.md
T
2026-06-20 21:21:32 -05:00

180 lines
5.7 KiB
Markdown

# Compaction Handoff
Current date/time context: 2026-06-20/21, local timezone America/Chicago.
## Current Installed State
- Latest commit: `64ddf7a Trace GPS provider filters`.
- Installed RED4ext plugin:
`Cyberpunk 2077/red4ext/plugins/EdgeWeightGPS/EdgeWeightGPS.dll`.
- Installed build is read-only. It should not alter route behavior.
- Plugin log is cleared and empty before the next test:
`Cyberpunk 2077/red4ext/plugins/EdgeWeightGPS/EdgeWeightGPS.log`.
- Game is cold as of the latest user message.
## New Toolbox Tools
The Fedora toolbox `2077` now has:
- `rizin` 0.7.4
- `python3-capstone` 5.0.5
- `python3-pefile` 2024.8.26
If adding Python-only tooling, create/use a venv and maintain `requirements.txt`
instead of one-off pip installs.
## Active Probe Configuration
In `red4ext/EdgeWeightGPS/src/Main.cpp`:
- `kEnableGpsProviderClassPatch = false`
- `kEnableGpsProviderClassPatchTrace = false`
- `kEnableGpsTraceHooks = true`
- `kEnableGpsQueryLifecycleHooks = true`
- `kEnableGpsRouteJobLifecycleHooks = false`
- `kEnableGpsLocalSearchHooks = true`
- `kEnableRouteUiTraceHooks = false`
Active hooks:
- query lifecycle:
- `GPSQuerySubmit 0x70a42c`
- `GPSQueryDispatch 0x70a570`
- `GPSQueryResultFetch 0x7094b8`
- `GPSQueryStatus 0xaa5704`
- `GPSSearch 0x44f054`
- `GPSRouteProducer 0x44cc7c`
- `GPSEdgeCost 0x44f838`
- filtered provider filter `0x44ff68`
- base provider filter `0x450b08`
Async route-job hooks (`0x8d17d8`, `0x126b28`, `0x883cd8`,
`0x11f5f60`, `0x818ba8`) are split behind
`kEnableGpsRouteJobLifecycleHooks` and currently disabled to keep the next
run focused on solved route result records plus local search/cost stats.
The filter probe records pass/fail totals by GPS point class and by bits in
`point + 0x10`, tested against provider masks at `+0x108` and `+0x10a`.
## Why This Probe Exists
Data and behavior patches tested so far:
- Traffic `maxSpeed` patches affected NPC freeway speed but not GPS route
choice.
- Lane connection probability patches did not change GPS route choice.
- Global cost-table patch produced weird routing but mostly confirmed we were
near the solver, not a clean highway preference knob.
- Provider class override patches fired correctly but produced no perceptible
route change after preserving vanilla class `14`.
Static disassembly clarified the provider split:
- Provider vtable slot `+0x08` is an admissibility filter, not cost.
- Provider vtable slot `+0x10` is geometric edge cost, multiplying distance by
`provider[0x08 + class * 4]`.
- We patched only slot `+0x10` inputs. If slot `+0x08` filtering dominates the
candidate graph, those cost changes can fire and still not visibly steer GPS.
## Important Native Findings
GPS pipeline landmarks:
- shared query submit: `0x70a42c`
- query dispatch: `0x70a570`
- route producer: `0x44cc7c`
- local search loop: `0x44f054`
- edge cost: `0x44f838`
- query result fetch: `0x7094b8`
The search loop is A*/Dijkstra-like:
- initialize/open list with start node
- pop best node
- check destination handle
- traverse adjacent lane handles
- call provider filter
- call provider cost
- update candidate cost/best predecessor
Provider details:
- Base provider vtable RVA: `0x2ae6120`
- Filtered provider vtable RVA: `0x2ae60f8`
- Base provider constructor `0x451158` fills 64 class multipliers with `1.0`
and sets mask `+0x108` to `0xffff`.
- Filtered provider constructor `0x44b9b4` changes vtable to `0x2ae60f8`.
- Filtered provider commonly has class `14 = 0.05`; preserve this unless
deliberately testing it.
Route result records:
- `0x7094b8` output records are 0x28-byte route segment records.
- `h00` in those records matches `worldTrafficLanePersistent.nodeRefHash`.
- Route records can be joined to `work/raw-segment-json/all.traffic_persistent.json`.
- The low byte of route-record `u08` is not the same as the search point class.
## Next User Test
Ask the user to run the usual routine:
1. Launch game.
2. Hit Continue on main menu.
3. Hit Space to Continue.
4. Wait for minimap/GPS to settle.
5. Open map.
6. Plot the usual three routes plus one custom highway-ish target.
7. Close game.
Ask for timestamps for:
- Space-to-Continue
- map open
- each route click
- game cold
After the run:
1. Archive the log to `logs/EdgeWeightGPS_provider_filter_probe_<time>.log`.
2. Inspect `GPSQuerySubmit`/`GPSQueryResultFetch` lines for tracked route IDs
from submit return RVA `0x8d20d4`, especially successful `0x7094b8`
records with `gpsResult_ptr28_rec40`.
3. Inspect `GPSSearch result` lines for `filterPassClasses`,
`filterFailClasses`, `filterPassMaskBits`, and `filterFailMaskBits`.
4. Compare filter pass/fail classes to `edgeSrcClasses` and route output
records. The key question is whether the class/mask filter is selecting the
graph subset before cost weighting can matter.
## Useful Commands
Build/install:
```bash
toolbox run -c 2077 ./tools/build_red4ext_shim.sh
toolbox run -c 2077 ./tools/install_red4ext_shim.sh
```
Clear plugin log:
```bash
truncate -s 0 '/var/home/salt/.var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/common/Cyberpunk 2077/red4ext/plugins/EdgeWeightGPS/EdgeWeightGPS.log'
```
Inspect current plugin log:
```bash
tail -n 240 '/var/home/salt/.var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/common/Cyberpunk 2077/red4ext/plugins/EdgeWeightGPS/EdgeWeightGPS.log'
```
Disassemble with rizin in toolbox:
```bash
toolbox run -c 2077 rizin -q -A '/var/home/salt/.var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/common/Cyberpunk 2077/bin/x64/Cyberpunk2077.exe'
```
## Caution
- Do not revert user changes or old untracked logs unless explicitly asked.
- Commit early/often.
- Do not install Python packages one by one with pip; use `requirements.txt`.