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/waxables.rs"]
55pub mod waxables;
56
57#[expect(warnings)]
58#[rustfmt::skip]
59#[path = "generated/weathering.rs"]
60pub mod weathering;
61
62#[expect(warnings)]
63#[rustfmt::skip]
64#[path = "generated/skull_types.rs"]
65pub mod skull_types;
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, InventoryTickContext,
77 PlacementOrientation, PlacementSource, UseItemContext, UseOnContext,
78};
79pub use fluid::{FLUID_BEHAVIORS, FluidBehaviorRegistry};
80pub(crate) use item::apply_use_remainder;
81pub use item::{ItemBehavior, ItemBehaviorRegistry, ItemUseAnimation, SignApplicator};
82use item_behaviors::register_item_behaviors;
83pub use items::{
84 BlockItem, BucketItem, DefaultItemBehavior, DoubleHighBlockItem, EnderEyeItem, HangingSignItem,
85 ScaffoldingBlockItem, ShieldItem, SolidBucketItem, StandingAndWallBlockItem,
86};
87pub use mob_effect::{MOB_EFFECT_BEHAVIORS, MobEffectBehaviorRegistry};
88use std::ops::Deref;
89use std::sync::OnceLock;
90use steel_registry::blocks::BlockRef;
91use steel_registry::blocks::block_state_ext::BlockStateExt;
92use steel_registry::consume_effect::vanilla_consume_effect_types;
93use steel_registry::fluid::FluidRef;
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;
140
141 fn can_be_replaced_by_fluid(&self, fluid: FluidRef) -> bool;
143
144 fn can_be_replaced(&self, context: &BlockPlaceContext<'_>) -> bool;
146
147 fn is_pathfindable(&self, computation_type: PathComputationType) -> bool;
149
150 fn is_bed(&self) -> bool;
152
153 fn is_liquid_block(&self) -> bool;
155
156 fn is_possible_to_respawn_in_this(&self) -> bool;
158}
159
160impl BlockStateBehaviorExt for BlockStateId {
161 fn is_liquid_container(&self) -> bool {
162 let block = self.get_block();
163 let behavior = BLOCK_BEHAVIORS.get_behavior(block);
164 behavior.is_liquid_container(*self)
165 }
166
167 fn can_be_replaced_by_fluid(&self, fluid: FluidRef) -> bool {
168 let block = self.get_block();
169 let behavior = BLOCK_BEHAVIORS.get_behavior(block);
170 behavior.can_be_replaced_by_fluid(*self, fluid)
171 }
172
173 fn can_be_replaced(&self, context: &BlockPlaceContext<'_>) -> bool {
174 let block = self.get_block();
175 let behavior = BLOCK_BEHAVIORS.get_behavior(block);
176 behavior.can_be_replaced(*self, context)
177 }
178
179 fn is_pathfindable(&self, computation_type: PathComputationType) -> bool {
180 let block = self.get_block();
181 let behavior = BLOCK_BEHAVIORS.get_behavior(block);
182 behavior.is_pathfindable(*self, computation_type)
183 }
184
185 fn is_bed(&self) -> bool {
186 let block = self.get_block();
187 BLOCK_BEHAVIORS.get_behavior(block).is_bed()
188 }
189
190 fn is_liquid_block(&self) -> bool {
191 let block = self.get_block();
192 BLOCK_BEHAVIORS.get_behavior(block).is_liquid_block()
193 }
194
195 fn is_possible_to_respawn_in_this(&self) -> bool {
196 let block = self.get_block();
197 let behavior = BLOCK_BEHAVIORS.get_behavior(block);
198 behavior.is_possible_to_respawn_in_this(*self)
199 }
200}
201
202pub static BLOCK_BEHAVIORS: BlockBehaviorLock = BlockBehaviorLock(OnceLock::new());
206
207pub static ITEM_BEHAVIORS: ItemBehaviorLock = ItemBehaviorLock(OnceLock::new());
211
212pub fn init_behaviors() {
216 BLOCK_BEHAVIORS.0.get_or_init(|| {
217 let mut block_behaviors = BlockBehaviorRegistry::new();
218 register_block_behaviors(&mut block_behaviors);
219 block_behaviors
220 });
221
222 FLUID_BEHAVIORS.0.get_or_init(|| {
223 let mut fluid_behaviors = FluidBehaviorRegistry::new();
224
225 let water_behavior: Box<dyn FluidBehavior> = Box::new(WaterFluid);
227 fluid_behaviors.set_behavior(&vanilla_fluids::WATER, water_behavior);
229 fluid_behaviors.set_behavior(&vanilla_fluids::FLOWING_WATER, Box::new(WaterFluid));
230
231 let lava_behavior: Box<dyn FluidBehavior> = Box::new(LavaFluid);
233 fluid_behaviors.set_behavior(&vanilla_fluids::LAVA, lava_behavior);
234 fluid_behaviors.set_behavior(&vanilla_fluids::FLOWING_LAVA, Box::new(LavaFluid));
235
236 fluid_behaviors
237 });
238
239 ITEM_BEHAVIORS.0.get_or_init(|| {
240 let mut item_behaviors = ItemBehaviorRegistry::new();
241 register_item_behaviors(&mut item_behaviors);
242 item_behaviors
243 });
244
245 CONSUME_EFFECT_BEHAVIORS.0.get_or_init(|| {
246 let mut consume_effect_behaviors = ConsumeEffectBehaviorRegistry::new();
247
248 let apply_effects: Box<dyn ConsumeEffectBehavior> = Box::new(ApplyEffectsBehavior);
249 consume_effect_behaviors
250 .set_behavior(&vanilla_consume_effect_types::APPLY_EFFECTS, apply_effects);
251
252 let remove_effects: Box<dyn ConsumeEffectBehavior> = Box::new(RemoveEffectsBehavior);
253 consume_effect_behaviors.set_behavior(
254 &vanilla_consume_effect_types::REMOVE_EFFECTS,
255 remove_effects,
256 );
257
258 let clear_all_effects: Box<dyn ConsumeEffectBehavior> = Box::new(ClearAllEffectsBehavior);
259 consume_effect_behaviors.set_behavior(
260 &vanilla_consume_effect_types::CLEAR_ALL_EFFECTS,
261 clear_all_effects,
262 );
263
264 let play_sound: Box<dyn ConsumeEffectBehavior> = Box::new(PlaySoundBehavior);
265 consume_effect_behaviors
266 .set_behavior(&vanilla_consume_effect_types::PLAY_SOUND, play_sound);
267
268 let teleport_randomly: Box<dyn ConsumeEffectBehavior> = Box::new(TeleportRandomlyBehavior);
269 consume_effect_behaviors.set_behavior(
270 &vanilla_consume_effect_types::TELEPORT_RANDOMLY,
271 teleport_randomly,
272 );
273
274 consume_effect_behaviors
275 });
276
277 MOB_EFFECT_BEHAVIORS.0.get_or_init(|| {
278 let mut mob_effect_behaviors = MobEffectBehaviorRegistry::new();
279
280 let instant_health: Box<dyn MobEffectBehavior> =
282 Box::new(HealOrHarmBehavior { is_harm: false });
283 mob_effect_behaviors.set_behavior(vanilla_mob_effects::INSTANT_HEALTH, instant_health);
284
285 let instant_damage: Box<dyn MobEffectBehavior> =
286 Box::new(HealOrHarmBehavior { is_harm: true });
287 mob_effect_behaviors.set_behavior(vanilla_mob_effects::INSTANT_DAMAGE, instant_damage);
288
289 let saturation: Box<dyn MobEffectBehavior> = Box::new(SaturationBehavior);
290 mob_effect_behaviors.set_behavior(vanilla_mob_effects::SATURATION, saturation);
291
292 let wither: Box<dyn MobEffectBehavior> = Box::new(WitherBehavior);
293 mob_effect_behaviors.set_behavior(vanilla_mob_effects::WITHER, wither);
294
295 let poison: Box<dyn MobEffectBehavior> = Box::new(PoisonBehavior);
296 mob_effect_behaviors.set_behavior(vanilla_mob_effects::POISON, poison);
297
298 let regeneration: Box<dyn MobEffectBehavior> = Box::new(RegenerationBehavior);
299 mob_effect_behaviors.set_behavior(vanilla_mob_effects::REGENERATION, regeneration);
300
301 let hunger: Box<dyn MobEffectBehavior> = Box::new(HungerBehavior);
302 mob_effect_behaviors.set_behavior(vanilla_mob_effects::HUNGER, hunger);
303
304 let absorption: Box<dyn MobEffectBehavior> = Box::new(AbsorptionBehavior);
305 mob_effect_behaviors.set_behavior(vanilla_mob_effects::ABSORPTION, absorption);
306
307 let bad_omen: Box<dyn MobEffectBehavior> = Box::new(BadOmenBehavior);
308 mob_effect_behaviors.set_behavior(vanilla_mob_effects::BAD_OMEN, bad_omen);
309
310 let raid_omen: Box<dyn MobEffectBehavior> = Box::new(RaidOmenBehavior);
311 mob_effect_behaviors.set_behavior(vanilla_mob_effects::RAID_OMEN, raid_omen);
312
313 let oozing: Box<dyn MobEffectBehavior> = Box::new(OozingBehavior);
314 mob_effect_behaviors.set_behavior(vanilla_mob_effects::OOZING, oozing);
315
316 let weaving: Box<dyn MobEffectBehavior> = Box::new(WeavingBehavior);
317 mob_effect_behaviors.set_behavior(vanilla_mob_effects::WEAVING, weaving);
318
319 let wind_charged: Box<dyn MobEffectBehavior> = Box::new(WindChargedBehavior);
320 mob_effect_behaviors.set_behavior(vanilla_mob_effects::WIND_CHARGED, wind_charged);
321
322 let infested: Box<dyn MobEffectBehavior> = Box::new(InfestedBehavior);
323 mob_effect_behaviors.set_behavior(vanilla_mob_effects::INFESTED, infested);
324
325 mob_effect_behaviors
326 });
327}