Skip to main content

steel_core/entity/base/
persistence.rs

1use std::{collections::BTreeSet, sync::Weak};
2
3use glam::DVec3;
4use simdnbt::owned::NbtCompound;
5use text_components::TextComponent;
6use uuid::Uuid;
7
8use super::{DEFAULT_MAX_AIR_SUPPLY, EntityFireFreezeState, MAX_ENTITY_TAGS};
9use crate::world::World;
10
11/// Shared vanilla entity save data that is not part of the movement snapshot.
12#[derive(Debug, Clone, PartialEq)]
13pub struct EntityBaseSaveData {
14    /// Synchronized vanilla `Air`/air supply value.
15    pub air_supply: i32,
16    /// Vanilla dimension-change portal cooldown.
17    pub portal_cooldown: i32,
18    /// Shared vanilla `NoGravity` flag.
19    pub no_gravity: bool,
20    /// Shared vanilla `Invulnerable` flag.
21    pub invulnerable: bool,
22    /// Optional synchronized vanilla custom name.
23    pub custom_name: Option<TextComponent>,
24    /// Synchronized vanilla custom-name visibility flag.
25    pub custom_name_visible: bool,
26    /// Synchronized vanilla silent flag.
27    pub silent: bool,
28    /// Server-owned vanilla glowing tag, projected into the shared flags byte.
29    pub glowing: bool,
30    /// Vanilla scoreboard tags.
31    pub tags: BTreeSet<String>,
32    /// Vanilla custom data component payload.
33    pub custom_data: NbtCompound,
34}
35
36impl EntityBaseSaveData {
37    /// Creates default vanilla base save data.
38    #[must_use]
39    pub fn new() -> Self {
40        Self {
41            air_supply: DEFAULT_MAX_AIR_SUPPLY,
42            portal_cooldown: 0,
43            no_gravity: false,
44            invulnerable: false,
45            custom_name: None,
46            custom_name_visible: false,
47            silent: false,
48            glowing: false,
49            tags: BTreeSet::new(),
50            custom_data: NbtCompound::new(),
51        }
52    }
53
54    /// Adds a scoreboard tag, respecting vanilla's per-entity tag limit.
55    pub fn add_tag(&mut self, tag: String) -> bool {
56        if self.tags.len() >= MAX_ENTITY_TAGS && !self.tags.contains(&tag) {
57            return false;
58        }
59        self.tags.insert(tag)
60    }
61}
62
63impl Default for EntityBaseSaveData {
64    fn default() -> Self {
65        Self::new()
66    }
67}
68
69/// Base fields restored from persistent entity data.
70///
71/// Vanilla loads these fields through `Entity.load` before type-specific
72/// entity data. Keeping them bundled makes the load boundary explicit and
73/// prevents constructor signatures from drifting as base state grows.
74#[derive(Debug, Clone)]
75pub struct EntityBaseLoad {
76    /// Fresh runtime ID from `next_entity_id()`.
77    pub id: i32,
78    /// Restored entity position.
79    pub position: DVec3,
80    /// Persisted entity UUID.
81    pub uuid: Uuid,
82    /// Restored velocity.
83    pub velocity: DVec3,
84    /// Restored yaw and pitch.
85    pub rotation: (f32, f32),
86    /// Restored accumulated fall distance.
87    pub fall_distance: f64,
88    /// Restored vanilla fire/freeze state.
89    pub fire_freeze: EntityFireFreezeState,
90    /// Restored ground-contact flag.
91    pub on_ground: bool,
92    /// Restored shared vanilla save data.
93    pub save_data: EntityBaseSaveData,
94    /// World reference for the loaded entity.
95    pub world: Weak<World>,
96}