1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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
}
|