Skip to main content

steel_registry/data_components/components/
cooking_fuel.rs

1//! Vanilla `minecraft:cooking_fuel` item component.
2
3use std::io::{Cursor, Result, Write};
4
5use simdnbt::owned::{NbtCompound, NbtTag};
6use simdnbt::{FromNbtTag, ToNbtTag};
7use steel_utils::Identifier;
8use steel_utils::hash::{ComponentHasher, HashComponent, HashEntry, sort_map_entries};
9use steel_utils::serial::{ReadFrom, WriteTo};
10
11/// References to the context int/float providers that give a fuel item its
12/// burn time and cooking-speed multiplier.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct CookingFuel {
15    pub burn_time: Identifier,
16    pub speed_multiplier: Identifier,
17}
18
19impl CookingFuel {
20    #[must_use]
21    pub const fn new(burn_time: Identifier, speed_multiplier: Identifier) -> Self {
22        Self {
23            burn_time,
24            speed_multiplier,
25        }
26    }
27}
28
29impl WriteTo for CookingFuel {
30    fn write(&self, writer: &mut impl Write) -> Result<()> {
31        self.burn_time.write(writer)?;
32        self.speed_multiplier.write(writer)
33    }
34}
35
36impl ReadFrom for CookingFuel {
37    fn read(data: &mut Cursor<&[u8]>) -> Result<Self> {
38        Ok(Self {
39            burn_time: Identifier::read(data)?,
40            speed_multiplier: Identifier::read(data)?,
41        })
42    }
43}
44
45impl ToNbtTag for CookingFuel {
46    fn to_nbt_tag(self) -> NbtTag {
47        let mut compound = NbtCompound::new();
48        compound.insert("burn_time", self.burn_time.to_nbt_tag());
49        compound.insert("speed_multiplier", self.speed_multiplier.to_nbt_tag());
50        NbtTag::Compound(compound)
51    }
52}
53
54impl FromNbtTag for CookingFuel {
55    fn from_nbt_tag(tag: simdnbt::borrow::NbtTag) -> Option<Self> {
56        let compound = tag.compound()?;
57        let burn_time = Identifier::from_nbt_tag(compound.get("burn_time")?)?;
58        let speed_multiplier = Identifier::from_nbt_tag(compound.get("speed_multiplier")?)?;
59        Some(Self {
60            burn_time,
61            speed_multiplier,
62        })
63    }
64}
65
66impl HashComponent for CookingFuel {
67    fn hash_component(&self, hasher: &mut ComponentHasher) {
68        let mut entries = Vec::with_capacity(2);
69        push_hash_entry(&mut entries, "burn_time", &self.burn_time);
70        push_hash_entry(&mut entries, "speed_multiplier", &self.speed_multiplier);
71        sort_map_entries(&mut entries);
72        hasher.start_map();
73        for entry in entries {
74            hasher.put_raw_bytes(&entry.key_bytes);
75            hasher.put_raw_bytes(&entry.value_bytes);
76        }
77        hasher.end_map();
78    }
79}
80
81fn push_hash_entry<T: HashComponent + ?Sized>(entries: &mut Vec<HashEntry>, key: &str, value: &T) {
82    let mut key_hasher = ComponentHasher::new();
83    key_hasher.put_string(key);
84    let mut value_hasher = ComponentHasher::new();
85    value.hash_component(&mut value_hasher);
86    entries.push(HashEntry::new(key_hasher, value_hasher));
87}
88
89#[cfg(test)]
90mod tests {
91    use std::io::Cursor;
92
93    use simdnbt::FromNbtTag as _;
94    use simdnbt::ToNbtTag as _;
95    use simdnbt::borrow::read_tag;
96    use simdnbt::owned::NbtTag;
97    use steel_utils::Identifier;
98    use steel_utils::serial::{ReadFrom as _, WriteTo as _};
99
100    use super::CookingFuel;
101
102    fn parse(tag: NbtTag) -> Option<CookingFuel> {
103        let mut bytes = Vec::new();
104        tag.write(&mut bytes);
105        let borrowed = read_tag(&mut Cursor::new(bytes.as_slice())).ok()?;
106        CookingFuel::from_nbt_tag(borrowed.as_tag())
107    }
108
109    #[test]
110    fn round_trips_both_codecs() {
111        let value = CookingFuel::new(
112            Identifier::vanilla_static("cooking/time_wood_blocks"),
113            Identifier::vanilla_static("cooking/speed_default"),
114        );
115
116        let nbt = value.clone().to_nbt_tag();
117        assert_eq!(parse(nbt), Some(value.clone()));
118
119        let mut network = Vec::new();
120        value.write(&mut network).expect("fuel should encode");
121        assert_eq!(
122            CookingFuel::read(&mut Cursor::new(network.as_slice())).expect("fuel should decode"),
123            value
124        );
125    }
126}