steel_core/behavior/blocks/building/
slime_block.rs1use std::sync::Arc;
2
3use glam::DVec3;
4use steel_macros::block_behavior;
5use steel_registry::{blocks::BlockRef, vanilla_damage_types};
6use steel_utils::{BlockPos, BlockStateId};
7
8use crate::{
9 behavior::{BlockBehavior, BlockPlaceContext, EntityFallDamage, EntityFallOnContext},
10 entity::{Entity, damage::DamageSource},
11 world::World,
12};
13
14#[block_behavior]
16pub struct SlimeBlock {
17 block: BlockRef,
18}
19
20impl SlimeBlock {
21 #[must_use]
23 pub const fn new(block: BlockRef) -> Self {
24 Self { block }
25 }
26
27 #[must_use]
28 fn velocity_after_step_on(velocity: DVec3, is_stepping_carefully: bool) -> DVec3 {
29 let abs_delta_y = velocity.y.abs();
30 if abs_delta_y >= 0.1 || is_stepping_carefully {
31 return velocity;
32 }
33
34 let scale = 0.4 + abs_delta_y * 0.2;
35 DVec3::new(velocity.x * scale, velocity.y, velocity.z * scale)
36 }
37}
38
39impl BlockBehavior for SlimeBlock {
40 fn get_state_for_placement(&self, _context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
41 Some(self.block.default_state())
42 }
43
44 fn fall_on(
45 &self,
46 _state: BlockStateId,
47 _world: &Arc<World>,
48 _pos: BlockPos,
49 context: EntityFallOnContext<'_>,
50 ) -> Option<EntityFallDamage> {
51 if context.suppresses_bounce {
52 None
53 } else {
54 Some(EntityFallDamage::new(
55 context.fall_distance,
56 0.0,
57 DamageSource::environment(&vanilla_damage_types::FALL),
58 ))
59 }
60 }
61
62 fn step_on(&self, state: BlockStateId, world: &Arc<World>, pos: BlockPos, entity: &dyn Entity) {
63 entity.set_velocity(Self::velocity_after_step_on(
64 entity.velocity(),
65 entity.is_stepping_carefully(),
66 ));
67
68 self.default_step_on(state, world, pos, entity);
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn step_on_damps_horizontal_velocity_for_non_careful_entities() {
78 let velocity = SlimeBlock::velocity_after_step_on(DVec3::new(1.0, 0.05, -2.0), false);
79
80 assert!((velocity - DVec3::new(0.41, 0.05, -0.82)).length() < 1.0e-12);
81 }
82
83 #[test]
84 fn step_on_keeps_velocity_for_careful_entities() {
85 let velocity = DVec3::new(1.0, 0.05, -2.0);
86
87 assert_eq!(SlimeBlock::velocity_after_step_on(velocity, true), velocity);
88 }
89
90 #[test]
91 fn step_on_keeps_horizontal_velocity_when_vertical_speed_is_large() {
92 let velocity = DVec3::new(1.0, -0.1, -2.0);
93
94 assert_eq!(
95 SlimeBlock::velocity_after_step_on(velocity, false),
96 velocity
97 );
98 }
99}