aboutsummaryrefslogtreecommitdiff
path: root/azalea-physics/src/collision/entity_collisions.rs
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2025-03-16 13:41:17 -0500
committerGitHub <noreply@github.com>2025-03-16 13:41:17 -0500
commitb0bd992adcff71ee294dd05060e00e652f62a7b2 (patch)
tree0a36d8b37befbc75c8c65cc2c8779c3df66bd87b /azalea-physics/src/collision/entity_collisions.rs
parenta95408cbcc05b5bd04a084b0a286b571069206f6 (diff)
downloadazalea-drasl-b0bd992adcff71ee294dd05060e00e652f62a7b2.tar.xz
Fluid physics fixes (#210)
* start fixing code related to fluid physics * implement force_solid for blocks * afk pool test
Diffstat (limited to 'azalea-physics/src/collision/entity_collisions.rs')
-rw-r--r--azalea-physics/src/collision/entity_collisions.rs97
1 files changed, 97 insertions, 0 deletions
diff --git a/azalea-physics/src/collision/entity_collisions.rs b/azalea-physics/src/collision/entity_collisions.rs
new file mode 100644
index 00000000..1300cf34
--- /dev/null
+++ b/azalea-physics/src/collision/entity_collisions.rs
@@ -0,0 +1,97 @@
+use azalea_core::aabb::AABB;
+use azalea_entity::{
+ LocalEntity, Physics,
+ metadata::{AbstractBoat, Shulker},
+};
+use azalea_world::Instance;
+use bevy_ecs::{
+ entity::Entity,
+ query::{Or, With, Without},
+ system::Query,
+};
+use tracing::error;
+
+use super::VoxelShape;
+
+/// This query matches on entities that we can collide with. That is, boats and
+/// shulkers.
+///
+/// If you want to use this in a more complex query, use
+/// [`CollidableEntityFilter`] as a filter instead.
+pub type CollidableEntityQuery<'world, 'state> = Query<'world, 'state, (), CollidableEntityFilter>;
+/// This filter matches on entities that we can collide with (boats and
+/// shulkers).
+///
+/// Use [`CollidableEntityQuery`] if you want an empty query that matches with
+/// this.
+pub type CollidableEntityFilter = Or<(With<AbstractBoat>, With<Shulker>)>;
+
+pub type PhysicsQuery<'world, 'state, 'a> =
+ Query<'world, 'state, &'a Physics, Without<LocalEntity>>;
+
+pub fn get_entity_collisions(
+ world: &Instance,
+ aabb: &AABB,
+ source_entity: Option<Entity>,
+ physics_query: &PhysicsQuery,
+ collidable_entity_query: &CollidableEntityQuery,
+) -> Vec<VoxelShape> {
+ if aabb.size() < 1.0E-7 {
+ return vec![];
+ }
+
+ let collision_predicate = |entity| collidable_entity_query.get(entity).is_ok();
+
+ let collidable_entities = get_entities(
+ world,
+ source_entity,
+ &aabb.inflate_all(1.0E-7),
+ &collision_predicate,
+ physics_query,
+ );
+
+ collidable_entities
+ .into_iter()
+ .map(|(_entity, aabb)| VoxelShape::from(aabb))
+ .collect()
+}
+
+/// Return all entities that are colliding with the given bounding box and match
+/// the given predicate.
+///
+/// `source_entity` is the entity that the bounding box belongs to, and won't be
+/// one of the returned entities.
+pub fn get_entities(
+ world: &Instance,
+ source_entity: Option<Entity>,
+ aabb: &AABB,
+ predicate: &dyn Fn(Entity) -> bool,
+ physics_query: &PhysicsQuery,
+) -> Vec<(Entity, AABB)> {
+ let mut matches = Vec::new();
+
+ super::world_collisions::for_entities_in_chunks_colliding_with(
+ world,
+ aabb,
+ |_chunk_pos, entities_in_chunk| {
+ // now check if the entity itself collides
+ for &candidate in entities_in_chunk {
+ if Some(candidate) != source_entity && predicate(candidate) {
+ let Ok(physics) = physics_query.get(candidate) else {
+ error!(
+ "Entity {candidate} (found from for_entities_in_chunks_colliding_with) is missing required components."
+ );
+ continue;
+ };
+
+ let candidate_aabb = physics.bounding_box;
+ if aabb.intersects_aabb(&candidate_aabb) {
+ matches.push((candidate, physics.bounding_box));
+ }
+ }
+ }
+ },
+ );
+
+ matches
+}