From b0bd992adcff71ee294dd05060e00e652f62a7b2 Mon Sep 17 00:00:00 2001 From: mat <27899617+mat-1@users.noreply.github.com> Date: Sun, 16 Mar 2025 13:41:17 -0500 Subject: Fluid physics fixes (#210) * start fixing code related to fluid physics * implement force_solid for blocks * afk pool test --- azalea-physics/src/collision/entity_collisions.rs | 97 +++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 azalea-physics/src/collision/entity_collisions.rs (limited to 'azalea-physics/src/collision/entity_collisions.rs') 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, With)>; + +pub type PhysicsQuery<'world, 'state, 'a> = + Query<'world, 'state, &'a Physics, Without>; + +pub fn get_entity_collisions( + world: &Instance, + aabb: &AABB, + source_entity: Option, + physics_query: &PhysicsQuery, + collidable_entity_query: &CollidableEntityQuery, +) -> Vec { + 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, + 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 +} -- cgit v1.2.3