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}