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