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}