steel_core/behavior/block/
collision.rs1use super::{
2 Arc, Axis, BLOCK_BEHAVIORS, BlockCollisionContext, BlockPos, BlockStateExt, BlockStateId,
3 BooleanOp, DVec3, World, WorldAabb, collide, join_unoptimized_boxes,
4};
5
6pub(crate) fn push_entities_up(
11 old_state: BlockStateId,
12 new_state: BlockStateId,
13 world: &Arc<World>,
14 pos: BlockPos,
15) -> BlockStateId {
16 let added_collision = added_collision_boxes(old_state, new_state, world, pos);
17 let Some(query_box) = world_aabb_bounds(&added_collision) else {
18 return new_state;
19 };
20
21 for entity in world.get_entities_in_aabb(&query_box) {
22 let offset = collide(
23 Axis::Y,
24 &entity.bounding_box().translate(DVec3::ZERO.with_y(1.0)),
25 &added_collision,
26 -1.0,
27 );
28 if let Err(error) =
29 entity.try_set_position(entity.position() + DVec3::new(0.0, 1.0 + offset, 0.0))
30 {
31 log::debug!(
32 "Failed to push entity {} up after block collision change at {pos:?}: {error}",
33 entity.id()
34 );
35 }
36 }
37
38 new_state
39}
40
41fn added_collision_boxes(
42 old_state: BlockStateId,
43 new_state: BlockStateId,
44 world: &Arc<World>,
45 pos: BlockPos,
46) -> Vec<WorldAabb> {
47 let context = BlockCollisionContext::empty();
48 let old_shape = BLOCK_BEHAVIORS
49 .get_behavior(old_state.get_block())
50 .get_collision_shape(old_state, world.as_ref(), pos, context);
51 let new_shape = BLOCK_BEHAVIORS
52 .get_behavior(new_state.get_block())
53 .get_collision_shape(new_state, world.as_ref(), pos, context);
54
55 join_unoptimized_boxes(old_shape, new_shape, BooleanOp::OnlySecond)
56 .into_iter()
57 .map(|aabb| aabb.at_block(pos))
58 .collect()
59}
60
61pub(super) fn world_aabb_bounds(boxes: &[WorldAabb]) -> Option<WorldAabb> {
62 let first = boxes.first()?;
63 let mut min_x = first.min_x();
64 let mut min_y = first.min_y();
65 let mut min_z = first.min_z();
66 let mut max_x = first.max_x();
67 let mut max_y = first.max_y();
68 let mut max_z = first.max_z();
69
70 for aabb in boxes {
71 min_x = min_x.min(aabb.min_x());
72 min_y = min_y.min(aabb.min_y());
73 min_z = min_z.min(aabb.min_z());
74 max_x = max_x.max(aabb.max_x());
75 max_y = max_y.max(aabb.max_y());
76 max_z = max_z.max(aabb.max_z());
77 }
78
79 Some(WorldAabb::new(min_x, min_y, min_z, max_x, max_y, max_z))
80}