Add RED4ext release packaging
This commit is contained in:
@@ -4,5 +4,6 @@ __pycache__/
|
|||||||
/work/
|
/work/
|
||||||
/work-*.txt
|
/work-*.txt
|
||||||
/build/
|
/build/
|
||||||
|
/dist/
|
||||||
/vendor/
|
/vendor/
|
||||||
/scratch/
|
/scratch/
|
||||||
|
|||||||
@@ -1,108 +1,137 @@
|
|||||||
# 2077 Edge Weight Mod
|
# EdgeWeightGPS
|
||||||
|
|
||||||
Experimental Cyberpunk 2077 GPS route-weighting mod tooling.
|
Cyberpunk 2077 RED4ext plugin that improves player GPS routing by penalizing
|
||||||
|
short-segment churn in the native GPS solver. The current validated default
|
||||||
|
pushes the GPS toward smoother, higher-momentum driving corridors without
|
||||||
|
globally forcing every route onto highways.
|
||||||
|
|
||||||
## Feasibility
|
## Current Status
|
||||||
|
|
||||||
Cyberpunk exposes a native `gamegpsGPSSystem`, but the current public RTTI dump does
|
Working prototype, validated in-game.
|
||||||
not expose script-callable methods for replacing or overriding the GPS planner. The
|
|
||||||
useful surfaces are generated traffic resources:
|
|
||||||
|
|
||||||
- `worldTrafficPersistentResource.data.lanes`
|
- Route scoring patch: enabled.
|
||||||
- `worldTrafficLanePersistent.length`
|
- Live tuning file: enabled.
|
||||||
- `worldTrafficLanePersistent.maxSpeed`
|
- Current default fixed-edge penalty: `80.0`.
|
||||||
- `worldTrafficLanePersistent.flags`
|
- Highway multiplier: neutral `1.0`; the earlier highway-speed/class
|
||||||
- `worldTrafficLanePersistent.playerGPSInfo`
|
experiments are not part of the playable default.
|
||||||
- `worldTrafficPersistentLaneConnectionsResource.data`
|
|
||||||
- `worldTrafficConnectivityOutLane.exitProbabilityCompressed`
|
|
||||||
- `worldTrafficConnectivityOutLane.isSharpAngle`
|
|
||||||
- `worldTrafficLanePersistentFlags.Highway`
|
|
||||||
- `worldTrafficLanePersistentFlags.GPSOnly`
|
|
||||||
|
|
||||||
The in-game GPS path is computed natively over generated traffic graph data. A
|
The active package is a RED4ext plugin only:
|
||||||
full replacement planner would require native hooks or patching the game
|
|
||||||
executable. A feasible REDmod-style mod has to patch generated graph resources
|
|
||||||
and test which fields the native planner actually consumes.
|
|
||||||
|
|
||||||
## Current Implementation
|
|
||||||
|
|
||||||
Current active work is a RED4ext shim under `red4ext/EdgeWeightGPS`. It has
|
|
||||||
confirmed the world-map GPS route path runs through the native async traffic
|
|
||||||
route pipeline, not the script-facing `RunGPSQuery`/`UpdateGPSQuery` helpers.
|
|
||||||
The shim can log the query lifecycle, async traffic result handoff, and route
|
|
||||||
postprocess stages.
|
|
||||||
|
|
||||||
A later spatial edge-cost prototype hooked the native local GPS edge-cost
|
|
||||||
callback at `0x44f838` and successfully changed thousands of candidate edge
|
|
||||||
costs in live route-producer calls. A controlled in-game inversion test still
|
|
||||||
produced byte-identical final `GPSQueryResultFetch` route records before and
|
|
||||||
after flipping highway weights from nearly free to extremely expensive. Treat
|
|
||||||
that hook as a useful local-search diagnostic, not the final player GPS
|
|
||||||
weighting surface.
|
|
||||||
|
|
||||||
An experimental traffic candidate scorer hook at RVA `0x8d46cc` proved the game
|
|
||||||
does consult traffic lane flags while selecting route/projection candidates:
|
|
||||||
highway, road, and pavement flags were visible live and the hook changed their
|
|
||||||
scores. That detour currently crashes during load, so it is disabled by default
|
|
||||||
in source and disabled in the local game install as `EdgeWeightGPS.dll.disabled`.
|
|
||||||
It should be treated as evidence and an RE lead, not a playable mod.
|
|
||||||
|
|
||||||
The older data-only tooling remains in the repo for reference:
|
|
||||||
|
|
||||||
This repo currently contains WolvenKit-export patchers:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 tools/patch_traffic_lanes.py exported-json-dir patched-json-dir
|
|
||||||
python3 tools/patch_lane_connections.py all.traffic_persistent.json all.lane_connections.json patched.lane_connections.json
|
|
||||||
```
|
|
||||||
|
|
||||||
`patch_traffic_lanes.py` recursively scans WolvenKit JSON exports for `lanes`
|
|
||||||
arrays that look like `worldTrafficLanePersistent` data and applies configurable
|
|
||||||
speed weighting:
|
|
||||||
|
|
||||||
- highways get boosted toward a preferred GPS speed in the game's lane scale
|
|
||||||
- regular roads keep a moderate speed floor
|
|
||||||
- pavement, crosswalk, and disabled traffic lanes are left alone
|
|
||||||
- optional non-highway speed caps can make highways more attractive
|
|
||||||
|
|
||||||
In-game testing disproved `maxSpeed` as the main GPS routing lever: even highway
|
|
||||||
speed `120` did not change GPS routes, although freeway traffic visibly moved
|
|
||||||
faster. Treat speed patches as traffic simulation experiments, not route
|
|
||||||
weighting.
|
|
||||||
|
|
||||||
`patch_lane_connections.py` patches `all.lane_connections` by raising
|
|
||||||
highway-enter/stay edge probabilities and lowering competing non-highway exits.
|
|
||||||
That candidate loaded in game, but live testing did not show a GPS routing
|
|
||||||
change.
|
|
||||||
|
|
||||||
After patching, deserialize the JSON back into CR2W and pack the resulting
|
|
||||||
resources into an archive.
|
|
||||||
|
|
||||||
The toolbox now has WolvenKit CLI installed:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
toolbox run --container 2077 bash -lc '$HOME/.dotnet/tools/cp77tools --help'
|
|
||||||
```
|
|
||||||
|
|
||||||
See [docs/tooling.md](docs/tooling.md) for the end-to-end archive build flow.
|
|
||||||
See [docs/traffic-system-debrief.md](docs/traffic-system-debrief.md) for the
|
|
||||||
detailed feasibility and traffic graph notes.
|
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
A conservative speed archive, an aggressive speed archive, and a connection
|
|
||||||
probability archive were built from the local Flatpak Steam Phantom Liberty
|
|
||||||
install. All `zz_edge` archives are currently disabled in the game folder.
|
|
||||||
|
|
||||||
The RED4ext plugin is also currently disabled for normal play:
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Cyberpunk 2077/red4ext/plugins/EdgeWeightGPS/EdgeWeightGPS.dll.disabled
|
red4ext/plugins/EdgeWeightGPS/EdgeWeightGPS.dll
|
||||||
|
red4ext/plugins/EdgeWeightGPS/momentum_weights.bin
|
||||||
|
red4ext/plugins/EdgeWeightGPS/solver_weights.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## What It Patches
|
||||||
|
|
||||||
|
Reverse engineering found the player GPS route search loop around the native
|
||||||
|
solver relaxation cluster. The useful patch surface is not the script-facing
|
||||||
|
`RunGPSQuery`/`UpdateGPSQuery` helpers and not the generated traffic
|
||||||
|
`maxSpeed` fields. The playable hook patches the two ordinary adjacency
|
||||||
|
expansion sites feeding the native relax/update routine at `0x40ba58`.
|
||||||
|
|
||||||
|
The plugin adds a nonnegative fixed cost to ordinary edge expansion. In
|
||||||
|
practice, this makes many tiny street segments and repeated 90-degree
|
||||||
|
stair-steps less attractive, while still allowing local roads when they are the
|
||||||
|
right path.
|
||||||
|
|
||||||
|
## Validation Summary
|
||||||
|
|
||||||
|
The default `80.0` penalty was selected after live A/B testing:
|
||||||
|
|
||||||
|
- `0.0`: vanilla behavior; visibly stair-stepped in highlighted routes.
|
||||||
|
- `40.0`: partial improvement, but still missed useful smoother corridors.
|
||||||
|
- `80.0`: best observed result; selected smoother high-speed corridors and
|
||||||
|
passed drive testing.
|
||||||
|
- `160.0`: too high; caused bad hairpins/local access and one fallback-style
|
||||||
|
route.
|
||||||
|
|
||||||
|
Drive validation at `80.0`:
|
||||||
|
|
||||||
|
- The Dogtown route used a smoother highway corridor and drove cleanly at high
|
||||||
|
speed.
|
||||||
|
- Live minimap recalculation still worked after a deliberate detour.
|
||||||
|
- Claire/Westbrook route also drove cleanly; one blind hill/ramp surprise was
|
||||||
|
driver unfamiliarity, not a route failure.
|
||||||
|
|
||||||
|
See [docs/gps-momentum-field-tests.md](docs/gps-momentum-field-tests.md) for
|
||||||
|
the detailed test notes, screenshots, and log references.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Build in the Fedora toolbox:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
toolbox run -c 2077 ./tools/build_red4ext_shim.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This writes:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Cyberpunk 2077/archive/pc/mod/zz_edge_weight_gps_highway_probability.archive.disabled
|
build/red4ext/EdgeWeightGPS-mingw64/EdgeWeightGPS.dll
|
||||||
```
|
```
|
||||||
|
|
||||||
Build outputs are ignored by git. Experimental archives and RED4ext DLL builds
|
## Install Locally
|
||||||
should be enabled one at a time and tested from a cold boot.
|
|
||||||
|
Only install while the game is cold.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
toolbox run -c 2077 ./tools/install_red4ext_shim.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The install script builds the DLL, installs it into the Flatpak Steam Cyberpunk
|
||||||
|
2077 folder, and writes the validated defaults:
|
||||||
|
|
||||||
|
- `momentum_weights.bin = 80.0`
|
||||||
|
- `solver_weights.bin = 1.0`
|
||||||
|
|
||||||
|
Override the game directory with `CYBERPUNK2077_GAME_DIR` if needed.
|
||||||
|
|
||||||
|
## Package
|
||||||
|
|
||||||
|
Create a redistributable RED4ext zip:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
toolbox run -c 2077 ./tools/package_red4ext_mod.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The package is written under `dist/` and contains the `red4ext/` folder layout
|
||||||
|
expected by the game.
|
||||||
|
|
||||||
|
## Live Tuning
|
||||||
|
|
||||||
|
`momentum_weights.bin` is a single little-endian float32 and is hot-reloaded
|
||||||
|
every 500 ms while the game is running.
|
||||||
|
|
||||||
|
Useful presets:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 tools/write_momentum_weights.py vanilla # 0.0
|
||||||
|
python3 tools/write_momentum_weights.py default # 80.0
|
||||||
|
python3 tools/write_momentum_weights.py overstrong # 160.0, known too high
|
||||||
|
```
|
||||||
|
|
||||||
|
`solver_weights.bin` is still present for older highway multiplier experiments,
|
||||||
|
but the playable default keeps it neutral:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 tools/write_solver_weights.py vanilla # 1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Repository Notes
|
||||||
|
|
||||||
|
This repository also contains older experiments and reverse-engineering tools:
|
||||||
|
|
||||||
|
- REDmod/archive traffic resource patchers.
|
||||||
|
- Traffic lane and connection probability patchers.
|
||||||
|
- Static disassembly helpers.
|
||||||
|
- RED4ext logging probes.
|
||||||
|
|
||||||
|
Those tools are retained because they explain the route-finding system and
|
||||||
|
document failed approaches, but they are not part of the current playable
|
||||||
|
package. The important debriefs are:
|
||||||
|
|
||||||
|
- [docs/traffic-system-debrief.md](docs/traffic-system-debrief.md)
|
||||||
|
- [docs/red4ext-logging-shim.md](docs/red4ext-logging-shim.md)
|
||||||
|
- [docs/gps-routing-research.md](docs/gps-routing-research.md)
|
||||||
|
|||||||
@@ -21,6 +21,15 @@ Current date/time context: 2026-06-27, local timezone America/Chicago.
|
|||||||
recalculation worked after a detour, and the Claire route drove cleanly aside
|
recalculation worked after a detour, and the Claire route drove cleanly aside
|
||||||
from a driver-unfamiliarity ramp/hill surprise.
|
from a driver-unfamiliarity ramp/hill surprise.
|
||||||
- Updated detailed notes in `docs/gps-momentum-field-tests.md`.
|
- Updated detailed notes in `docs/gps-momentum-field-tests.md`.
|
||||||
|
- The rebuilt source-default-80 DLL was installed while the game was cold at
|
||||||
|
about `04:17` local. Installed defaults were rewritten:
|
||||||
|
`momentum_weights.bin = 80.0`, `solver_weights.bin = 1.0`.
|
||||||
|
- Added release packaging:
|
||||||
|
`toolbox run -c 2077 ./tools/package_red4ext_mod.sh`.
|
||||||
|
Verified package:
|
||||||
|
`dist/EdgeWeightGPS-red4ext-20260627-041942.zip`, containing
|
||||||
|
`red4ext/plugins/EdgeWeightGPS/EdgeWeightGPS.dll`,
|
||||||
|
`momentum_weights.bin = 80.0`, and `solver_weights.bin = 1.0`.
|
||||||
|
|
||||||
## 2026-06-27 Live Momentum Knob Installed
|
## 2026-06-27 Live Momentum Knob Installed
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
EdgeWeightGPS RED4ext package
|
||||||
|
|
||||||
|
Install:
|
||||||
|
Copy the red4ext folder from this package into the Cyberpunk 2077 game folder.
|
||||||
|
The final layout should include:
|
||||||
|
|
||||||
|
Cyberpunk 2077/red4ext/plugins/EdgeWeightGPS/EdgeWeightGPS.dll
|
||||||
|
Cyberpunk 2077/red4ext/plugins/EdgeWeightGPS/momentum_weights.bin
|
||||||
|
Cyberpunk 2077/red4ext/plugins/EdgeWeightGPS/solver_weights.bin
|
||||||
|
|
||||||
|
Default tuning:
|
||||||
|
momentum_weights.bin = 80.0 fixed ordinary-edge penalty
|
||||||
|
solver_weights.bin = 1.0 neutral highway multiplier
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
The plugin changes player GPS route scoring by adding a fixed cost to ordinary
|
||||||
|
edge expansion in the native GPS solver. This favors smoother routes with fewer
|
||||||
|
short-segment stair-steps and was validated in-game on long highway routes,
|
||||||
|
City Center routes, and local Watson/Westbrook routes.
|
||||||
|
|
||||||
|
Tuning:
|
||||||
|
momentum_weights.bin is a single little-endian float32 and is hot-reloaded while
|
||||||
|
the game is running. Set it to 0.0 to disable the fixed-edge penalty. Values
|
||||||
|
around 80.0 are the current validated default. 160.0 was tested and is too high:
|
||||||
|
it can trigger bad hairpins or fallback-style routing.
|
||||||
@@ -8,5 +8,9 @@ plugin_out="$game_dir/red4ext/plugins/EdgeWeightGPS"
|
|||||||
dll_path="$("$repo_root/tools/build_red4ext_shim.sh" | tail -n 1)"
|
dll_path="$("$repo_root/tools/build_red4ext_shim.sh" | tail -n 1)"
|
||||||
mkdir -p "$plugin_out"
|
mkdir -p "$plugin_out"
|
||||||
install -m 0644 "$dll_path" "$plugin_out/EdgeWeightGPS.dll"
|
install -m 0644 "$dll_path" "$plugin_out/EdgeWeightGPS.dll"
|
||||||
|
install -m 0644 "$repo_root/presets/momentum/default.bin" "$plugin_out/momentum_weights.bin"
|
||||||
|
install -m 0644 "$repo_root/presets/solver_weights/vanilla.bin" "$plugin_out/solver_weights.bin"
|
||||||
|
|
||||||
printf 'Installed %s\n' "$plugin_out/EdgeWeightGPS.dll"
|
printf 'Installed %s\n' "$plugin_out/EdgeWeightGPS.dll"
|
||||||
|
printf 'Installed %s\n' "$plugin_out/momentum_weights.bin"
|
||||||
|
printf 'Installed %s\n' "$plugin_out/solver_weights.bin"
|
||||||
|
|||||||
Executable
+24
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
timestamp="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
staging="$repo_root/build/package/EdgeWeightGPS-$timestamp"
|
||||||
|
dist_dir="$repo_root/dist"
|
||||||
|
zip_path="$dist_dir/EdgeWeightGPS-red4ext-$timestamp.zip"
|
||||||
|
|
||||||
|
dll_path="$("$repo_root/tools/build_red4ext_shim.sh" | tail -n 1)"
|
||||||
|
plugin_out="$staging/red4ext/plugins/EdgeWeightGPS"
|
||||||
|
|
||||||
|
mkdir -p "$plugin_out" "$dist_dir"
|
||||||
|
install -m 0644 "$dll_path" "$plugin_out/EdgeWeightGPS.dll"
|
||||||
|
install -m 0644 "$repo_root/presets/momentum/default.bin" "$plugin_out/momentum_weights.bin"
|
||||||
|
install -m 0644 "$repo_root/presets/solver_weights/vanilla.bin" "$plugin_out/solver_weights.bin"
|
||||||
|
install -m 0644 "$repo_root/packaging/EdgeWeightGPS-README.txt" "$plugin_out/README.txt"
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "$staging"
|
||||||
|
python3 -m zipfile -c "$zip_path" red4ext
|
||||||
|
)
|
||||||
|
|
||||||
|
printf '%s\n' "$zip_path"
|
||||||
Reference in New Issue
Block a user