1use std::io::{Read, Write};
4
5use mcproto_codec::error::{CodecError, CodecKind, InvalidEncodingReason};
6
7use crate::{Identifier, PrefixedArray, TypeCodec, TypeStructCodec, VarInt};
8
9use super::{Slot, components::DataComponentType};
10
11macro_rules! display_struct {
12 ($(#[$meta:meta])* $name:ident { $($(#[$field_meta:meta])* $field:ident: $ty:ty),* $(,)? }) => {
13 $(#[$meta])*
14 #[derive(Debug, Clone, PartialEq, TypeStructCodec)]
15 #[type_struct_codec(kind = SlotDisplay)]
16 pub struct $name { $($(#[$field_meta])* pub $field: $ty,)* }
17 };
18}
19
20display_struct!(WithAnyPotionSlotDisplay { base: Box<SlotDisplay> });
22display_struct!(OnlyWithComponentSlotDisplay {
24 base: Box<SlotDisplay>,
25 component_type: DataComponentType,
26});
27display_struct!(ItemSlotDisplay { item_type_id: VarInt });
29display_struct!(ItemStackSlotDisplay { item_stack: Slot });
31display_struct!(TagSlotDisplay { tag: Identifier });
33display_struct!(DyedSlotDisplay { dye: Box<SlotDisplay>, target: Box<SlotDisplay> });
35display_struct!(SmithingTrimSlotDisplay {
37 base: Box<SlotDisplay>,
38 material: Box<SlotDisplay>,
39 pattern_id: VarInt,
40});
41display_struct!(WithRemainderSlotDisplay {
43 ingredient: Box<SlotDisplay>,
44 remainder: Box<SlotDisplay>,
45});
46display_struct!(CompositeSlotDisplay { options: PrefixedArray<SlotDisplay> });
48
49#[derive(Debug, Clone, PartialEq)]
77pub enum SlotDisplay {
78 Empty,
79 AnyFuel,
80 WithAnyPotion(WithAnyPotionSlotDisplay),
81 OnlyWithComponent(OnlyWithComponentSlotDisplay),
82 Item(ItemSlotDisplay),
83 ItemStack(ItemStackSlotDisplay),
84 Tag(TagSlotDisplay),
85 Dyed(DyedSlotDisplay),
86 SmithingTrim(SmithingTrimSlotDisplay),
87 WithRemainder(WithRemainderSlotDisplay),
88 Composite(CompositeSlotDisplay),
89}
90
91impl TypeCodec for SlotDisplay {
92 fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
93 let (id, payload): (i32, Option<&dyn EncodableDisplay>) = match self {
94 Self::Empty => (0, None),
95 Self::AnyFuel => (1, None),
96 Self::WithAnyPotion(v) => (2, Some(v)),
97 Self::OnlyWithComponent(v) => (3, Some(v)),
98 Self::Item(v) => (4, Some(v)),
99 Self::ItemStack(v) => (5, Some(v)),
100 Self::Tag(v) => (6, Some(v)),
101 Self::Dyed(v) => (7, Some(v)),
102 Self::SmithingTrim(v) => (8, Some(v)),
103 Self::WithRemainder(v) => (9, Some(v)),
104 Self::Composite(v) => (10, Some(v)),
105 };
106 VarInt(id)
107 .encode(writer)
108 .map_err(|e| e.with_context(CodecKind::SlotDisplay))?;
109 if let Some(payload) = payload {
110 payload
111 .encode_display(writer)
112 .map_err(|e| e.with_context(CodecKind::SlotDisplay))?;
113 }
114 Ok(())
115 }
116
117 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
118 let id = VarInt::decode(reader)
119 .map_err(|e| e.with_context(CodecKind::SlotDisplay))?
120 .0;
121 match id {
122 0 => Ok(Self::Empty),
123 1 => Ok(Self::AnyFuel),
124 2 => Ok(Self::WithAnyPotion(WithAnyPotionSlotDisplay::decode(
125 reader,
126 )?)),
127 3 => Ok(Self::OnlyWithComponent(
128 OnlyWithComponentSlotDisplay::decode(reader)?,
129 )),
130 4 => Ok(Self::Item(ItemSlotDisplay::decode(reader)?)),
131 5 => Ok(Self::ItemStack(ItemStackSlotDisplay::decode(reader)?)),
132 6 => Ok(Self::Tag(TagSlotDisplay::decode(reader)?)),
133 7 => Ok(Self::Dyed(DyedSlotDisplay::decode(reader)?)),
134 8 => Ok(Self::SmithingTrim(SmithingTrimSlotDisplay::decode(reader)?)),
135 9 => Ok(Self::WithRemainder(WithRemainderSlotDisplay::decode(
136 reader,
137 )?)),
138 10 => Ok(Self::Composite(CompositeSlotDisplay::decode(reader)?)),
139 value => Err(CodecError::invalid_encoding(
140 CodecKind::SlotDisplay,
141 0,
142 InvalidEncodingReason::InvalidEnumValue {
143 value: i128::from(value),
144 },
145 )),
146 }
147 }
148}
149
150trait EncodableDisplay {
151 fn encode_display(&self, writer: &mut dyn Write) -> Result<(), CodecError>;
152}
153
154macro_rules! impl_encodable_display {
155 ($($ty:ty),+ $(,)?) => {$(
156 impl EncodableDisplay for $ty {
157 fn encode_display(&self, writer: &mut dyn Write) -> Result<(), CodecError> {
158 struct DynWriter<'a>(&'a mut dyn Write);
159 impl Write for DynWriter<'_> {
160 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { self.0.write(buf) }
161 fn flush(&mut self) -> std::io::Result<()> { self.0.flush() }
162 }
163 self.encode(&mut DynWriter(writer))
164 }
165 }
166 )+};
167}
168
169impl_encodable_display!(
170 WithAnyPotionSlotDisplay,
171 OnlyWithComponentSlotDisplay,
172 ItemSlotDisplay,
173 ItemStackSlotDisplay,
174 TagSlotDisplay,
175 DyedSlotDisplay,
176 SmithingTrimSlotDisplay,
177 WithRemainderSlotDisplay,
178 CompositeSlotDisplay,
179);