ghast_protocol/types/
slot.rs1pub mod legacy {
9 use bytes::{BufMut, BytesMut};
10
11 use crate::codec::{Decode, DecodeResult, Encode, EncodeResult, Reader};
12 use crate::error::EncodeError;
13 use crate::nbt::RawNbt;
14
15 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
17 pub struct ItemStack {
18 pub id: i16,
20 pub count: i8,
22 pub damage: i16,
24 pub nbt: Option<RawNbt>,
26 }
27
28 #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
30 pub struct Slot(pub Option<ItemStack>);
31
32 impl Slot {
33 pub const EMPTY: Slot = Slot(None);
35
36 #[inline]
38 pub fn is_empty(&self) -> bool {
39 self.0.is_none()
40 }
41
42 #[inline]
44 pub fn item(&self) -> Option<&ItemStack> {
45 self.0.as_ref()
46 }
47 }
48
49 impl Decode for Slot {
50 #[inline]
51 fn decode(r: &mut Reader<'_>) -> DecodeResult<Self> {
52 let id = r.read_i16()?;
53 if id == -1 {
54 return Ok(Slot(None));
55 }
56 Ok(Slot(Some(ItemStack {
57 id,
58 count: r.read_i8()?,
59 damage: r.read_i16()?,
60 nbt: RawNbt::read_optional(r)?,
61 })))
62 }
63 }
64
65 impl Encode for Slot {
66 #[inline]
67 fn encode(&self, w: &mut BytesMut) -> EncodeResult {
68 match &self.0 {
69 None => w.put_i16(-1),
70 Some(it) => {
71 if it.id == -1 {
72 return Err(EncodeError::Invalid(
73 "item id -1 is reserved for empty slots",
74 ));
75 }
76 w.put_i16(it.id);
77 w.put_i8(it.count);
78 w.put_i16(it.damage);
79 RawNbt::write_optional(&it.nbt, w);
80 }
81 }
82 Ok(())
83 }
84 }
85}
86
87pub mod modern {
90 use bytes::{BufMut, BytesMut};
91
92 use crate::codec::{Decode, DecodeResult, Encode, EncodeResult, McWrite, Reader};
93 use crate::nbt::RawNbt;
94
95 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
97 pub struct ItemStack {
98 pub id: i32,
100 pub count: i8,
102 pub nbt: Option<RawNbt>,
104 }
105
106 #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
108 pub struct Slot(pub Option<ItemStack>);
109
110 impl Slot {
111 pub const EMPTY: Slot = Slot(None);
113
114 #[inline]
116 pub fn is_empty(&self) -> bool {
117 self.0.is_none()
118 }
119
120 #[inline]
122 pub fn item(&self) -> Option<&ItemStack> {
123 self.0.as_ref()
124 }
125 }
126
127 impl Decode for Slot {
128 #[inline]
129 fn decode(r: &mut Reader<'_>) -> DecodeResult<Self> {
130 if !r.read_bool()? {
131 return Ok(Slot(None));
132 }
133 Ok(Slot(Some(ItemStack {
134 id: r.read_varint()?,
135 count: r.read_i8()?,
136 nbt: RawNbt::read_optional(r)?,
137 })))
138 }
139 }
140
141 impl Encode for Slot {
142 #[inline]
143 fn encode(&self, w: &mut BytesMut) -> EncodeResult {
144 match &self.0 {
145 None => w.put_bool(false),
146 Some(it) => {
147 w.put_bool(true);
148 w.put_varint(it.id);
149 w.put_i8(it.count);
150 RawNbt::write_optional(&it.nbt, w);
151 }
152 }
153 Ok(())
154 }
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161 use crate::codec::{Encode, decode_exact};
162 use bytes::{Bytes, BytesMut};
163
164 #[test]
165 fn legacy_known_answers() {
166 let b = Bytes::from_static(&[0xff, 0xff]);
168 assert_eq!(decode_exact::<legacy::Slot>(&b), Ok(legacy::Slot::EMPTY));
169 let b = Bytes::from_static(&[0x00, 0x01, 0x40, 0x00, 0x00, 0x00]);
171 let s = decode_exact::<legacy::Slot>(&b).unwrap();
172 let it = s.item().unwrap();
173 assert_eq!(
174 (it.id, it.count, it.damage, it.nbt.is_none()),
175 (1, 64, 0, true)
176 );
177 let mut w = BytesMut::new();
178 s.encode(&mut w).unwrap();
179 assert_eq!(&w[..], &b[..]);
180 let b = Bytes::from_static(&[0x01, 0x14, 0x01, 0x00, 0x05, 0x0a, 0x00, 0x00, 0x00]);
182 let s = decode_exact::<legacy::Slot>(&b).unwrap();
183 assert_eq!(s.item().unwrap().nbt.as_ref().unwrap().as_bytes().len(), 4);
184 }
185
186 #[test]
187 fn modern_known_answers() {
188 let b = Bytes::from_static(&[0x00]);
189 assert_eq!(decode_exact::<modern::Slot>(&b), Ok(modern::Slot::EMPTY));
190 let b = Bytes::from_static(&[0x01, 0xac, 0x02, 0x10, 0x00]);
191 let s = decode_exact::<modern::Slot>(&b).unwrap();
192 let it = s.item().unwrap();
193 assert_eq!((it.id, it.count), (300, 16));
194 }
195}