1mod block;
28pub mod blocks;
29mod consume_effect;
30mod context;
31pub mod fluid;
32mod item;
33pub(crate) mod item_utils;
34pub mod items;
35mod mob_effect;
36
37#[expect(warnings)]
38#[rustfmt::skip]
39#[path = "generated/blocks.rs"]
40pub mod block_behaviors;
41
42#[expect(warnings)]
43#[rustfmt::skip]
44#[path = "generated/candle_cakes.rs"]
45pub mod candle_cakes;
46
47#[allow(warnings)]
48#[rustfmt::skip]
49#[path = "generated/items.rs"]
50pub mod item_behaviors;
51
52#[expect(warnings)]
53#[rustfmt::skip]
54#[path = "generated/strippables.rs"]
55pub mod strippables;
56
57#[expect(warnings)]
58#[rustfmt::skip]
59#[path = "generated/waxables.rs"]
60pub mod waxables;
61
62#[expect(warnings)]
63#[rustfmt::skip]
64#[path = "generated/weathering.rs"]
65pub mod weathering;
66
67pub use block::{
68 BlockBehavior, BlockBehaviorRegistry, BlockCollisionBoxes, BlockCollisionContext,
69 BlockEntityCreation, BlockLootContext, BrushableData, DefaultBlockBehavior, EntityFallDamage,
70 EntityFallOnContext, EntityFallOnFacts, EntityLandingContext, Fallable, RailBehavior,
71};
72pub(crate) use block::{pickup_waterlogged_block, try_drop_experience};
73use block_behaviors::register_block_behaviors;
74pub use consume_effect::{CONSUME_EFFECT_BEHAVIORS, ConsumeEffectBehaviorRegistry};
75pub use context::{
76 BlockHitResult, BlockPlaceContext, InteractionResult, InventoryAccess, PlacementOrientation,
77 PlacementSource, UseItemContext, UseOnContext,
78};
79pub use fluid::{FLUID_BEHAVIORS, FluidBehaviorRegistry};
80pub(crate) use item::apply_use_remainder;
81pub use item::{ItemBehavior, ItemBehaviorRegistry, ItemUseAnimation};
82use item_behaviors::register_item_behaviors;
83pub use items::{
84 BedItem, BlockItem, BucketItem, DefaultItemBehavior, DoubleHighBlockItem, EnderEyeItem,
85 HangingSignItem, ScaffoldingBlockItem, ShovelItem, SignItem, SolidBucketItem,
86 StandingAndWallBlockItem,
87};
88pub use mob_effect::{MOB_EFFECT_BEHAVIORS, MobEffectBehaviorRegistry};
89use std::ops::Deref;
90use std::sync::OnceLock;
91use steel_registry::blocks::BlockRef;
92use steel_registry::blocks::block_state_ext::BlockStateExt;
93use steel_registry::consume_effect::vanilla_consume_effect_types;
94use steel_registry::vanilla_fluids;
95use steel_registry::vanilla_mob_effects;
96use steel_utils::BlockStateId;
97
98use crate::entity::ai::path::PathComputationType;
99use crate::entity::consume_effect::{
100 ApplyEffectsBehavior, ClearAllEffectsBehavior, ConsumeEffectBehavior, PlaySoundBehavior,
101 RemoveEffectsBehavior, TeleportRandomlyBehavior,
102};
103use crate::entity::mob_effect::{
104 AbsorptionBehavior, BadOmenBehavior, HealOrHarmBehavior, HungerBehavior, InfestedBehavior,
105 MobEffectBehavior, OozingBehavior, PoisonBehavior, RaidOmenBehavior, RegenerationBehavior,
106 SaturationBehavior, WeavingBehavior, WindChargedBehavior, WitherBehavior,
107};
108use crate::fluid::{FluidBehavior, LavaFluid, WaterFluid};
109
110pub struct BlockBehaviorLock(OnceLock<BlockBehaviorRegistry>);
112
113impl Deref for BlockBehaviorLock {
114 type Target = BlockBehaviorRegistry;
115
116 fn deref(&self) -> &Self::Target {
117 self.0.get().expect("Block behaviors not initialized")
118 }
119}
120
121pub struct ItemBehaviorLock(OnceLock<ItemBehaviorRegistry>);
123
124impl Deref for ItemBehaviorLock {
125 type Target = ItemBehaviorRegistry;
126
127 fn deref(&self) -> &Self::Target {
128 self.0.get().expect("Item behaviors not initialized")
129 }
130}
131
132pub trait BlockStateBehaviorExt {
137 fn is_liquid_container(&self) -> bool;
139
140 fn can_be_replaced_by_fluid(&self, fluid_block: BlockRef) -> bool;
142
143 fn can_be_replaced(&self, context: &BlockPlaceContext<'_>) -> bool;
145
146 fn is_pathfindable(&self, computation_type: PathComputationType) -> bool;
148
149 fn is_bed(&self) -> bool;
151
152 fn is_liquid_block(&self) -> bool;
154
155 fn is_possible_to_respawn_in_this(&self) -> bool;
157}
158
159impl BlockStateBehaviorExt for BlockStateId {
160 fn is_liquid_container(&self) -> bool {
161 let block = self.get_block();
162 let behavior = BLOCK_BEHAVIORS.get_behavior(block);
163 behavior.is_liquid_container(*self)
164 }
165
166 fn can_be_replaced_by_fluid(&self, fluid_block: BlockRef) -> bool {
167 let block = self.get_block();
168 let behavior = BLOCK_BEHAVIORS.get_behavior(block);
169 behavior.can_be_replaced_by_fluid(*self, fluid_block)
170 }
171
172 fn can_be_replaced(&self, context: &BlockPlaceContext<'_>) -> bool {
173 let block = self.get_block();
174 let behavior = BLOCK_BEHAVIORS.get_behavior(block);
175 behavior.can_be_replaced(*self, context)
176 }
177
178 fn is_pathfindable(&self, computation_type: PathComputationType) -> bool {
179 let block = self.get_block();
180 let behavior = BLOCK_BEHAVIORS.get_behavior(block);
181 behavior.is_pathfindable(*self, computation_type)
182 }
183
184 fn is_bed(&self) -> bool {
185 let block = self.get_block();
186 BLOCK_BEHAVIORS.get_behavior(block).is_bed()
187 }
188
189 fn is_liquid_block(&self) -> bool {
190 let block = self.get_block();
191 BLOCK_BEHAVIORS.get_behavior(block).is_liquid_block()
192 }
193
194 fn is_possible_to_respawn_in_this(&self) -> bool {
195 let block = self.get_block();
196 let behavior = BLOCK_BEHAVIORS.get_behavior(block);
197 behavior.is_possible_to_respawn_in_this(*self)
198 }
199}
200
201pub static BLOCK_BEHAVIORS: BlockBehaviorLock = BlockBehaviorLock(OnceLock::new());
205
206pub static ITEM_BEHAVIORS: ItemBehaviorLock = ItemBehaviorLock(OnceLock::new());
210
211pub fn init_behaviors() {
215 BLOCK_BEHAVIORS.0.get_or_init(|| {
216 let mut block_behaviors = BlockBehaviorRegistry::new();
217 register_block_behaviors(&mut block_behaviors);
218 block_behaviors
219 });
220
221 FLUID_BEHAVIORS.0.get_or_init(|| {
222 let mut fluid_behaviors = FluidBehaviorRegistry::new();
223
224 let water_behavior: Box<dyn FluidBehavior> = Box::new(WaterFluid);
226 fluid_behaviors.set_behavior(&vanilla_fluids::WATER, water_behavior);
228 fluid_behaviors.set_behavior(&vanilla_fluids::FLOWING_WATER, Box::new(WaterFluid));
229
230 let lava_behavior: Box<dyn FluidBehavior> = Box::new(LavaFluid);
232 fluid_behaviors.set_behavior(&vanilla_fluids::LAVA, lava_behavior);
233 fluid_behaviors.set_behavior(&vanilla_fluids::FLOWING_LAVA, Box::new(LavaFluid));
234
235 fluid_behaviors
236 });
237
238 ITEM_BEHAVIORS.0.get_or_init(|| {
239 let mut item_behaviors = ItemBehaviorRegistry::new();
240 register_item_behaviors(&mut item_behaviors);
241 item_behaviors
242 });
243
244 CONSUME_EFFECT_BEHAVIORS.0.get_or_init(|| {
245 let mut consume_effect_behaviors = ConsumeEffectBehaviorRegistry::new();
246
247 let apply_effects: Box<dyn ConsumeEffectBehavior> = Box::new(ApplyEffectsBehavior);
248 consume_effect_behaviors
249 .set_behavior(&vanilla_consume_effect_types::APPLY_EFFECTS, apply_effects);
250
251 let remove_effects: Box<dyn ConsumeEffectBehavior> = Box::new(RemoveEffectsBehavior);
252 consume_effect_behaviors.set_behavior(
253 &vanilla_consume_effect_types::REMOVE_EFFECTS,
254 remove_effects,
255 );
256
257 let clear_all_effects: Box<dyn ConsumeEffectBehavior> = Box::new(ClearAllEffectsBehavior);
258 consume_effect_behaviors.set_behavior(
259 &vanilla_consume_effect_types::CLEAR_ALL_EFFECTS,
260 clear_all_effects,
261 );
262
263 let play_sound: Box<dyn ConsumeEffectBehavior> = Box::new(PlaySoundBehavior);
264 consume_effect_behaviors
265 .set_behavior(&vanilla_consume_effect_types::PLAY_SOUND, play_sound);
266
267 let teleport_randomly: Box<dyn ConsumeEffectBehavior> = Box::new(TeleportRandomlyBehavior);
268 consume_effect_behaviors.set_behavior(
269 &vanilla_consume_effect_types::TELEPORT_RANDOMLY,
270 teleport_randomly,
271 );
272
273 consume_effect_behaviors
274 });
275
276 MOB_EFFECT_BEHAVIORS.0.get_or_init(|| {
277 let mut mob_effect_behaviors = MobEffectBehaviorRegistry::new();
278
279 let instant_health: Box<dyn MobEffectBehavior> =
281 Box::new(HealOrHarmBehavior { is_harm: false });
282 mob_effect_behaviors.set_behavior(vanilla_mob_effects::INSTANT_HEALTH, instant_health);
283
284 let instant_damage: Box<dyn MobEffectBehavior> =
285 Box::new(HealOrHarmBehavior { is_harm: true });
286 mob_effect_behaviors.set_behavior(vanilla_mob_effects::INSTANT_DAMAGE, instant_damage);
287
288 let saturation: Box<dyn MobEffectBehavior> = Box::new(SaturationBehavior);
289 mob_effect_behaviors.set_behavior(vanilla_mob_effects::SATURATION, saturation);
290
291 let wither: Box<dyn MobEffectBehavior> = Box::new(WitherBehavior);
292 mob_effect_behaviors.set_behavior(vanilla_mob_effects::WITHER, wither);
293
294 let poison: Box<dyn MobEffectBehavior> = Box::new(PoisonBehavior);
295 mob_effect_behaviors.set_behavior(vanilla_mob_effects::POISON, poison);
296
297 let regeneration: Box<dyn MobEffectBehavior> = Box::new(RegenerationBehavior);
298 mob_effect_behaviors.set_behavior(vanilla_mob_effects::REGENERATION, regeneration);
299
300 let hunger: Box<dyn MobEffectBehavior> = Box::new(HungerBehavior);
301 mob_effect_behaviors.set_behavior(vanilla_mob_effects::HUNGER, hunger);
302
303 let absorption: Box<dyn MobEffectBehavior> = Box::new(AbsorptionBehavior);
304 mob_effect_behaviors.set_behavior(vanilla_mob_effects::ABSORPTION, absorption);
305
306 let bad_omen: Box<dyn MobEffectBehavior> = Box::new(BadOmenBehavior);
307 mob_effect_behaviors.set_behavior(vanilla_mob_effects::BAD_OMEN, bad_omen);
308
309 let raid_omen: Box<dyn MobEffectBehavior> = Box::new(RaidOmenBehavior);
310 mob_effect_behaviors.set_behavior(vanilla_mob_effects::RAID_OMEN, raid_omen);
311
312 let oozing: Box<dyn MobEffectBehavior> = Box::new(OozingBehavior);
313 mob_effect_behaviors.set_behavior(vanilla_mob_effects::OOZING, oozing);
314
315 let weaving: Box<dyn MobEffectBehavior> = Box::new(WeavingBehavior);
316 mob_effect_behaviors.set_behavior(vanilla_mob_effects::WEAVING, weaving);
317
318 let wind_charged: Box<dyn MobEffectBehavior> = Box::new(WindChargedBehavior);
319 mob_effect_behaviors.set_behavior(vanilla_mob_effects::WIND_CHARGED, wind_charged);
320
321 let infested: Box<dyn MobEffectBehavior> = Box::new(InfestedBehavior);
322 mob_effect_behaviors.set_behavior(vanilla_mob_effects::INFESTED, infested);
323
324 mob_effect_behaviors
325 });
326}