Skip to content

Commit

Permalink
Fix Mesh being required
Browse files Browse the repository at this point in the history
  • Loading branch information
Jondolf committed Jul 7, 2024
1 parent d73349f commit d02a9b8
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 85 deletions.
142 changes: 77 additions & 65 deletions src/collision/collider/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,16 +284,16 @@ pub(crate) fn init_colliders<C: AnyCollider>(
/// Panics if the [`ColliderConstructor`] requires a mesh but no mesh handle is found.
fn init_collider_constructors(
mut commands: Commands,
meshes: Res<Assets<Mesh>>,
#[cfg(all(feature = "3d", feature = "collider-from-mesh"))] meshes: Res<Assets<Mesh>>,
#[cfg(all(feature = "3d", feature = "collider-from-mesh"))] mesh_handles: Query<&Handle<Mesh>>,
constructors: Query<(
Entity,
Option<&Handle<Mesh>>,
Option<&Collider>,
Option<&Name>,
&ColliderConstructor,
)>,
) {
for (entity, mesh_handle, existing_collider, name, constructor) in constructors.iter() {
for (entity, existing_collider, name, constructor) in constructors.iter() {
let name = pretty_name(name, entity);
if existing_collider.is_some() {
warn!(
Expand All @@ -303,8 +303,9 @@ fn init_collider_constructors(
commands.entity(entity).remove::<ColliderConstructor>();
continue;
}
#[cfg(all(feature = "3d", feature = "collider-from-mesh"))]
let mesh = if constructor.requires_mesh() {
let mesh_handle = mesh_handle.unwrap_or_else(|| panic!(
let mesh_handle = mesh_handles.get(entity).unwrap_or_else(|_| panic!(
"Tried to add a collider to entity {name} via {constructor:#?} that requires a mesh, \
but no mesh handle was found"));
let mesh = meshes.get(mesh_handle);
Expand All @@ -317,13 +318,17 @@ fn init_collider_constructors(
None
};

#[cfg(all(feature = "3d", feature = "collider-from-mesh"))]
let collider = Collider::try_from_constructor(constructor.clone(), mesh);
#[cfg(not(all(feature = "3d", feature = "collider-from-mesh")))]
let collider = Collider::try_from_constructor(constructor.clone());

if let Some(collider) = collider {
commands.entity(entity).insert(collider);
} else {
error!(
"Tried to add a collider to entity {name} via {constructor:#?}, \
but the collider could not be generated from mesh {mesh:#?}. Skipping.",
but the collider could not be generated. Skipping.",
);
}
commands.entity(entity).remove::<ColliderConstructor>();
Expand All @@ -335,13 +340,14 @@ fn init_collider_constructors(
/// If an entity has a `SceneInstance`, its collider hierarchy is only generated once the scene is ready.
fn init_collider_constructor_hierarchies(
mut commands: Commands,
meshes: Res<Assets<Mesh>>,
#[cfg(all(feature = "3d", feature = "collider-from-mesh"))] meshes: Res<Assets<Mesh>>,
#[cfg(all(feature = "3d", feature = "collider-from-mesh"))] mesh_handles: Query<&Handle<Mesh>>,
#[cfg(feature = "bevy_scene")] scene_spawner: Res<SceneSpawner>,
#[cfg(feature = "bevy_scene")] scenes: Query<&Handle<Scene>>,
#[cfg(feature = "bevy_scene")] scene_instances: Query<&SceneInstance>,
collider_constructors: Query<(Entity, &ColliderConstructorHierarchy)>,
children: Query<&Children>,
mesh_handles: Query<(Option<&Name>, Option<&Collider>, Option<&Handle<Mesh>>)>,
child_query: Query<(Option<&Name>, Option<&Collider>)>,
) {
for (scene_entity, collider_constructor_hierarchy) in collider_constructors.iter() {
#[cfg(feature = "bevy_scene")]
Expand All @@ -360,73 +366,79 @@ fn init_collider_constructor_hierarchies(
}

for child_entity in children.iter_descendants(scene_entity) {
if let Ok((name, existing_collider, handle)) = mesh_handles.get(child_entity) {
let pretty_name = pretty_name(name, child_entity);

let default_collider = || {
Some(ColliderConstructorHierarchyConfig {
constructor: collider_constructor_hierarchy.default_constructor.clone(),
..default()
})
};

let collider_data = if let Some(name) = name {
collider_constructor_hierarchy
.config
.get(name.as_str())
.cloned()
.unwrap_or_else(default_collider)
} else if existing_collider.is_some() {
warn!("Tried to add a collider to entity {pretty_name} via {collider_constructor_hierarchy:#?}, \
let Ok((name, existing_collider)) = child_query.get(child_entity) else {
continue;
};

let pretty_name = pretty_name(name, child_entity);

let default_collider = || {
Some(ColliderConstructorHierarchyConfig {
constructor: collider_constructor_hierarchy.default_constructor.clone(),
..default()
})
};

let collider_data = if let Some(name) = name {
collider_constructor_hierarchy
.config
.get(name.as_str())
.cloned()
.unwrap_or_else(default_collider)
} else if existing_collider.is_some() {
warn!("Tried to add a collider to entity {pretty_name} via {collider_constructor_hierarchy:#?}, \
but that entity already holds a collider. Skipping. \
If this was intentional, add the name of the collider to overwrite to `ColliderConstructorHierarchy.config`.");
continue;
} else {
default_collider()
};
continue;
} else {
default_collider()
};

// If the configuration is explicitly set to `None`, skip this entity.
let Some(collider_data) = collider_data else {
continue;
};
// If the configuration is explicitly set to `None`, skip this entity.
let Some(collider_data) = collider_data else {
continue;
};

// Use the configured constructor if specified, otherwise use the default constructor.
// If both are `None`, skip this entity.
let Some(constructor) = collider_data
.constructor
.or_else(|| collider_constructor_hierarchy.default_constructor.clone())
else {
continue;
};

// Use the configured constructor if specified, otherwise use the default constructor.
// If both are `None`, skip this entity.
let Some(constructor) = collider_data
.constructor
.or_else(|| collider_constructor_hierarchy.default_constructor.clone())
else {
#[cfg(all(feature = "3d", feature = "collider-from-mesh"))]
let mesh = if constructor.requires_mesh() {
if let Ok(handle) = mesh_handles.get(child_entity) {
meshes.get(handle)
} else {
continue;
};
}
} else {
None
};

let mesh = if constructor.requires_mesh() {
if let Some(handle) = handle {
meshes.get(handle)
} else {
continue;
}
} else {
None
};
#[cfg(all(feature = "3d", feature = "collider-from-mesh"))]
let collider = Collider::try_from_constructor(constructor, mesh);
#[cfg(not(all(feature = "3d", feature = "collider-from-mesh")))]
let collider = Collider::try_from_constructor(constructor);

let collider = Collider::try_from_constructor(constructor, mesh);

if let Some(collider) = collider {
commands.entity(child_entity).insert((
collider,
collider_data
.layers
.unwrap_or(collider_constructor_hierarchy.default_layers),
collider_data
.density
.unwrap_or(collider_constructor_hierarchy.default_density),
));
} else {
error!(
if let Some(collider) = collider {
commands.entity(child_entity).insert((
collider,
collider_data
.layers
.unwrap_or(collider_constructor_hierarchy.default_layers),
collider_data
.density
.unwrap_or(collider_constructor_hierarchy.default_density),
));
} else {
error!(
"Tried to add a collider to entity {pretty_name} via {collider_constructor_hierarchy:#?}, \
but the collider could not be generated from mesh {mesh:#?}. Skipping.",
but the collider could not be generated. Skipping.",
);
}
}
}

Expand Down
24 changes: 9 additions & 15 deletions src/collision/collider/constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,22 +432,16 @@ pub enum ColliderConstructor {

impl ColliderConstructor {
/// Returns `true` if the collider type requires a mesh to be generated.
#[cfg(all(feature = "3d", feature = "collider-from-mesh"))]
pub fn requires_mesh(&self) -> bool {
#[cfg(all(feature = "3d", feature = "collider-from-mesh"))]
{
matches!(
self,
Self::TrimeshFromMesh
| Self::TrimeshFromMeshWithConfig(_)
| Self::ConvexDecompositionFromMesh
| Self::ConvexDecompositionFromMeshWithConfig(_)
| Self::ConvexHullFromMesh
)
}
#[cfg(not(all(feature = "3d", feature = "collider-from-mesh")))]
{
false
}
matches!(
self,
Self::TrimeshFromMesh
| Self::TrimeshFromMeshWithConfig(_)
| Self::ConvexDecompositionFromMesh
| Self::ConvexDecompositionFromMeshWithConfig(_)
| Self::ConvexHullFromMesh
)
}
}

Expand Down
17 changes: 12 additions & 5 deletions src/collision/collider/parry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1073,16 +1073,23 @@ impl Collider {
})
}

/// Attempts to create a collider from an optional mesh with the given [`ColliderConstructor`].
/// Attempts to create a collider with the given [`ColliderConstructor`].
/// By using this, you can serialize and deserialize the collider's creation method
/// separately from the collider itself via the [`ColliderConstructor`] enum.
///
/// Returns `None` in the following cases:
/// - The given [`ColliderConstructor`] requires a mesh, but none was provided.
/// - Creating the collider from the given [`ColliderConstructor`] failed.
#[cfg_attr(
all(feature = "3d", feature = "collider-from-mesh"),
doc = "Returns `None` in the following cases:
- The given [`ColliderConstructor`] requires a mesh, but none was provided.
- Creating the collider from the given [`ColliderConstructor`] failed."
)]
#[cfg_attr(
not(all(feature = "3d", feature = "collider-from-mesh")),
doc = "Returns `None` if creating the collider from the given [`ColliderConstructor`] failed."
)]
pub fn try_from_constructor(
collider_constructor: ColliderConstructor,
#[allow(unused_variables)] mesh: Option<&Mesh>,
#[cfg(all(feature = "3d", feature = "collider-from-mesh"))] mesh: Option<&Mesh>,
) -> Option<Self> {
match collider_constructor {
#[cfg(feature = "2d")]
Expand Down

0 comments on commit d02a9b8

Please sign in to comment.