steel_core/behavior/block/
context.rs1use super::{
2 Arc, Axis, BlockLocalAabb, BlockPos, BlockStateId, DVec3, DamageSource, Entity, EntityTypeRef,
3 ItemStack, SharedBlockEntity, SmallVec, SoundEventRef, VoxelShape, World, vanilla_entities,
4};
5
6pub struct PickupResult {
7 pub filled_bucket: ItemStack,
8 pub sound: Option<SoundEventRef>,
9}
10
11pub enum BlockEntityCreation {
17 Created(SharedBlockEntity),
19 NoEntity,
21 Unimplemented,
23}
24
25impl BlockEntityCreation {
26 #[must_use]
28 pub fn from_registered_factory(entity: Option<SharedBlockEntity>) -> Self {
29 entity.map_or(Self::Unimplemented, Self::Created)
30 }
31
32 #[must_use]
34 pub fn into_created(self) -> Option<SharedBlockEntity> {
35 match self {
36 Self::Created(entity) => Some(entity),
37 Self::NoEntity | Self::Unimplemented => None,
38 }
39 }
40}
41
42pub trait RailBehavior: Send + Sync {
48 fn is_straight(&self) -> bool;
50}
51
52pub type BlockCollisionBoxes = SmallVec<[BlockLocalAabb; 4]>;
58
59pub struct BlockLootContext<'a> {
65 world: &'a Arc<World>,
66 pos: BlockPos,
67 entity: Option<&'a dyn Entity>,
68 tool: Option<&'a ItemStack>,
69 luck: f32,
70}
71
72impl<'a> BlockLootContext<'a> {
73 #[must_use]
75 pub const fn new(world: &'a Arc<World>, pos: BlockPos) -> Self {
76 Self {
77 world,
78 pos,
79 entity: None,
80 tool: None,
81 luck: 0.0,
82 }
83 }
84
85 #[must_use]
87 pub const fn with_entity(mut self, entity: Option<&'a dyn Entity>) -> Self {
88 self.entity = entity;
89 self
90 }
91
92 #[must_use]
94 pub const fn with_tool(mut self, tool: &'a ItemStack) -> Self {
95 self.tool = Some(tool);
96 self
97 }
98
99 #[must_use]
101 pub const fn with_luck(mut self, luck: f32) -> Self {
102 self.luck = luck;
103 self
104 }
105
106 #[must_use]
108 pub const fn world(&self) -> &'a Arc<World> {
109 self.world
110 }
111
112 #[must_use]
114 pub const fn pos(&self) -> BlockPos {
115 self.pos
116 }
117
118 #[must_use]
120 pub fn get_drops(&self, state: BlockStateId) -> Vec<ItemStack> {
121 World::block_drops(state, self)
122 }
123
124 pub(crate) const fn entity(&self) -> Option<&'a dyn Entity> {
125 self.entity
126 }
127
128 pub(crate) const fn tool(&self) -> Option<&'a ItemStack> {
129 self.tool
130 }
131
132 pub(crate) const fn luck(&self) -> f32 {
133 self.luck
134 }
135}
136
137const COLLISION_CONTEXT_ABOVE_EPSILON: f64 = 1.0e-5;
138
139#[derive(Debug, Clone, Copy, PartialEq)]
141pub struct BlockCollisionContext {
142 entity_bottom: Option<f64>,
143 fall_distance: f64,
144 can_walk_on_powder_snow: bool,
145 is_falling_block: bool,
146 descending: bool,
147 placement: bool,
148}
149
150impl BlockCollisionContext {
151 #[must_use]
153 pub const fn empty() -> Self {
154 Self {
155 entity_bottom: None,
156 fall_distance: 0.0,
157 can_walk_on_powder_snow: false,
158 is_falling_block: false,
159 descending: false,
160 placement: false,
161 }
162 }
163
164 #[must_use]
166 pub const fn entity(entity_bottom: f64, descending: bool) -> Self {
167 Self {
168 entity_bottom: Some(entity_bottom),
169 fall_distance: 0.0,
170 can_walk_on_powder_snow: false,
171 is_falling_block: false,
172 descending,
173 placement: false,
174 }
175 }
176
177 #[must_use]
179 pub const fn pre_move(entity_bottom: f64, descending: bool) -> Self {
180 Self {
181 entity_bottom: Some(entity_bottom),
182 fall_distance: 0.0,
183 can_walk_on_powder_snow: false,
184 is_falling_block: false,
185 descending,
186 placement: true,
187 }
188 }
189
190 #[must_use]
192 pub const fn position_context(y: f64) -> Self {
193 Self {
194 entity_bottom: Some(y),
195 fall_distance: 0.0,
196 can_walk_on_powder_snow: false,
197 is_falling_block: false,
198 descending: false,
199 placement: false,
200 }
201 }
202
203 #[must_use]
205 pub const fn with_fall_distance(mut self, fall_distance: f64) -> Self {
206 self.fall_distance = fall_distance;
207 self
208 }
209
210 #[must_use]
212 pub const fn with_can_walk_on_powder_snow(mut self, can_walk_on_powder_snow: bool) -> Self {
213 self.can_walk_on_powder_snow = can_walk_on_powder_snow;
214 self
215 }
216
217 #[must_use]
219 pub const fn with_falling_block(mut self, is_falling_block: bool) -> Self {
220 self.is_falling_block = is_falling_block;
221 self
222 }
223
224 #[must_use]
226 pub const fn fall_distance(self) -> f64 {
227 self.fall_distance
228 }
229
230 #[must_use]
232 pub const fn can_walk_on_powder_snow(self) -> bool {
233 self.can_walk_on_powder_snow
234 }
235
236 #[must_use]
238 pub const fn is_falling_block(self) -> bool {
239 self.is_falling_block
240 }
241
242 #[must_use]
244 pub const fn is_descending(self) -> bool {
245 self.descending
246 }
247
248 #[must_use]
250 pub const fn is_placement(self) -> bool {
251 self.placement
252 }
253
254 #[must_use]
256 pub fn is_above(self, shape: VoxelShape, pos: BlockPos, default_value: bool) -> bool {
257 let Some(entity_bottom) = self.entity_bottom else {
258 return default_value;
259 };
260
261 entity_bottom > f64::from(pos.y()) + shape.max(Axis::Y) - COLLISION_CONTEXT_ABOVE_EPSILON
262 }
263}
264
265#[derive(Debug, Clone, Copy, PartialEq)]
267pub struct EntityLandingContext {
268 pub velocity: DVec3,
270 pub is_living_entity: bool,
272 pub suppresses_bounce: bool,
274}
275
276#[derive(Debug, Clone, Copy, PartialEq)]
278pub struct EntityFallOnFacts {
279 pub entity_type: EntityTypeRef,
281 pub is_living_entity: bool,
283 pub bounding_box_width: f64,
285 pub bounding_box_height: f64,
287 pub fall_sounds: (SoundEventRef, SoundEventRef),
289}
290
291impl EntityFallOnFacts {
292 #[must_use]
294 pub const fn new(
295 entity_type: EntityTypeRef,
296 is_living_entity: bool,
297 bounding_box_width: f64,
298 bounding_box_height: f64,
299 fall_sounds: (SoundEventRef, SoundEventRef),
300 ) -> Self {
301 Self {
302 entity_type,
303 is_living_entity,
304 bounding_box_width,
305 bounding_box_height,
306 fall_sounds,
307 }
308 }
309
310 #[must_use]
312 pub fn from_entity(entity: &dyn Entity) -> Self {
313 let bounding_box = entity.bounding_box();
314 Self::new(
315 entity.entity_type(),
316 entity.is_living_entity(),
317 bounding_box.width(),
318 bounding_box.height(),
319 entity.fall_sounds(),
320 )
321 }
322
323 #[must_use]
325 pub fn is_player(self) -> bool {
326 self.entity_type == &vanilla_entities::PLAYER
327 }
328
329 #[must_use]
332 pub fn bounding_box_width_squared_height(self) -> f64 {
333 self.bounding_box_width * self.bounding_box_width * self.bounding_box_height
334 }
335}
336
337#[derive(Clone, Copy)]
339pub struct EntityFallOnContext<'a> {
340 pub fall_distance: f64,
342 pub suppresses_bounce: bool,
344 pub entity: EntityFallOnFacts,
346 pub source_entity: Option<&'a dyn Entity>,
348}
349
350impl<'a> EntityFallOnContext<'a> {
351 #[must_use]
353 pub const fn new(
354 fall_distance: f64,
355 suppresses_bounce: bool,
356 entity: EntityFallOnFacts,
357 source_entity: Option<&'a dyn Entity>,
358 ) -> Self {
359 Self {
360 fall_distance,
361 suppresses_bounce,
362 entity,
363 source_entity,
364 }
365 }
366
367 #[must_use]
369 pub fn from_entity(fall_distance: f64, entity: &'a dyn Entity) -> Self {
370 Self::new(
371 fall_distance,
372 entity.is_suppressing_bounce(),
373 EntityFallOnFacts::from_entity(entity),
374 Some(entity),
375 )
376 }
377
378 #[must_use]
380 pub const fn with_fall_distance(mut self, fall_distance: f64) -> Self {
381 self.fall_distance = fall_distance;
382 self
383 }
384
385 #[must_use]
387 pub const fn source_entity(self) -> Option<&'a dyn Entity> {
388 self.source_entity
389 }
390}
391
392#[derive(Debug, Clone)]
394pub struct EntityFallDamage {
395 pub fall_distance: f64,
397 pub damage_modifier: f32,
399 pub source: DamageSource,
401}
402
403impl EntityFallDamage {
404 #[must_use]
406 pub const fn new(fall_distance: f64, damage_modifier: f32, source: DamageSource) -> Self {
407 Self {
408 fall_distance,
409 damage_modifier,
410 source,
411 }
412 }
413}
414
415impl EntityLandingContext {
416 #[must_use]
418 pub const fn new(velocity: DVec3, is_living_entity: bool, suppresses_bounce: bool) -> Self {
419 Self {
420 velocity,
421 is_living_entity,
422 suppresses_bounce,
423 }
424 }
425
426 #[must_use]
428 pub const fn default_velocity_after_fall_on(self) -> DVec3 {
429 DVec3::new(self.velocity.x, 0.0, self.velocity.z)
430 }
431}