steel_core/fluid/fluids/
lava.rs1use std::sync::Arc;
6
7use glam::DVec3;
8use steel_registry::REGISTRY;
9use steel_registry::blocks::block_state_ext::BlockStateExt;
10use steel_registry::blocks::properties::Direction;
11use steel_registry::items::ItemRef;
12use steel_registry::level_events;
13use steel_registry::sound_event::SoundEventRef;
14use steel_registry::sound_events;
15use steel_registry::vanilla_blocks;
16use steel_registry::vanilla_game_rules::LAVA_SOURCE_CONVERSION;
17use steel_registry::vanilla_items;
18use steel_utils::BlockPos;
19use steel_utils::BlockStateId;
20use steel_utils::types::UpdateFlags;
21
22use crate::entity::{Entity, InsideBlockEffectCollector, InsideBlockEffectType};
23use crate::fluid::{FlowingFluid, FluidBehavior, get_flow as flowing_fluid_flow};
24use crate::fluid::{
25 FluidRef, FluidState, FluidStateExt, get_fluid_state, get_height, is_lava_fluid,
26 is_water_fluid, lava_id, liquid_block_state,
27};
28use crate::world::World;
29const NORMAL_LAVA_ENTITY_FLOW_SCALE: f64 = 0.002_333_333_333_333_333_5;
30const FAST_LAVA_ENTITY_FLOW_SCALE: f64 = 0.007;
31
32pub struct LavaFluid;
38
39impl LavaFluid {
40 fn is_fast_lava(world: &Arc<World>) -> bool {
42 world.dimension_type.fast_lava
43 }
44
45 pub(crate) fn entity_flow_scale(world: &Arc<World>) -> f64 {
47 if Self::is_fast_lava(world) {
48 FAST_LAVA_ENTITY_FLOW_SCALE
49 } else {
50 NORMAL_LAVA_ENTITY_FLOW_SCALE
51 }
52 }
53}
54
55impl FluidBehavior for LavaFluid {
56 fn pickup_sound(&self) -> Option<SoundEventRef> {
57 Some(&sound_events::ITEM_BUCKET_FILL_LAVA)
58 }
59
60 fn create_legacy_block(&self, fluid_state: FluidState) -> BlockStateId {
61 liquid_block_state(&vanilla_blocks::LAVA, fluid_state)
62 }
63
64 fn bucket(&self) -> ItemRef {
65 &vanilla_items::LAVA_BUCKET
66 }
67
68 fn fluid_type(&self) -> FluidRef {
69 lava_id()
70 }
71
72 fn is_same(&self, fluid: FluidRef) -> bool {
73 is_lava_fluid(fluid)
74 }
75
76 fn tick_delay(&self, world: &Arc<World>) -> i32 {
77 if Self::is_fast_lava(world) { 10 } else { 30 }
78 }
79
80 fn drop_off(&self, world: &Arc<World>) -> u8 {
81 if Self::is_fast_lava(world) { 1 } else { 2 }
82 }
83
84 fn slope_find_distance(&self, world: &Arc<World>) -> u8 {
85 if Self::is_fast_lava(world) { 4 } else { 2 }
86 }
87
88 fn explosion_resistance(&self) -> f32 {
89 100.0
90 }
91
92 fn can_convert_to_source(&self, world: &Arc<World>) -> bool {
93 world.get_game_rule(&LAVA_SOURCE_CONVERSION)
94 }
95
96 fn get_flow(&self, world: &Arc<World>, pos: BlockPos, fluid_state: FluidState) -> DVec3 {
97 flowing_fluid_flow(world, pos, fluid_state)
98 }
99
100 fn can_be_replaced_with(
105 &self,
106 fluid_state: FluidState,
107 world: &Arc<World>,
108 pos: BlockPos,
109 other_fluid: FluidRef,
110 _direction: Direction,
111 ) -> bool {
112 get_height(world, pos, fluid_state) >= 0.444_444_45 && is_water_fluid(other_fluid)
113 }
114
115 fn get_spread_delay(
121 &self,
122 world: &Arc<World>,
123 pos: BlockPos,
124 old_state: FluidState,
125 new_state: FluidState,
126 ) -> i32 {
127 let base = self.tick_delay(world);
128 if !old_state.is_empty()
129 && !new_state.is_empty()
130 && !old_state.falling
131 && !new_state.falling
132 && get_height(world, pos, new_state) > get_height(world, pos, old_state)
133 && rand::random_range(0u32..4) != 0
134 {
135 base * 4
136 } else {
137 base
138 }
139 }
140
141 fn before_destroying_block(&self, world: &Arc<World>, pos: BlockPos, _state: BlockStateId) {
143 world.level_event(level_events::LAVA_FIZZ, pos, 0, None);
144 }
145
146 fn entity_inside(
148 &self,
149 _world: &Arc<World>,
150 _pos: BlockPos,
151 _entity: &dyn Entity,
152 effect_collector: &mut InsideBlockEffectCollector,
153 ) {
154 effect_collector.apply(InsideBlockEffectType::ClearFreeze);
155 effect_collector.apply(InsideBlockEffectType::LavaIgnite);
156 effect_collector.run_after(
157 InsideBlockEffectType::LavaIgnite,
158 Box::new(Entity::lava_hurt),
159 );
160 }
161
162 fn tick(
163 &self,
164 world: &Arc<World>,
165 pos: BlockPos,
166 block_state: BlockStateId,
167 fluid_state: FluidState,
168 ) {
169 self.base_tick(world, pos, block_state, fluid_state);
170 }
171
172 fn spread(
173 &self,
174 world: &Arc<World>,
175 pos: BlockPos,
176 block_state: BlockStateId,
177 fluid_state: FluidState,
178 ) {
179 self.base_spread(world, pos, block_state, fluid_state);
180 }
181}
182
183impl FlowingFluid for LavaFluid {
185 fn spread_to(
186 &self,
187 world: &Arc<World>,
188 pos: BlockPos,
189 fluid_state: FluidState,
190 direction: Direction,
191 ) {
192 if direction == Direction::Down {
193 let below_fluid = get_fluid_state(world, pos);
194 if below_fluid.is_water() {
195 world.level_event(level_events::LAVA_FIZZ, pos, 0, None);
198
199 let below_block = world.get_block_state(pos).get_block();
202 if below_block == &vanilla_blocks::WATER {
203 world.set_block(
204 pos,
205 REGISTRY.blocks.get_default_state_id(&vanilla_blocks::STONE),
206 UpdateFlags::UPDATE_ALL_IMMEDIATE,
207 );
208 }
209 return;
210 }
211 }
212
213 self.base_spread_to(world, pos, fluid_state);
214 }
215}