New in 0.1.2: - Debug color overlay: tint cars by physics state (yellow=frozen, cyan=fast-path, magenta=full-accuracy), individual toggles per state - Exclude locomotives from Physics Optimizer and Auto Freeze - Debug stats line in overlay showing live counts per state - Resync quality 1/16 option added Defaults tuned for new installs: - Resync quality: 1/4 -> 1/8 - Speed threshold: ~0.7 mph -> 0.2 mph - Overlay opacity: 100% -> 75% Rename: Physics Overhaul -> Physics Optimizer throughout
103 lines
6 KiB
Markdown
103 lines
6 KiB
Markdown
# Railroader Physics Optimizer
|
|
|
|
A [Unity Mod Manager](https://www.nexusmods.com/site/mods/21) mod for [Railroader](https://store.steampowered.com/app/1638770/Railroader/) that reduces CPU time spent on train physics without sacrificing gameplay.
|
|
|
|
This mod is **HEAVILY** experimental. Although it should be fully compatible and shouldnt corrupt your save, any use on your existing saves is your own risk and I accept no liability.
|
|
|
|
## Features
|
|
|
|
### Physics Optimizer (LOD fast-path)
|
|
Cars farther than a configurable distance threshold (default 30 m) get a lightweight position update instead of running the full Bezier-curve solver every physics tick. Every few ticks the car resyncs against the full solver to stay numerically correct. The result: far fewer expensive curve evaluations per frame, with limited to no visible difference to gameplay.
|
|
|
|
### Auto Freeze
|
|
Consists that are both slow (< 0.3 m/s) and far from the camera (> 200 m) are skipped entirely by the Verlet integration step. If running the wonderful Stock Optimizer mod please disable this feature and beware that there might be instability.
|
|
|
|
### In-Game Profiler Overlay
|
|
A movable HUD window shows a stacked line chart of frame time over the last 300 physics ticks (~5 seconds). Layers from the bottom up:
|
|
|
|
| Color | Layer |
|
|
|-------|-------|
|
|
| Blue | Render frame time (GPU + CPU render work) |
|
|
| Green | `FixedUpdate` total (all physics) |
|
|
| Yellow | `Tick()` only (Verlet integration) |
|
|
| Orange | `PositionCars` (3D position update) |
|
|
|
|
Reference lines at 16.7 ms (60 fps) and 33.3 ms (30 fps) are always on screen regardless of how well the game is running. Toggle the overlay with `/rpf overlay` or from the UMM settings panel.
|
|
|
|
## Theory of Operation
|
|
|
|
### Why physics is expensive in Railroader
|
|
Each physics tick (`FixedUpdate`), `TrainController` calls `PositionWheelBoundsFront` for every car. This method walks the spline to find the 3D position and orientation for each truck — two expensive distance-to-parameter lookups per car. With long consists on curved track, this dominates frame time.
|
|
|
|
### Physics Optimizer detail
|
|
The mod patches `Car.PositionWheelBoundsFront` with a Harmony prefix. When a car is far from the camera and all its couplers are coupled:
|
|
1. **Track bounds** (`WheelBoundsF`/`R`) are still updated every tick — the constraint solver needs them.
|
|
2. **Truck positions** are computed, but only every N ticks (controlled by `ResyncInterval`). Between resyncs, the car keeps the body rotation from the previous tick.
|
|
3. **`PositionAccuracy`** matches what the full path would use (`High` when visible, `Standard` otherwise) so there is no positional jump when the camera enters the threshold.
|
|
4. **`OnPosition`** is fired so `TrainController.CarDidPosition` runs — this keeps the car-culler bounding sphere, spatial hash, and segment cache current.
|
|
5. **`LocationF`/`LocationR`** are updated each tick so the segment cache never goes stale.
|
|
|
|
### Auto Freeze detail
|
|
`ShouldSkipTick` is replaced. This mod tracks each car individually and skips cars that are far away and *very* slow, reducing wasteful simulation of parked cars.
|
|
|
|
### Sampling model (the "% of FixedUpdate" number)
|
|
The profiler measures time with `Stopwatch.GetTimestamp()` (nanosecond resolution, no GC pressure). It accumulates over 60-tick windows. "% of FixedUpdate" is how much of the total physics budget `Tick()` alone consumed that window — a high percentage means Verlet integration dominates; a low percentage means air brakes, coupler forces, or position updates are the bottleneck.
|
|
|
|
## Installation
|
|
|
|
### Requirements
|
|
- [Unity Mod Manager](https://www.nexusmods.com/site/mods/21) installed and configured for Railroader
|
|
- Railroader (Steam)
|
|
|
|
### Installing with Unity Mod Manager (recommended)
|
|
1. Download the latest release zip.
|
|
2. Open Unity Mod Manager (Ctrl+F10 in game, or the standalone installer).
|
|
3. Drag the zip onto the **Mods** tab, or click **Install Mod** and select the zip.
|
|
4. Launch the game.
|
|
|
|
### Manual installation
|
|
1. Unzip the release into `<Railroader install folder>\Mods\RailroaderPhysicsOverhaul\`.
|
|
2. The folder must contain `Info.json` and `RailroaderPhysicsOverhaul.dll`.
|
|
3. Launch the game.
|
|
|
|
## Console Commands
|
|
|
|
Open the in-game console and type `/rpf <subcommand>`:
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `/rpf help` | List all subcommands |
|
|
| `/rpf overlay` | Toggle the profiler HUD |
|
|
| `/rpf timing` | Print the current timing report to the console |
|
|
| `/rpf dump` | Dump the selected consist's state (cars, speed, coupling, segment) |
|
|
| `/rpf lod <meters>` | Set the LOD distance threshold |
|
|
| `/rpf lod off` | Disable the LOD fast-path entirely |
|
|
| `/rpf freeze` | Freeze the selected consist's physics |
|
|
| `/rpf unfreeze` | Unfreeze the selected consist |
|
|
| `/rpf forceactive` | Toggle ForceActive (bypasses the at-rest check for profiling) |
|
|
|
|
## Settings
|
|
|
|
Open UMM (Ctrl+F10), select **Physics Optimizer**. All settings auto-save on change.
|
|
|
|
| Setting | Default | Description |
|
|
|---------|---------|-------------|
|
|
| Physics Optimizer | On | Enable/disable the LOD fast-path |
|
|
| Distance Threshold | 30 m | Cars beyond this distance use the fast path |
|
|
| Resync Interval | 4 ticks | Full recalculation every N ticks (1 = every tick, no dead-reckoning) |
|
|
| Auto Freeze | On | Enable/disable the individual-consist freeze |
|
|
| Auto Freeze Distance | 200 m | Consists beyond this distance are eligible for freezing |
|
|
| Auto Freeze Speed | 0.3 m/s | Maximum speed for a consist to be considered stopped |
|
|
| Show Overlay | On | Show/hide the profiler HUD on game load |
|
|
| Overlay Opacity | 100% | Profiler window background opacity |
|
|
| Blacklist/Whitelist | Off | Filter specific road numbers in or out of LOD treatment |
|
|
|
|
## Building from Source
|
|
|
|
```
|
|
dotnet build PhysicsOverhaulMod.csproj
|
|
```
|
|
|
|
The build output goes directly to `<Railroader install folder>\Mods\RailroaderPhysicsOverhaul\`. The project references game DLLs relative to the source folder, so it must be placed inside the Railroader game directory.
|
|
|
|
**Prerequisites:** .NET SDK 6 or later, Railroader installed in the same directory tree.
|