Skip to main content

yog_api/mods/storage/
item.rs

1//! Values kept on a stack — the Rust side of a Yog Script item's `saved`
2//! members (`docs/design/storage.md`): bytes by key in the custom data of
3//! what a player holds, so they travel with the stack.
4
5use std::marker::PhantomData;
6
7use yog_data::Schema;
8
9/// A value kept in the data of the stack a player holds, at its key (the
10/// mod's own: `<mod>:<key>`); its default where the stack has none yet.
11///
12/// ```ignore
13/// static CHARGES: ItemData<u32> = ItemData::new("charges");
14/// CHARGES.update(&use_item.player, use_item.off_hand, |n| *n = n.saturating_sub(1));
15/// ```
16pub struct ItemData<T> {
17    key: &'static str,
18    value: PhantomData<fn() -> T>,
19}
20
21impl<T: Schema + Default> ItemData<T> {
22    pub const fn new(key: &'static str) -> Self {
23        ItemData {
24            key,
25            value: PhantomData,
26        }
27    }
28
29    /// The value on the stack `player` holds (`off_hand`: in its other
30    /// hand); its default when the stack has none (or there's no stack).
31    pub fn get(&self, player: &str, off_hand: bool) -> T {
32        crate::event::player::held_item_data(player, off_hand, self.stack_key())
33            .and_then(|r| yog_data::read_bytes(&r.bytes).ok())
34            .unwrap_or_default()
35    }
36
37    /// Puts `value` on the stack `player` holds; false when it holds nothing.
38    pub fn set(&self, player: &str, off_hand: bool, value: &T) -> bool {
39        crate::event::player::set_held_item_data(
40            player,
41            off_hand,
42            self.stack_key(),
43            yog_data::to_bytes(value),
44        )
45    }
46
47    /// The value on the stack `player` holds changed by `change`, and put
48    /// back; what `change` returns, none when it holds nothing.
49    pub fn update<R>(
50        &self,
51        player: &str,
52        off_hand: bool,
53        change: impl FnOnce(&mut T) -> R,
54    ) -> Option<R> {
55        let mut value = self.get(player, off_hand);
56        let out = change(&mut value);
57        self.set(player, off_hand, &value).then_some(out)
58    }
59
60    /// The key in a stack's data: the mod's, then its own (as Yog Script's are).
61    fn stack_key(&self) -> String {
62        format!("{}{}{}", crate::mod_id(), yog_ids::sep::NAMESPACE, self.key)
63    }
64}