mirror of
https://github.com/SK8-ENGINE/skate-3-rust-engine.git
synced 2026-10-26 19:47:44 +00:00
Physics: solve the board/skater with retail's 50 constraint iterations
The stock RWMaxIterations (25) is only the Simulation's setup value; TU3 solves with 50 on every gameplay frame. With 25 the constraints converged less: wheels sank ~10x faster at rest, the ollie deck sat ~1 cm low and the jump velocity the pop sound reads was too small (rolling ollie 0.21-0.29 vs retail 0.50), so pops picked the quiet row. Maps validate identically; water traces stay within expectations. See docs/hails-additions/12-solver-iterations.md.
This commit is contained in:
2 files changed
+82
-3
No files matched your search
@@ -18,6 +18,16 @@ use skate_core::{
|
||||
};
|
||||
use skate_data::collections::Collections;
|
||||
|
||||
/// Constraint iterations of the skater's `rw::physics::Simulation` (+176), read by the solver
|
||||
/// stages `82AE30F0` / `82AE27D0` as their loop count. Measured in TU3 (recomp, Aletown,
|
||||
/// board + skater pipeline with 28 joints / 53 drives): 50 on every solve. Setup `82DC2840`
|
||||
/// first copies 25 from the hard-coded config built by `8275DCC8` (`li r27,25`); the value is
|
||||
/// 50 before the first gameplay solve (the later writer is not identified yet). The stock
|
||||
/// `physics/default.RWMaxIterations` is 25, equal to the setup value but not the live one;
|
||||
/// solving with 25 left wheels sinking ~10x faster than retail (-0.012 vs -0.001 m/s at rest)
|
||||
/// and the ollie pop's deck ~1 cm low by its 4th frame (retail-matching with 50).
|
||||
pub(crate) const SIMULATION_ITERATIONS: u32 = 50;
|
||||
|
||||
pub(crate) struct PhysicsSettings {
|
||||
pub step: BoardStepSettings,
|
||||
pub masses: [RetailBodyMassProperties; 7],
|
||||
@@ -88,7 +98,7 @@ impl PhysicsSettings {
|
||||
);
|
||||
let step = BoardStepSettings {
|
||||
simulation,
|
||||
iterations: data.integer("physics", "default", "RWMaxIterations")?,
|
||||
iterations: SIMULATION_ITERATIONS,
|
||||
base_truck_transforms: calculate_truck_transforms(RetailTruckTransformInputs {
|
||||
deck_mid_length: geometry.deck_mid_length,
|
||||
truck_z_position_front: geometry.truck_z_position_front,
|
||||
@@ -105,8 +115,8 @@ impl PhysicsSettings {
|
||||
}),
|
||||
force_point_y_offset: f("physicsdeck", "DeckForceYOffset")?,
|
||||
};
|
||||
if wheel_radius <= 0.0 || mass_factor <= 0.0 || step.iterations == 0 {
|
||||
return Err("Invalid stock board radius, mass factor or solver iterations".into());
|
||||
if wheel_radius <= 0.0 || mass_factor <= 0.0 {
|
||||
return Err("Invalid stock board radius or mass factor".into());
|
||||
}
|
||||
Ok(Self {
|
||||
step,
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# Board solver: 50 constraint iterations (retail live value)
|
||||
|
||||
## Problem
|
||||
|
||||
Ollie pops were too soft. Retail's player audio chooses the pop's loudness row from the
|
||||
skater's jump velocity (audio state +468 = |Air+112| / 2.65, thresholds 0.25 / 0.42). A rolling
|
||||
ollie in retail measures 0.50 at about 4 m/s. Ours measured 0.21–0.29, so every rolling pop used
|
||||
the quiet row. A standing ollie (0.507) was already right.
|
||||
|
||||
## Root cause
|
||||
|
||||
The board/skater solve ran with `physics/default.RWMaxIterations` from the stock collections,
|
||||
which is **25**. Retail's live `rw::physics::Simulation` solves with **50** iterations.
|
||||
|
||||
- The solver stages `82AE30F0` / `82AE27D0` read the Simulation's iteration count (+176) as their
|
||||
loop count.
|
||||
- Setup (`82DC2840`) first copies 25 from a hard-coded config built by `8275DCC8` (`li r27,25`).
|
||||
The value is 50 before the first gameplay solve. The later writer is not identified yet.
|
||||
- `RWMaxIterations` = 25 equals the setup value, not the live one.
|
||||
|
||||
With 25 iterations the constraints don't converge as far each tick, and the effects were
|
||||
measurable:
|
||||
- At rest, wheels sank about 10× faster than retail (−0.012 vs −0.001 m/s).
|
||||
- By the pop's 4th frame the ollie deck was about 1 cm low.
|
||||
- The jump velocity that the audio state reads was lower.
|
||||
|
||||
## Evidence
|
||||
|
||||
- TU3 traces in the static recompilation (reference only, not shipped): hooks on the Simulation
|
||||
setup and the solver entry logged the iteration count on every solve, recorded in Aletown with
|
||||
the board + skater pipeline (28 joints / 53 drives).
|
||||
- Jump velocity after the change: a rolling ollie at 0.35–0.55 (retail 0.50 at ~4 m/s), standing
|
||||
0.56.
|
||||
|
||||
## Change
|
||||
|
||||
`crates/skate-game/src/physics/settings.rs`: `SIMULATION_ITERATIONS = 50` replaces the
|
||||
`RWMaxIterations` read. The "zero iterations" validation goes away with it, since the value is
|
||||
now a constant.
|
||||
|
||||
## Verification
|
||||
|
||||
- `--validate-maps` on every map, 25 vs 50: identical (collision triangles, support drop, grounded
|
||||
ticks, floor gap).
|
||||
- Water drop traces (`water_drop`, ignored test), positions as expected with both counts:
|
||||
- University shallow channel (340.3, 69.94, −294.3): lowest body part 67.996–68.014 on 67.94,
|
||||
board 68.03. Settled mean part speed 0.059 → 0.120 m/s; peak 0.46 → 1.56. The user saw
|
||||
nothing wrong in play.
|
||||
- DownTown Aletown canal (−182.3, 10.93, 465.9): parts 8.3–9.0 vs 8.93, board 8.91, camera
|
||||
11.934. Settled 0.357 → 0.247 m/s.
|
||||
- The differences come only from the iteration count: a build with every other change but 25
|
||||
iterations reproduced the old numbers exactly.
|
||||
- In play (user, 2026-10-02): pops, landings and grinds much closer to retail; nothing wrong seen
|
||||
in a shallow-water wipeout.
|
||||
|
||||
## Open questions
|
||||
|
||||
- `customiser_equipment_reaches_ground_force_and_torque` (ignored test, needs private assets)
|
||||
fails at 50 iterations: "Profile hardness was lost before live straighten torque".
|
||||
- Samples of (side force, deck torque y) for hardness 0 / 0.7 / 1.0:
|
||||
- 25 iterations: (−23.31, −1.114), (−15.15, −1.114), (−11.66, +1.170)
|
||||
- 50 iterations: (−23.31, −1.114), (−15.15, −1.114), (−11.66, −1.114)
|
||||
- Side friction still scales with hardness exactly.
|
||||
- Even at 25, only hardness 1.0 changes the torque. The assertion appears to depend on a branch
|
||||
threshold (82C07000 limits the straighten request by the deck's existing angular velocity) in
|
||||
the test's synthetic one-frame state. This is not proven; the test is unchanged.
|
||||
- The code that raises the count from 25 to 50 is not identified yet.
|
||||
- Pops at 5–8 m/s still use the soft row. Our pushes reach 6–8 m/s where retail reaches about
|
||||
4 m/s. That is a separate physics issue.
|
||||
Reference in new issue
Block a user