diff --git a/crates/skate-game/src/physics/handplant.rs b/crates/skate-game/src/physics/handplant.rs index ac2b3b11..d09f2208 100644 --- a/crates/skate-game/src/physics/handplant.rs +++ b/crates/skate-game/src/physics/handplant.rs @@ -166,6 +166,27 @@ pub(super) fn ground_update( } Ok(()) } + +/// Capture the solved pose before the bail check, rather than comparing this +/// tick's targets against last tick's bodies in HANDPLANT_POSE. +pub(super) fn trace_solved(physics: &GamePhysics, skater: &SkaterRuntime) { + if physics.ticks % 6 != 0 && skater.collision_maximum_error.unwrap_or(0.0) < 0.15 { + return; + } + let root = &skater.animated_skeleton.roots.animation_to_world; + let actual = skater.skeleton.part_transforms(); + let parts = [3, 4, 5, 6, 7, 8, 9, 10]; + let authored = parts.map(|i| point(root, skater.animated_skeleton.record.pose[i][3])); + let targets = parts.map(|i| point(root, skater.skeleton_input.drive_frames[i][3])); + let solved = parts.map(|i| actual[i][3]); + let strengths = parts.map(|i| skater.skeleton_drives.bones[i].as_ref() + .map(|bone| (bone.active, bone.dynamics.strengths))); + let ik = &skater.foot_ik.state.limbs; + let feedback = &skater.collision_feedback; + bevy::log::info!("HANDPLANT_SOLVED tick={} phase={} parts={parts:?} authored={authored:?} targets={targets:?} solved={solved:?} strengths={strengths:?} ik={ik:?} partial={} collision_weight={} pose_errors={:?} anchor={:?}", + physics.ticks, skater.handplant.phase, skater.skeleton_collision.partial_ragdoll, + feedback.drive_weight, skater.pose_errors.parts, skater.handplant.anchor); +} ///Ground82D38430 submits the candidate before82D37F38 consumes its investigation. pub(super) fn ground_query(physics: &GamePhysics, skater: &mut SkaterRuntime) { let p = &skater.player_input.processed; diff --git a/crates/skate-game/src/physics/wipeout.rs b/crates/skate-game/src/physics/wipeout.rs index 54c766c4..0ae44ab3 100644 --- a/crates/skate-game/src/physics/wipeout.rs +++ b/crates/skate-game/src/physics/wipeout.rs @@ -97,6 +97,7 @@ pub(super) fn check_after_physics( PhysicalStateId::FootPlant | PhysicalStateId::HandPlant => { let frame = observations.frame()?; if skater.player_state.current() == PhysicalStateId::HandPlant { + super::handplant::trace_solved(physics, skater); //HandPlant vtable823273CC slot40 ->82D4C530 ->82D90358(false). //FootPlant's82D4C6D8 alone uses82D8FDC0. Its low trick-impact //thresholds must not replace HandPlant's normal air checks. diff --git a/docs/plants.md b/docs/plants.md index 126df3ea..da440fe0 100644 --- a/docs/plants.md +++ b/docs/plants.md @@ -210,3 +210,23 @@ beyond the lip, consistent with the blocked feet and invalid late-entry arc. The port now uses the native component order and standalone sin/cos helpers. Regression tests cover the observed late-entry COM, apex arrival/zero vertical velocity, and zero-angle symmetry. Pose traces remain enabled for verification. + +## Arm and variation investigation (8 September, 17:54 run) + +User reports the normal body animation improved, with one arm misplaced; +A/B variations still bail. In plants-20260908-175441-712-2596.log, HandPlant +requests reason1 (pose displacement) at ticks2209 and5093, without board +contact or closing velocity. The previous HANDPLANT_POSE samples compare +current targets with the previous physical pose and cannot identify the +within-tick source of that displacement. + +HANDPLANT_SOLVED now captures authored, IK-adjusted and solved arm positions +in world coordinates, arm drive strengths, four limb modes/blends, partial +ragdoll state and per-part pose errors before the handplant bail check. It +samples every six ticks, or every tick when maximum pose error reaches0.15. +This is diagnostic only: neither the arm problem nor variation bails are +claimed fixed. Native82D633B0,82BE3220,82BD9728 and82BEDC10 were inspected; +the selected arm, two0.65m clamps and feet-only external post pass match the +existing port. Need another normal/A/B reproduction to locate the divergence. +The same run later terminates in unsupported IsGrindBluntingBackslash at8059; +that separate grind condition remains unresolved by this diagnostic change.