Skip to main content

yog_api/mods/storage/
entity.rs

1//! Values kept on an entity — the Rust side of a Yog Script entity's
2//! `saved` and `synced` members (`docs/design/storage.md`): the runtime's
3//! entity data, at the same `<mod>:<key>` keys — saved with the entity,
4//! sent to the players who see it, gone with it.
5
6use std::marker::PhantomData;
7
8use yog_data::Schema;
9
10/// A value kept on each entity, by uuid, at its key (the mod's own:
11/// `<mod>:<key>`); its default where the entity has none yet.
12///
13/// ```ignore
14/// static HITS: EntityData<u32> = EntityData::new("hits");
15/// HITS.with_mut(&damage.uuid, |n| *n += 1);
16/// ```
17pub struct EntityData<T> {
18    key: &'static str,
19    persist: bool,
20    value: PhantomData<fn() -> T>,
21}
22
23impl<T: Schema + Default> EntityData<T> {
24    /// Saved with the entity.
25    pub const fn new(key: &'static str) -> Self {
26        EntityData {
27            key,
28            persist: true,
29            value: PhantomData,
30        }
31    }
32
33    /// Kept while the entity is loaded, not saved (a Yog Script member
34    /// `synced` and not `saved`).
35    pub const fn session(key: &'static str) -> Self {
36        EntityData {
37            key,
38            persist: false,
39            value: PhantomData,
40        }
41    }
42
43    /// What `read` makes of entity `uuid`'s value: the server's where it
44    /// runs here, else what this client was sent.
45    pub fn with<R>(&self, uuid: &str, read: impl FnOnce(&T) -> R) -> R {
46        let key = self.entity_key();
47        let bytes =
48            crate::event::entity::data(uuid, &key).or_else(|| crate::body::entity_data(uuid, &key));
49        read(
50            &bytes
51                .and_then(|b| yog_data::read_bytes(&b).ok())
52                .unwrap_or_default(),
53        )
54    }
55
56    /// Entity `uuid`'s value changed by `change`, and set (server side:
57    /// sent to the players who see it by the tick's end).
58    pub fn with_mut<R>(&self, uuid: &str, change: impl FnOnce(&mut T) -> R) -> R {
59        let key = self.entity_key();
60        let mut value: T = crate::event::entity::data(uuid, &key)
61            .and_then(|b| yog_data::read_bytes(&b).ok())
62            .unwrap_or_default();
63        let out = change(&mut value);
64        crate::event::entity::set_data(uuid, key, Some(&yog_data::to_bytes(&value)), self.persist);
65        out
66    }
67
68    /// The key in an entity's data: the mod's, then its own (as Yog Script's are).
69    fn entity_key(&self) -> String {
70        format!("{}{}{}", crate::mod_id(), yog_ids::sep::NAMESPACE, self.key)
71    }
72}