diff --git a/crates/skate-game/src/graph_host/action.rs b/crates/skate-game/src/graph_host/action.rs index b6d07550..433a67db 100644 --- a/crates/skate-game/src/graph_host/action.rs +++ b/crates/skate-game/src/graph_host/action.rs @@ -429,14 +429,6 @@ impl Host for ActionHost { let Some(instance) = self.operation(behavior).cloned() else { return; }; - if matches!(instance.operation, ActionOperation::BoardAdjust) { - // TU3 82BA2EB8 removes both authored axes so the motion filters - // blend back to neutral even when End has no preceding Update. - for name in [instance.config.mg_intent_mag.as_deref(), instance.config.mg_intent_angle.as_deref()].into_iter().flatten() { - self.motion_intents.remove(name); - } - return; - } if matches!(instance.operation, ActionOperation::CreateTrickIntentFromGesture { .. }) { self.trick_handlers[behavior].end(&mut self.motion_intents); return; diff --git a/crates/skate-game/src/tests/action_host.rs b/crates/skate-game/src/tests/action_host.rs index 61bbe8d8..ae67b769 100644 --- a/crates/skate-game/src/tests/action_host.rs +++ b/crates/skate-game/src/tests/action_host.rs @@ -52,62 +52,6 @@ fn gesture_behavior_publishes_and_releases_the_stock_tre_flip_intent() { assert!(host.errors.is_empty(), "{:?}", host.errors); } -#[test] -fn board_adjust_release_returns_filtered_pose_to_neutral() { - use skate_core::animation::intent_filter::{Settings, State}; - - // Stock T_BoardAdjust.xml: release uses blendOut, then exits below 0.4. - let settings = Settings { - starting_value: 0.0, default_value: 0.0, scale: 1.0, - filters: [0; 4], ramp_time: None, - blend_rising: 0.25, blend_falling: 0.25, blend_out: Some(0.08), - clamp_velocity: Some(0.2), clamp_acceleration: Some(0.03), - }; - for direction in ["Left", "Right", "Up", "Down"] { - for mirrored in [false, true] { - let magnitude = format!("{direction}BoardAdjustMag"); - let angle = format!("{direction}BoardAdjustAngle"); - let mut config = parameter("", 0.0); - config.mg_intent = None; - config.mg_intent_mag = Some(magnitude.clone()); - config.mg_intent_angle = Some(angle.clone()); - config.negate_on_mirror = true; - let mut host = ActionHost::new(ActionInstances::new(vec![ActionInstance { - operation: ActionOperation::BoardAdjust, config, parameters: vec![], - }]), OperationRemap { behaviors: vec![0], conditions: vec![], hooks: vec![] }); - host.stance = Some((false, mirrored)); - host.motion_intents.insert("Unrelated", 0.75); - let frame = Frame { dt: 1.0 / 60.0, current: None, last: None, state_times: vec![] }; - for _ in 0..2 { - let mut filters = [State::default(); 2]; - host.action_intents.insert("BoardAdjustMag", 0.9); - host.action_intents.insert("BoardAdjustAngle", 0.8); - Host::begin(&mut host, 0, [0; 6], &frame); - for _ in 0..60 { - Host::update(&mut host, 0, [0; 6], &frame); - for (filter, key) in filters.iter_mut().zip([&magnitude, &angle]) { - filter.update(&settings, host.motion_intents.get(key.as_str()).copied(), frame.dt, (false, mirrored)); - } - } - assert!(filters.iter().all(|filter| filter.value.abs() > 0.7)); - host.action_intents.remove("BoardAdjustMag"); - host.action_intents.remove("BoardAdjustAngle"); - // Graph exits directly on release: no final Update callback. - Host::end(&mut host, 0, [0; 6], &frame); - for _ in 0..120 { - for (filter, key) in filters.iter_mut().zip([&magnitude, &angle]) { - filter.update(&settings, host.motion_intents.get(key.as_str()).copied(), frame.dt, (false, mirrored)); - } - } - assert!(filters.iter().all(|filter| filter.value.abs() < 0.001), "{direction}, mirrored={mirrored}: {filters:?}"); - assert!(!host.motion_intents.contains_key(magnitude.as_str())); - assert!(!host.motion_intents.contains_key(angle.as_str())); - assert_eq!(host.motion_intents.get("Unrelated"), Some(&0.75)); - } - } - } -} - #[test] fn const_callbacks_publish_then_remove_motion_intent() { let instance = ActionInstance { diff --git a/docs/board-adjust-neutral.md b/docs/board-adjust-neutral.md deleted file mode 100644 index ce89ce0e..00000000 --- a/docs/board-adjust-neutral.md +++ /dev/null @@ -1,25 +0,0 @@ -# Airborne board adjustment release (2026-09-09) - -Releasing the right stick could leave the board held in its adjusted pose without -a grab. `ActionHost::end` only removed the generic `MGIntent`; `BoardAdjust` -instead publishes `MGIntentMag` and `MGIntentAngle`. A graph exit without another -Update left these values present, so the motion filters kept targeting the old -pose. - -TU3 evidence: constructor `82BA2A30` stores the authored magnitude and angle -names at offsets `0x1C` and `0x34`. Vtable `8231E624` selects End `82BA2EB8`, -which gets the actor's motion-intent map and calls removal `82BC1068` for both -names (`82BA2F20`, `82BA2F2C`). The Rust End callback now performs those removals. - -Stock `MotionGraphIncludes/BoardAdjusts/T_BoardAdjust.xml` already filters missing -inputs toward zero using `blendOut=0.08`, acceleration limit `0.03` and velocity -limit `0.2`, and exits to InAir when both absolute filtered values are below -`0.4` and the directional intent is absent. No filter coefficients changed. - -The regression holds the adjustment, ends directly on release with no final -Update, and runs the stock filter settings. It covers all four output names, -mirrored angle signs, reentry, and preservation of unrelated motion intents. -Gameplay appearance remains for user testing; no game was launched. - -Validation: the regression failed before the fix with retained values 0.9/0.8; -all six action-host tests passed after it (release, Windows MSVC, static CRT).