diff --git a/crates/skate-game/src/physics/skeleton_colliders.rs b/crates/skate-game/src/physics/skeleton_colliders.rs index 4c4c67e2..0798c28c 100644 --- a/crates/skate-game/src/physics/skeleton_colliders.rs +++ b/crates/skate-game/src/physics/skeleton_colliders.rs @@ -16,6 +16,27 @@ use skate_core::{ pub(super) fn world_volumes( skeleton: &SkeletonBody, collision: &SkeletonCollisionMode, +) -> Result, String> { + let mut volumes = enabled_volumes(skeleton, collision)?; + retain_world_volumes(&mut volumes, collision); + Ok(volumes) +} + +/// Volume+84 group4 disables world contacts only. Keep these shapes available +/// to the separate SkaterSkaterCollisionPipeline and its own pair filters. +pub(super) fn retain_world_volumes( + volumes: &mut Vec, + collision: &SkeletonCollisionMode, +) { + volumes.retain(|volume| match volume.body { + CollisionBody::Attached(part) => collision.parts[part].volume_group != 4, + _ => unreachable!("skeleton volumes must reference attached bodies"), + }); +} + +pub(super) fn enabled_volumes( + skeleton: &SkeletonBody, + collision: &SkeletonCollisionMode, ) -> Result, String> { let transforms = skeleton.part_transforms(); let mut volumes = Vec::new(); @@ -29,7 +50,7 @@ pub(super) fn world_volumes( if !state.enabled { continue; } - if state.volume_group != 0 { + if !matches!(state.volume_group, 0 | 4) { return Err(format!( "Skater part{index} requires volume group{} world filtering", state.volume_group diff --git a/crates/skate-game/src/physics/solve.rs b/crates/skate-game/src/physics/solve.rs index 776c55d7..3c47cd7e 100644 --- a/crates/skate-game/src/physics/solve.rs +++ b/crates/skate-game/src/physics/solve.rs @@ -23,7 +23,7 @@ pub(super) fn advance( Vec::new() }; let skeleton_volumes = - skeleton_colliders::world_volumes(&skater.skeleton, &skater.skeleton_collision)?; + skeleton_colliders::enabled_volumes(&skater.skeleton, &skater.skeleton_collision)?; // Each native assembly has its own query record and retention buffer. // Skeleton82BE5094 passes false to82768728: its edge threshold is -1, // whereas the board requests .999. GroundPipeline supplies the remaining @@ -37,8 +37,10 @@ pub(super) fn advance( let skeleton_timer = crate::performance::Scope::new("skeleton_world_contacts"); let mut skeleton_query = physics.query; skeleton_query.edge_cos_bend_normal_threshold = -1.0; + let mut skeleton_world_volumes = skeleton_volumes.clone(); + skeleton_colliders::retain_world_volumes(&mut skeleton_world_volumes, &skater.skeleton_collision); contacts.extend_from_slice(physics.world.query_primitives( - &skeleton_volumes, + &skeleton_world_volumes, skeleton_query, physics.retention, )); diff --git a/docs/plants.md b/docs/plants.md index b37bd0a7..354c70a9 100644 --- a/docs/plants.md +++ b/docs/plants.md @@ -47,6 +47,14 @@ input is released. Those paths already run through `handplant::ground_query` and `ground_update`. The obsolete error and its unused duplicate manager have been removed; input still reaches the stock graphs and handplant selector. +The subsequent normal-map run failed at tick4225 in KnownAir because enabled +foot part15 carried volume group4. This is the existing native +DisableCollisionWithWorld classification, not an unsupported shape. Enabled +group4 shapes now stay in the assembly collision pass but are excluded from +the world query. Re-enabling world collision by restoring group0 takes effect +on the next query. This fixes that explicit exit; the separately logged +off-board world-object query and non-finite-pose failures remain under investigation. + The task executable is a separate copy, built with: ```powershell