Prototype spatial GPS edge weights
This commit is contained in:
@@ -6,8 +6,8 @@ Current date/time context: 2026-06-26, local timezone America/Chicago.
|
||||
|
||||
- Installed RED4ext state is safe: the game plugin directory contains
|
||||
`EdgeWeightGPS.dll.disabled`, not an active `EdgeWeightGPS.dll`.
|
||||
- Latest committed safe source before this update: `d68a874 Disable unstable
|
||||
traffic scorer hook`.
|
||||
- Latest committed safe source before this update: `55f4087 Document VAND GPS
|
||||
search graph`.
|
||||
- Current source has `kEnableGpsTrafficEdgeWeightPatch = false` and
|
||||
`kEnableGpsLocalSearchHooks = false`.
|
||||
- The real route search is confirmed at `0x44f054`, called from
|
||||
@@ -44,6 +44,42 @@ Current date/time context: 2026-06-26, local timezone America/Chicago.
|
||||
highway/arterial corridors, or patch the navigation VAND graph/classes after
|
||||
extracting the relevant streamingsector resources.
|
||||
|
||||
## 2026-06-26 Spatial Edge-Cost Prototype
|
||||
|
||||
- Added `tools/generate_spatial_edge_grid.py`, which combines
|
||||
`work/raw-segment-json/all.traffic_persistent.json` lane flags with
|
||||
`work/traffic-companions/json/all.lane_polygons.json` polygons.
|
||||
- Generated
|
||||
`red4ext/EdgeWeightGPS/src/GeneratedSpatialRoadGrid.hpp`. The grid is
|
||||
332 x 361 cells at 32 m/cell, origin `(-4640, -7392)`, with final cell
|
||||
counts `H=7574`, `R=19617`, `G=20`, `P=996`, `unknown=91645`.
|
||||
- Added disabled-by-default runtime plumbing behind
|
||||
`kEnableGpsSpatialEdgeWeightPatch = false`. When enabled, it attaches only
|
||||
`GPSRouteProducer 0x44cc7c` and `GPSEdgeCost 0x44f838` unless the old verbose
|
||||
local-search probe is also enabled.
|
||||
- The patch reads search-state vectors as `(world X, height, world Y)`, samples
|
||||
the current endpoint, neighbor endpoint, and midpoint, chooses the strongest
|
||||
spatial road class, then applies a multiplier after native `0x44f838`
|
||||
returns. Current test multipliers are highway `0.62`, road `1.0`,
|
||||
GPS-only `1.20`, pavement `1.35`, unknown `1.05`.
|
||||
- The patch intentionally does not rewrite VAND point class bits. Static
|
||||
materialization code branches on those bits later, so changing them in data is
|
||||
riskier than adjusting cost at the edge-cost vtable slot.
|
||||
- Fixed `DetourGpsEdgeCost` logging: native `0x44f838` indexes the provider
|
||||
cost table by neighbor point class, not source point class.
|
||||
- Build verification passed in the Fedora toolbox:
|
||||
`toolbox run -c 2077 tools/build_red4ext_shim.sh`.
|
||||
- The resulting DLL remains uninstalled. Game install still has only
|
||||
`EdgeWeightGPS.dll.disabled`, not an active plugin DLL.
|
||||
|
||||
Important caveat:
|
||||
|
||||
- Runtime logs show long visible GPS routes are decomposed into many
|
||||
`0x44cc7c` local searches. The `ret_rva=0x70aa22` caller with
|
||||
`query_f78=10` and `query_ptr98_rva=0x8d76c4` mostly produces tiny connector
|
||||
searches, not the whole route. Do not gate the spatial patch only on that
|
||||
caller unless a later test proves it covers the desired route segment.
|
||||
|
||||
## Current Installed State
|
||||
|
||||
- Installed RED4ext plugin is disabled:
|
||||
@@ -76,12 +112,14 @@ In `red4ext/EdgeWeightGPS/src/Main.cpp`:
|
||||
- `kEnableGpsQueryLifecycleHooks = true`
|
||||
- `kEnableGpsRouteJobLifecycleHooks = false`
|
||||
- `kEnableGpsRouteJobStartTrace = false`
|
||||
- `kEnableGpsSpatialEdgeWeightPatch = false`
|
||||
- `kEnableGpsLocalSearchHooks = false`
|
||||
- `kEnableRouteUiTraceHooks = false`
|
||||
|
||||
If rebuilt with the current defaults, active hooks are query/async lifecycle
|
||||
only. The local search/cost hooks below require `kEnableGpsLocalSearchHooks =
|
||||
true`:
|
||||
only. The spatial edge-cost patch requires `kEnableGpsSpatialEdgeWeightPatch =
|
||||
true`. The full local search/cost hooks below require
|
||||
`kEnableGpsLocalSearchHooks = true`:
|
||||
|
||||
- query lifecycle:
|
||||
- `GPSQuerySubmit 0x70a42c`
|
||||
|
||||
@@ -66,14 +66,23 @@ Current behavior:
|
||||
|
||||
Active build note:
|
||||
|
||||
- The currently installed build is read-only. It disables provider class
|
||||
multiplier overrides and enables GPS query lifecycle tracing plus local GPS
|
||||
search tracing.
|
||||
- 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 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
|
||||
search/provider-cost stats.
|
||||
- It hooks `GPSSearch` (`0x44f054`), `GPSRouteProducer` (`0x44cc7c`),
|
||||
- `kEnableGpsSpatialEdgeWeightPatch` is a disabled-by-default implementation
|
||||
path. When enabled, it hooks `GPSRouteProducer` (`0x44cc7c`) and
|
||||
`GPSEdgeCost` (`0x44f838`), samples a generated traffic-lane spatial grid
|
||||
using the search-state coordinates, and applies highway/road/pavement
|
||||
multipliers to returned edge costs.
|
||||
- The old verbose local-search probe is still available behind
|
||||
`kEnableGpsLocalSearchHooks`. It hooks `GPSSearch` (`0x44f054`),
|
||||
`GPSResolveHandle` (`0x44e1a8`), `GPSEdgeCost` (`0x44f838`), and the two
|
||||
cost-provider filters `0x44ff68`/`0x450b08`.
|
||||
- The filter probe records pass/fail counts by point class and by the
|
||||
@@ -345,10 +354,14 @@ Current static producer lead:
|
||||
`(*(routePoint + 0x13) & 0x3f)`. The GPS planner is therefore weighted, but
|
||||
by a compact baked road-class table, not by traffic `maxSpeed` or lane
|
||||
connection probabilities.
|
||||
- The active probe now hooks `0x44f054` and `0x44f838` read-only. It logs the
|
||||
live provider vtable, the 64 class multipliers, start/target handles, and a
|
||||
capped sample of edge-cost calls with point class IDs, masks, handles, and
|
||||
returned costs.
|
||||
- The read-only local-search probe can still hook `0x44f054` and `0x44f838` to
|
||||
log the live provider vtable, the 64 class multipliers, start/target handles,
|
||||
and a capped sample of edge-cost calls with point class IDs, masks, handles,
|
||||
and returned costs.
|
||||
- The new spatial edge-cost path is implemented but disabled by default. Its
|
||||
generated grid is built from traffic lane polygons/flags, not from VAND point
|
||||
classes, so it can bias the search toward highway cells without rewriting
|
||||
VAND metadata that later materialization code branches on.
|
||||
|
||||
Autodrive finding:
|
||||
|
||||
|
||||
@@ -836,18 +836,30 @@ renamed to `EdgeWeightGPS.dll.disabled`.
|
||||
The main takeaway is still valuable, but narrower than first suspected:
|
||||
traffic lane flags are available in native route-side endpoint/candidate code,
|
||||
and `0x8d46cc` is an excellent landmark. It is not the city-wide graph-cost
|
||||
function. The safer cost target is `0x44f838`, or a data patch against the
|
||||
navigation `VAND` blobs it consumes. The next native work should avoid a full
|
||||
detour of `0x8d46cc` and instead look for either:
|
||||
function.
|
||||
|
||||
- a `0x44f838` edge-cost hook that classifies graph edges by spatial proximity
|
||||
to highway/arterial corridors
|
||||
- a navigation streamingsector patch that marks/weights selected `VAND` graph
|
||||
points or edges
|
||||
- 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
|
||||
The current prototype therefore targets `0x44f838` instead. It generates a
|
||||
compact spatial grid from traffic lane polygons/flags and samples that grid
|
||||
from the search-state coordinates passed to the edge-cost callback. The first
|
||||
test multipliers are:
|
||||
|
||||
```text
|
||||
highway 0.62
|
||||
road 1.00
|
||||
GPSOnly 1.20
|
||||
pavement 1.35
|
||||
unknown 1.05
|
||||
```
|
||||
|
||||
This deliberately leaves VAND point class bits untouched. The materialization
|
||||
path branches on those bits after search, so rewriting them in data could alter
|
||||
route construction or instructions as well as cost.
|
||||
|
||||
Runtime logs also show that long visible routes are decomposed into many local
|
||||
`0x44cc7c` route-producer searches. The tempting world-map caller
|
||||
`ret_rva=0x70aa22` mostly produced tiny connector searches in the resolver
|
||||
logs, so the first spatial test should patch edge cost across route-producer
|
||||
calls instead of gating only on that caller.
|
||||
|
||||
## Future Improvements
|
||||
|
||||
@@ -861,8 +873,10 @@ Better versions of this mod could:
|
||||
polygons and highway flags
|
||||
- extract the full Night City navigation streamingsector set into workspace
|
||||
storage and summarize it with `tools/analyze_vand_navigation.py`
|
||||
- implement a bounded `0x44f838` edge-cost hook or `VAND` data patch using that
|
||||
join, rather than traffic `maxSpeed`
|
||||
- tune the generated spatial grid resolution and multipliers after in-game A/B
|
||||
tests
|
||||
- add route-mode gating if the spatial edge-cost hook affects pedestrians,
|
||||
autodrive, or other local navigation too broadly
|
||||
- inspect `GPSOnly` connector lanes if a later native trace proves they are
|
||||
consumed by the player GPS
|
||||
- build district-specific presets if a real data-cost surface is found
|
||||
|
||||
Reference in New Issue
Block a user