steel_core/behavior/blocks/building/
lava_cauldron_block.rs1use std::sync::Arc;
2
3use steel_macros::block_behavior;
4use steel_registry::blocks::{BlockRef, properties::Direction, shapes::VoxelShape};
5use steel_utils::{BlockLocalAabb, BlockPos, BlockStateId};
6
7use crate::{
8 behavior::{BlockBehavior, BlockPlaceContext},
9 entity::ai::path::PathComputationType,
10 entity::{Entity, InsideBlockEffectCollector, InsideBlockEffectType},
11 world::{LevelReader, World},
12};
13
14const CAULDRON_FILLED_ENTITY_INSIDE_BOXES: &[BlockLocalAabb] = &[
15 BlockLocalAabb::new(0.0, 0.0, 0.0, 0.1875, 0.5625, 0.1875),
16 BlockLocalAabb::new(0.8125, 0.0, 0.0, 1.0, 0.5625, 0.1875),
17 BlockLocalAabb::new(0.0, 0.1875, 0.1875, 1.0, 0.5625, 1.0),
18 BlockLocalAabb::new(0.1875, 0.1875, 0.0, 0.8125, 0.5625, 0.1875),
19 BlockLocalAabb::new(0.0, 0.0, 0.8125, 0.1875, 0.5625, 1.0),
20 BlockLocalAabb::new(0.8125, 0.0, 0.8125, 1.0, 0.5625, 1.0),
21 BlockLocalAabb::new(0.0, 0.1875, 0.0, 1.0, 0.5625, 0.8125),
22 BlockLocalAabb::new(0.1875, 0.1875, 0.8125, 0.8125, 0.5625, 1.0),
23 BlockLocalAabb::new(0.125, 0.25, 0.125, 0.875, 0.9375, 0.875),
24];
25const CAULDRON_FILLED_ENTITY_INSIDE_SHAPE: VoxelShape =
26 VoxelShape::from_boxes(CAULDRON_FILLED_ENTITY_INSIDE_BOXES);
27
28#[block_behavior]
32pub struct LavaCauldronBlock {
33 block: BlockRef,
34}
35
36impl LavaCauldronBlock {
37 #[must_use]
39 pub const fn new(block: BlockRef) -> Self {
40 Self { block }
41 }
42}
43
44impl BlockBehavior for LavaCauldronBlock {
45 fn get_state_for_placement(&self, _context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
46 Some(self.block.default_state())
47 }
48
49 fn get_entity_inside_collision_shape(
50 &self,
51 _state: BlockStateId,
52 _world: &dyn LevelReader,
53 _pos: BlockPos,
54 _entity: &dyn Entity,
55 ) -> VoxelShape {
56 CAULDRON_FILLED_ENTITY_INSIDE_SHAPE
57 }
58
59 fn has_analog_output_signal(&self, _state: BlockStateId) -> bool {
60 true
61 }
62
63 fn get_analog_output_signal(
64 &self,
65 _state: BlockStateId,
66 _world: &dyn LevelReader,
67 _pos: BlockPos,
68 _direction: Direction,
69 ) -> i32 {
70 3
71 }
72
73 fn is_pathfindable(
74 &self,
75 _state: BlockStateId,
76 _computation_type: PathComputationType,
77 ) -> bool {
78 false
79 }
80
81 fn entity_inside(
82 &self,
83 _state: BlockStateId,
84 _world: &Arc<World>,
85 _pos: BlockPos,
86 _entity: &dyn Entity,
87 effect_collector: &mut InsideBlockEffectCollector,
88 _is_precise: bool,
89 ) {
90 effect_collector.apply(InsideBlockEffectType::ClearFreeze);
91 effect_collector.apply(InsideBlockEffectType::LavaIgnite);
92 effect_collector.run_after(
93 InsideBlockEffectType::LavaIgnite,
94 Box::new(Entity::lava_hurt),
95 );
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use steel_registry::{init_vanilla_registry, vanilla_blocks};
102
103 use super::*;
104 use crate::{
105 behavior::{BLOCK_BEHAVIORS, init_behaviors},
106 test_support::TestLevel,
107 };
108
109 fn assert_f64_close(actual: f64, expected: f64) {
110 assert!(
111 (actual - expected).abs() <= f64::EPSILON,
112 "expected {actual} to equal {expected}"
113 );
114 }
115
116 #[test]
117 fn filled_entity_inside_shape_includes_lava_column() {
118 let Some(bounds) = CAULDRON_FILLED_ENTITY_INSIDE_SHAPE.bounds() else {
119 panic!("lava cauldron entity-inside shape is non-empty");
120 };
121
122 assert_f64_close(bounds.min_x(), 0.0);
123 assert_f64_close(bounds.min_y(), 0.0);
124 assert_f64_close(bounds.min_z(), 0.0);
125 assert_f64_close(bounds.max_x(), 1.0);
126 assert_f64_close(bounds.max_y(), 0.9375);
127 assert_f64_close(bounds.max_z(), 1.0);
128 assert_eq!(CAULDRON_FILLED_ENTITY_INSIDE_SHAPE.len(), 9);
129 }
130
131 #[test]
132 fn registered_lava_cauldron_outputs_three() {
133 init_vanilla_registry();
134 init_behaviors();
135 let state = vanilla_blocks::LAVA_CAULDRON.default_state();
136 let behavior = BLOCK_BEHAVIORS.get_behavior(&vanilla_blocks::LAVA_CAULDRON);
137
138 assert!(behavior.has_analog_output_signal(state));
139 assert_eq!(
140 behavior.get_analog_output_signal(
141 state,
142 &TestLevel::default(),
143 BlockPos::ZERO,
144 Direction::North,
145 ),
146 3,
147 );
148 }
149}