8.8 KiB
Compaction Handoff
Current date/time context: 2026-06-20/21, local timezone America/Chicago.
Current Installed State
- Latest installed probe commit:
54f014b Trace full GPS query results. - Installed RED4ext plugin:
Cyberpunk 2077/red4ext/plugins/EdgeWeightGPS/EdgeWeightGPS.dll. - Installed build is read-only. It should not alter route behavior.
- Latest archived test log:
logs/EdgeWeightGPS_query_route_probe_2308.log. - Game is cold as of the latest user message.
New Toolbox Tools
The Fedora toolbox 2077 now has:
rizin0.7.4python3-capstone5.0.5python3-pefile2024.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 = falsekEnableGpsProviderClassPatchTrace = falsekEnableGpsTraceHooks = truekEnableGpsQueryLifecycleHooks = truekEnableGpsRouteJobLifecycleHooks = falsekEnableGpsRouteJobStartTrace = falsekEnableGpsLocalSearchHooks = truekEnableRouteUiTraceHooks = false
Active hooks:
- query lifecycle:
GPSQuerySubmit 0x70a42cGPSQueryDispatch 0x70a570GPSQueryResultFetch 0x7094b8GPSQueryStatus 0xaa5704
GPSSearch 0x44f054GPSRouteProducer 0x44cc7cGPSResolveHandle 0x44e1a8GPSEdgeCost 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
maxSpeedpatches 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
+0x08is an admissibility filter, not cost. - Provider vtable slot
+0x10is geometric edge cost, multiplying distance byprovider[0x08 + class * 4]. - We patched only slot
+0x10inputs. If slot+0x08filtering 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 - packed-handle resolver:
0x44e1a8 - 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
0x451158fills 64 class multipliers with1.0and sets mask+0x108to0xffff. - Filtered provider constructor
0x44b9b4changes vtable to0x2ae60f8. - Filtered provider commonly has class
14 = 0.05; preserve this unless deliberately testing it.
Route result records:
0x7094b8output records are 0x28-byte route segment records.h00in those records matchesworldTrafficLanePersistent.nodeRefHash.- Route records can be joined to
work/raw-segment-json/all.traffic_persistent.json. - The low byte of route-record
u08is not the same as the search point class. - The log's human wall timestamp has a millisecond rollover bug around second
boundaries. Use the
+Nmselapsed field for ordering and durations.
Packed-handle resolver:
0x44e1a8decodes the packed route handle used by the search/materialization side:- low 20 bits: point index
- bits 20..47: segment index
- high bits: generation/check value
- It resolves the handle into a 0x68-byte segment record and a 0x14-byte point
record. The point record's
+0x13 & 0x3fis the search-side class consumed by0x44f838. - The current probe logs selected resolver calls at return RVAs
0x44d26c,0x44d304,0x44d99f,0x44d9cd,0x44db50,0x44db88, and0x44dd92, plus the first 64 successful calls as a guard against a bad static address assumption. Logs are capped at 512 calls. - Each resolver line includes the decoded handle, segment/point pointers,
segment pointer fields
+0x08through+0x38, raw segment bytes, and raw point bytes. The goal is to determine whether the selected-path segment still carries, or points to, the traffic lane hash/resource flags before the final 0x28 route records are emitted.
Latest 23:08 Test Result
The user clicked:
- 23:08 continue on main menu
- 23:30 space to continue
- 23:46 map open
- 23:56 side job
- 24:06 Sinnerman
- 24:14 Claire
- 24:21 custom
- 24:30 Aldecaldo camp
- 24:47 far gig east
- 25:03 Violence
- 25:10 cyberpsycho unfinished highway
Use:
python3 tools/summarize_gps_route_records.py \
--traffic-json work/raw-segment-json/all.traffic_persistent.json \
logs/EdgeWeightGPS_query_route_probe_2308.log
Important result table:
- qid 1: startup/minimap route, 18 records, 50 ms, 1216.5 pavement length.
- qid 2: side job, 12 records, 32 ms, 578.6 pavement length.
- qid 3: Sinnerman, 23 records, 45 ms, 897.4 pavement, 160.4 highway, 89.8 road.
- qid 4: Claire, 18 records, 34 ms, 1216.5 pavement.
- qid 5: custom, 17 records, 44 ms, 1006.3 pavement, 241.0 highway, 38.0 road.
- qid 6: Aldecaldo camp, 80 records, 325 ms, 5853.5 road, 1492.9 highway, 1111.5 pavement, 24.6 gpsonly.
- qid 7: far east gig, 81 records, 144 ms, 5086.2 road, 1523.0 highway, 1111.5 pavement, 24.6 gpsonly.
- qid 8: Violence, 55 records, 97 ms, 1991.5 pavement, 358.5 highway, 86.1 road.
- qid 9: cyberpsycho unfinished highway, 58 records, 147 ms, 2657.4 pavement, 519.0 highway, 113.2 road, 56.7 gpsonly.
All 362 route-record handles matched traffic lane hashes in the extracted resource.
Local search/provider aggregate from this run:
- 159 searches, 4036 provider filter calls, only 3 filter failures.
- Filter pass classes:
3:3114,5:451,15:310,1:116,4:42. - Edge source classes:
3:3244,5:487,15:318,1:117,4:58. - Edge return RVAs:
0x44f457:4033,0x44f629:151,0x8d74d3:30,0x8d76b0:10.
Inference:
- Provider vtable slot
+0x08filtering is almost not pruning these route searches, so it is not the dominant reason class-cost patches failed to visibly steer GPS. - Search-side edge classes are only
{1,3,4,5,15}in this run. Final emitted route-record classes include{0,1,2,3,4,5,7,8,9}and class 7/8/9 are highway-heavy. Therefore final route-recordu08low byte and search pointpoint+0x13class are different domains.
Next Work
- Install the resolver probe and run the usual map route routine.
- Archive the plugin log as
logs/EdgeWeightGPS_resolve_handle_probe_<time>.log. - Compare
GPSResolveHandlehandles/segment bytes against the finalGPSQueryResultFetchroute-recordh00values joined towork/raw-segment-json/all.traffic_persistent.json. - If the resolver's 0x68 segment record or its pointer fields expose
worldTrafficLanePersistent.nodeRefHashor equivalent road/highway flags, use that data insideDetourGpsEdgeCostto weight true resource-side highways/major roads. If not, follow the segment pointer fields statically. - Avoid post-
0x7094b8rewriting unless everything upstream fails; that would likely only change displayed path records and risks desynchronizing instructions from the real planner.
Useful Commands
Build/install:
toolbox run -c 2077 ./tools/build_red4ext_shim.sh
toolbox run -c 2077 ./tools/install_red4ext_shim.sh
Clear plugin log:
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:
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:
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.