Skip to main content

steel_core/entity/pushing/
snapshot.rs

1use glam::DVec3;
2
3use super::EntityPush;
4use crate::entity::{Entity, LivingEntity};
5
6/// Vanilla push and cramming behavior with no overrides. Implementors only read state,
7/// only write velocity and the velocity sync flag, and never re-enter the entity manager.
8/// Entities that override contact, velocity or cramming hooks must not opt in.
9pub trait DefaultEntityPush: Entity {
10    /// Push inputs for one contact, or `None` while riding. `known_pushable` skips the
11    /// `is_pushable` check when the selector has already passed this entity.
12    fn push_snapshot(&self, known_pushable: bool) -> Option<EntityPushSnapshot> {
13        let state = self.base().unmounted_push_state()?;
14
15        Some(EntityPushSnapshot {
16            position: state.position,
17            no_physics: state.no_physics,
18            receives_impulse: !state.is_vehicle && (known_pushable || self.is_pushable()),
19            sleeping: self
20                .as_living_entity()
21                .is_some_and(LivingEntity::is_sleeping),
22        })
23    }
24}
25
26/// Saved inputs for one push contact.
27#[derive(Clone, Copy, Debug)]
28pub struct EntityPushSnapshot {
29    position: DVec3,
30    no_physics: bool,
31    receives_impulse: bool,
32    sleeping: bool,
33}
34
35impl EntityPush {
36    pub(super) fn apply_contact(
37        source: &dyn Entity,
38        source_state: EntityPushSnapshot,
39        target: &dyn Entity,
40        target_state: EntityPushSnapshot,
41    ) {
42        if source_state.sleeping || source_state.no_physics || target_state.no_physics {
43            return;
44        }
45
46        let Some(impulse) = Self::impulse(source_state.position, target_state.position) else {
47            return;
48        };
49
50        if source_state.receives_impulse {
51            source
52                .base()
53                .push_impulse(DVec3::new(-impulse.x, 0.0, -impulse.z));
54        }
55
56        if target_state.receives_impulse {
57            target.base().push_impulse(impulse);
58        }
59    }
60}