mcproto_types/slot/
hashed.rs1use std::io::{Read, Write};
4
5use mcproto_codec::{
6 error::{CodecError, CodecKind},
7 varint::{VarIntRead, VarIntWrite},
8};
9
10use crate::{Boolean, Int, TypeCodec, TypeStructCodec};
11
12use super::{
13 DataComponentType, InvalidItemStack, decode_item_count, decode_item_id, read_length,
14 validate_item_fields, write_length,
15};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TypeStructCodec)]
23#[type_struct_codec(kind = HashedSlot)]
24pub struct HashedDataComponent {
25 pub component_type: DataComponentType,
27 pub data_hash: Int,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct HashedItemStack {
34 pub item_id: u32,
36 pub count: u32,
38 pub components_to_add: Vec<HashedDataComponent>,
40 pub components_to_remove: Vec<DataComponentType>,
42}
43
44impl HashedItemStack {
45 pub fn new(count: u32, item_id: u32) -> Result<Self, InvalidItemStack> {
50 if count == 0 || count > i32::MAX as u32 {
51 return Err(InvalidItemStack::Count(count));
52 }
53 if item_id > i32::MAX as u32 {
54 return Err(InvalidItemStack::ItemId(item_id));
55 }
56 Ok(Self {
57 item_id,
58 count,
59 components_to_add: Vec::new(),
60 components_to_remove: Vec::new(),
61 })
62 }
63}
64
65#[derive(Debug, Clone, PartialEq, Eq, Default)]
97pub enum HashedSlot {
98 #[default]
100 Empty,
101 Item(HashedItemStack),
103}
104
105impl TypeCodec for HashedSlot {
106 fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
107 let Self::Item(item) = self else {
108 return Boolean(false)
109 .encode(writer)
110 .map_err(|error| error.with_context(CodecKind::HashedSlot));
111 };
112
113 validate_item_fields(item.count, item.item_id, CodecKind::HashedSlot)?;
114 Boolean(true)
115 .encode(writer)
116 .map_err(|error| error.with_context(CodecKind::HashedSlot))?;
117 writer
118 .write_varint(item.item_id as i32)
119 .map_err(|error| error.with_context(CodecKind::HashedSlot))?;
120 writer
121 .write_varint(item.count as i32)
122 .map_err(|error| error.with_context(CodecKind::HashedSlot))?;
123 write_length(writer, item.components_to_add.len(), CodecKind::HashedSlot)?;
124 for component in &item.components_to_add {
125 component.encode(writer)?;
126 }
127 write_length(
128 writer,
129 item.components_to_remove.len(),
130 CodecKind::HashedSlot,
131 )?;
132 for component_type in &item.components_to_remove {
133 component_type
134 .encode(writer)
135 .map_err(|error| error.with_context(CodecKind::HashedSlot))?;
136 }
137 Ok(())
138 }
139
140 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
141 let has_item = Boolean::decode(reader)
142 .map_err(|error| error.with_context(CodecKind::HashedSlot))?
143 .0;
144 if !has_item {
145 return Ok(Self::Empty);
146 }
147
148 let item_id = reader
149 .read_varint()
150 .map_err(|error| error.with_context(CodecKind::HashedSlot))?;
151 let item_id = decode_item_id(item_id, CodecKind::HashedSlot)?;
152 let count = reader
153 .read_varint()
154 .map_err(|error| error.with_context(CodecKind::HashedSlot))?;
155 let count = decode_item_count(count, CodecKind::HashedSlot)?;
156
157 let add_count = read_length(reader, CodecKind::HashedSlot)?;
158 let mut components_to_add = Vec::with_capacity(add_count.min(1024));
159 for _ in 0..add_count {
160 components_to_add.push(HashedDataComponent::decode(reader)?);
161 }
162
163 let remove_count = read_length(reader, CodecKind::HashedSlot)?;
164 let mut components_to_remove = Vec::with_capacity(remove_count.min(1024));
165 for _ in 0..remove_count {
166 components_to_remove.push(
167 DataComponentType::decode(reader)
168 .map_err(|error| error.with_context(CodecKind::HashedSlot))?,
169 );
170 }
171
172 Ok(Self::Item(HashedItemStack {
173 item_id,
174 count,
175 components_to_add,
176 components_to_remove,
177 }))
178 }
179}