azalea_physics/collision/
entity_collisions.rs1use azalea_core::aabb::Aabb;
2use azalea_entity::{
3 Physics,
4 metadata::{AbstractBoat, Shulker},
5};
6use azalea_world::Instance;
7use bevy_ecs::{
8 component::Component,
9 entity::Entity,
10 query::{Changed, Or, With},
11 system::{Commands, Query},
12};
13use tracing::error;
14
15use super::VoxelShape;
16
17pub type CollidableEntityQuery<'world, 'state> = Query<'world, 'state, (), CollidableEntityFilter>;
23pub type CollidableEntityFilter = Or<(With<AbstractBoat>, With<Shulker>)>;
29
30#[derive(Component)]
33pub struct LastBoundingBox(pub Aabb);
34
35pub type AabbQuery<'world, 'state, 'a> = Query<'world, 'state, &'a LastBoundingBox>;
36
37pub fn update_last_bounding_box(
39 mut commands: Commands,
40 mut query: Query<(Entity, Option<&mut LastBoundingBox>, &Physics), Changed<Physics>>,
41) {
42 for (entity, mut last_bounding_box, physics) in &mut query {
43 if let Some(last_bounding_box) = last_bounding_box.as_mut() {
44 last_bounding_box.0 = physics.bounding_box;
45 } else {
46 commands
47 .entity(entity)
48 .insert(LastBoundingBox(physics.bounding_box));
49 }
50 }
51}
52
53pub fn get_entity_collisions(
54 world: &Instance,
55 aabb: &Aabb,
56 source_entity: Option<Entity>,
57 aabb_query: &AabbQuery,
58 collidable_entity_query: &CollidableEntityQuery,
59) -> Vec<VoxelShape> {
60 if aabb.size() < 1.0E-7 {
61 return vec![];
62 }
63
64 let collision_predicate = |entity| collidable_entity_query.get(entity).is_ok();
65
66 let collidable_entities = get_entities(
67 world,
68 source_entity,
69 &aabb.inflate_all(1.0E-7),
70 &collision_predicate,
71 aabb_query,
72 );
73
74 collidable_entities
75 .into_iter()
76 .map(|(_entity, aabb)| VoxelShape::from(aabb))
77 .collect()
78}
79
80pub fn get_entities(
86 world: &Instance,
87 source_entity: Option<Entity>,
88 aabb: &Aabb,
89 predicate: &dyn Fn(Entity) -> bool,
90 aabb_query: &AabbQuery,
91) -> Vec<(Entity, Aabb)> {
92 let mut matches = Vec::new();
93
94 super::world_collisions::for_entities_in_chunks_colliding_with(
95 world,
96 aabb,
97 |_chunk_pos, entities_in_chunk| {
98 for &candidate in entities_in_chunk {
100 if Some(candidate) != source_entity && predicate(candidate) {
101 let Ok(candidate_aabb) = aabb_query.get(candidate) else {
102 error!(
103 "Entity {candidate} (found from for_entities_in_chunks_colliding_with) is missing required components."
104 );
105 continue;
106 };
107 let candidate_aabb = &candidate_aabb.0;
108
109 if aabb.intersects_aabb(candidate_aabb) {
110 matches.push((candidate, candidate_aabb.to_owned()));
111 }
112 }
113 }
114 },
115 );
116
117 matches
118}