1use std::{fmt, io::Read};
4
5use mcproto_codec::error::{CodecError, CodecKind, CodecOperation, InvalidEncodingReason};
6
7use crate::{
8 Boolean, Byte, Float, IdOr, PaintingVariant, Position, PrefixedString, ProtocolEnum,
9 ResolvableProfile, Slot, TextComponent, TypeCodec, UnsignedByte, VarInt, VarLong,
10};
11
12use super::{
13 ArmadilloState, BlockStateId, CatSoundVariantId, CatVariantId, ChickenSoundVariantId,
14 ChickenVariantId, CopperGolemState, CowSoundVariantId, CowVariantId, Direction, FrogVariantId,
15 HumanoidArm, OptionalBlockState, OptionalGlobalPosition, OptionalLivingEntityReference,
16 OptionalPosition, OptionalTextComponent, OptionalVarInt, Particle, Particles,
17 PigSoundVariantId, PigVariantId, Pose, Quaternion, Rotations, SnifferState, Vector3,
18 VillagerData, WeatheringCopperState, WolfSoundVariantId, WolfVariantId,
19 ZombieNautilusVariantId,
20};
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24pub struct InvalidEntityMetadataIndex {
25 index: u8,
26}
27
28impl InvalidEntityMetadataIndex {
29 #[must_use]
31 pub const fn index(self) -> u8 {
32 self.index
33 }
34}
35
36impl fmt::Display for InvalidEntityMetadataIndex {
37 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
38 write!(
39 formatter,
40 "entity metadata index 0x{:02X} is reserved as the terminator",
41 self.index
42 )
43 }
44}
45
46impl std::error::Error for InvalidEntityMetadataIndex {}
47
48#[repr(transparent)]
53#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
54pub struct EntityMetadataIndex(u8);
55
56impl EntityMetadataIndex {
57 pub const MAX: u8 = 0xfe;
59 pub const TERMINATOR: u8 = 0xff;
61
62 pub const fn new(index: u8) -> Result<Self, InvalidEntityMetadataIndex> {
64 if index == Self::TERMINATOR {
65 Err(InvalidEntityMetadataIndex { index })
66 } else {
67 Ok(Self(index))
68 }
69 }
70
71 #[must_use]
73 pub const fn get(self) -> u8 {
74 self.0
75 }
76}
77
78impl TryFrom<u8> for EntityMetadataIndex {
79 type Error = InvalidEntityMetadataIndex;
80
81 fn try_from(value: u8) -> Result<Self, Self::Error> {
82 Self::new(value)
83 }
84}
85
86impl From<EntityMetadataIndex> for u8 {
87 fn from(value: EntityMetadataIndex) -> Self {
88 value.get()
89 }
90}
91
92impl TypeCodec for EntityMetadataIndex {
93 fn encode(&self, writer: &mut impl std::io::Write) -> Result<(), CodecError> {
94 UnsignedByte(self.0)
95 .encode(writer)
96 .map_err(|error| error.with_context(CodecKind::EntityMetadataEntry))
97 }
98
99 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
100 let index = UnsignedByte::decode(reader)
101 .map_err(|error| error.with_context(CodecKind::EntityMetadataEntry))?
102 .0;
103 Self::new(index).map_err(|_| {
104 CodecError::invalid_encoding(
105 CodecKind::EntityMetadataEntry,
106 1,
107 InvalidEncodingReason::InvalidEntityMetadataIndex { index },
108 )
109 })
110 }
111}
112
113macro_rules! define_metadata_values {
114 ($($id:literal => $variant:ident($payload:ty) = $name:literal,)*) => {
115 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ProtocolEnum)]
122 #[protocol_enum(repr = VarInt)]
123 pub enum EntityMetadataValueType {
124 $(
125 #[doc = concat!("The `", $name, "` value type (ID `", stringify!($id), "`).")]
126 $variant = $id,
127 )*
128 }
129
130 #[derive(Debug, Clone, PartialEq)]
135 pub enum EntityMetadataValue {
136 $(
137 #[doc = concat!("A `", $name, "` metadata value.")]
138 $variant($payload),
139 )*
140 }
141
142 impl EntityMetadataValue {
143 #[must_use]
145 pub const fn value_type(&self) -> EntityMetadataValueType {
146 match self {
147 $(Self::$variant(_) => EntityMetadataValueType::$variant,)*
148 }
149 }
150
151 #[must_use]
153 pub fn type_id(&self) -> i32 {
154 self.value_type().discriminant() as i32
155 }
156 }
157
158 impl TypeCodec for EntityMetadataValue {
159 fn encode(
160 &self,
161 writer: &mut impl std::io::Write,
162 ) -> Result<(), CodecError> {
163 self.value_type()
164 .encode(writer)
165 .map_err(with_value_context)?;
166 match self {
167 $(Self::$variant(value) => value.encode(writer).map_err(with_value_context),)*
168 }
169 }
170
171 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
172 let value_type = EntityMetadataValueType::decode(reader)
173 .map_err(with_value_context)?;
174 match value_type {
175 $(
176 EntityMetadataValueType::$variant => <$payload>::decode(reader)
177 .map(Self::$variant)
178 .map_err(with_value_context),
179 )*
180 }
181 }
182 }
183 };
184}
185
186define_metadata_values! {
187 0 => Byte(Byte) = "Byte",
188 1 => VarInt(VarInt) = "VarInt",
189 2 => VarLong(VarLong) = "VarLong",
190 3 => Float(Float) = "Float",
191 4 => String(PrefixedString) = "String",
192 5 => TextComponent(TextComponent) = "Text Component",
193 6 => OptionalTextComponent(OptionalTextComponent) = "Optional Text Component",
194 7 => Slot(Slot) = "Slot",
195 8 => Boolean(Boolean) = "Boolean",
196 9 => Rotations(Rotations) = "Rotations",
197 10 => Position(Position) = "Position",
198 11 => OptionalPosition(OptionalPosition) = "Optional Position",
199 12 => Direction(Direction) = "Direction",
200 13 => OptionalLivingEntityReference(OptionalLivingEntityReference) = "Optional Living Entity Reference",
201 14 => BlockState(BlockStateId) = "Block State",
202 15 => OptionalBlockState(OptionalBlockState) = "Optional Block State",
203 16 => Particle(Particle) = "Particle",
204 17 => Particles(Particles) = "Particles",
205 18 => VillagerData(VillagerData) = "Villager Data",
206 19 => OptionalVarInt(OptionalVarInt) = "Optional VarInt",
207 20 => Pose(Pose) = "Pose",
208 21 => CatVariant(CatVariantId) = "Cat Variant",
209 22 => CatSoundVariant(CatSoundVariantId) = "Cat Sound Variant",
210 23 => CowVariant(CowVariantId) = "Cow Variant",
211 24 => CowSoundVariant(CowSoundVariantId) = "Cow Sound Variant",
212 25 => WolfVariant(WolfVariantId) = "Wolf Variant",
213 26 => WolfSoundVariant(WolfSoundVariantId) = "Wolf Sound Variant",
214 27 => FrogVariant(FrogVariantId) = "Frog Variant",
215 28 => PigVariant(PigVariantId) = "Pig Variant",
216 29 => PigSoundVariant(PigSoundVariantId) = "Pig Sound Variant",
217 30 => ChickenVariant(ChickenVariantId) = "Chicken Variant",
218 31 => ChickenSoundVariant(ChickenSoundVariantId) = "Chicken Sound Variant",
219 32 => ZombieNautilusVariant(ZombieNautilusVariantId) = "Zombie Nautilus Variant",
220 33 => OptionalGlobalPosition(OptionalGlobalPosition) = "Optional Global Position",
221 34 => PaintingVariant(IdOr<PaintingVariant>) = "Painting Variant",
222 35 => SnifferState(SnifferState) = "Sniffer State",
223 36 => ArmadilloState(ArmadilloState) = "Armadillo State",
224 37 => CopperGolemState(CopperGolemState) = "Copper Golem State",
225 38 => WeatheringCopperState(WeatheringCopperState) = "Weathering Copper State",
226 39 => Vector3(Vector3) = "Vector3",
227 40 => Quaternion(Quaternion) = "Quaternion",
228 41 => ResolvableProfile(ResolvableProfile) = "Resolvable Profile",
229 42 => HumanoidArm(HumanoidArm) = "Humanoid Arm",
230}
231
232fn with_value_context(error: CodecError) -> CodecError {
233 if error.context() == Some(CodecKind::EntityMetadataValue) {
234 error
235 } else {
236 error.with_context(CodecKind::EntityMetadataValue)
237 }
238}
239
240#[derive(Debug, Clone, PartialEq)]
242pub struct EntityMetadataEntry {
243 index: EntityMetadataIndex,
244 value: EntityMetadataValue,
245}
246
247impl EntityMetadataEntry {
248 #[must_use]
250 pub const fn new(index: EntityMetadataIndex, value: EntityMetadataValue) -> Self {
251 Self { index, value }
252 }
253
254 pub fn try_new(
256 index: u8,
257 value: EntityMetadataValue,
258 ) -> Result<Self, InvalidEntityMetadataIndex> {
259 Ok(Self::new(EntityMetadataIndex::new(index)?, value))
260 }
261
262 #[must_use]
264 pub const fn index(&self) -> EntityMetadataIndex {
265 self.index
266 }
267
268 #[must_use]
270 pub const fn value(&self) -> &EntityMetadataValue {
271 &self.value
272 }
273
274 #[must_use]
276 pub fn into_value(self) -> EntityMetadataValue {
277 self.value
278 }
279}
280
281impl TypeCodec for EntityMetadataEntry {
282 fn encode(&self, writer: &mut impl std::io::Write) -> Result<(), CodecError> {
283 self.index.encode(writer)?;
284 self.value
285 .encode(writer)
286 .map_err(|error| error.with_context(CodecKind::EntityMetadataEntry))
287 }
288
289 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
290 let index = EntityMetadataIndex::decode(reader)?;
291 let value = EntityMetadataValue::decode(reader)
292 .map_err(|error| error.with_context(CodecKind::EntityMetadataEntry))?;
293 Ok(Self { index, value })
294 }
295}
296
297#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
299pub struct DuplicateEntityMetadataIndex {
300 index: EntityMetadataIndex,
301}
302
303impl DuplicateEntityMetadataIndex {
304 #[must_use]
306 pub const fn index(self) -> EntityMetadataIndex {
307 self.index
308 }
309}
310
311impl fmt::Display for DuplicateEntityMetadataIndex {
312 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
313 write!(
314 formatter,
315 "duplicate entity metadata index {}",
316 self.index.get()
317 )
318 }
319}
320
321impl std::error::Error for DuplicateEntityMetadataIndex {}
322
323#[derive(Debug, Clone, PartialEq, Default)]
355pub struct EntityMetadata {
356 entries: Vec<EntityMetadataEntry>,
357}
358
359impl EntityMetadata {
360 pub fn new(entries: Vec<EntityMetadataEntry>) -> Result<Self, DuplicateEntityMetadataIndex> {
362 validate_unique_indices(&entries)?;
363 Ok(Self { entries })
364 }
365
366 #[must_use]
368 pub fn entries(&self) -> &[EntityMetadataEntry] {
369 &self.entries
370 }
371
372 #[must_use]
374 pub fn into_entries(self) -> Vec<EntityMetadataEntry> {
375 self.entries
376 }
377
378 #[must_use]
380 pub const fn len(&self) -> usize {
381 self.entries.len()
382 }
383
384 #[must_use]
386 pub const fn is_empty(&self) -> bool {
387 self.entries.is_empty()
388 }
389
390 #[must_use]
392 pub fn get(&self, index: EntityMetadataIndex) -> Option<&EntityMetadataEntry> {
393 self.entries.iter().find(|entry| entry.index == index)
394 }
395
396 pub fn push(&mut self, entry: EntityMetadataEntry) -> Result<(), DuplicateEntityMetadataIndex> {
398 if self.get(entry.index).is_some() {
399 return Err(DuplicateEntityMetadataIndex { index: entry.index });
400 }
401 self.entries.push(entry);
402 Ok(())
403 }
404}
405
406impl TypeCodec for EntityMetadata {
407 fn encode(&self, writer: &mut impl std::io::Write) -> Result<(), CodecError> {
408 if let Err(error) = validate_unique_indices(&self.entries) {
409 return Err(CodecError::invalid_encoding_for_operation(
410 CodecKind::EntityMetadata,
411 CodecOperation::Write,
412 0,
413 InvalidEncodingReason::DuplicateEntityMetadataIndex {
414 index: error.index.get(),
415 },
416 ));
417 }
418 for entry in &self.entries {
419 entry
420 .encode(writer)
421 .map_err(|error| error.with_context(CodecKind::EntityMetadata))?;
422 }
423 UnsignedByte(EntityMetadataIndex::TERMINATOR)
424 .encode(writer)
425 .map_err(|error| error.with_context(CodecKind::EntityMetadata))
426 }
427
428 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
429 let mut entries = Vec::new();
430 let mut seen = [false; EntityMetadataIndex::TERMINATOR as usize];
431 loop {
432 let index = UnsignedByte::decode(reader)
433 .map_err(|error| error.with_context(CodecKind::EntityMetadata))?
434 .0;
435 if index == EntityMetadataIndex::TERMINATOR {
436 return Ok(Self { entries });
437 }
438 if seen[index as usize] {
439 return Err(CodecError::invalid_encoding(
440 CodecKind::EntityMetadata,
441 0,
442 InvalidEncodingReason::DuplicateEntityMetadataIndex { index },
443 ));
444 }
445 seen[index as usize] = true;
446 let value = EntityMetadataValue::decode(reader)
447 .map_err(|error| error.with_context(CodecKind::EntityMetadataEntry))
448 .map_err(|error| error.with_context(CodecKind::EntityMetadata))?;
449 entries.push(EntityMetadataEntry {
450 index: EntityMetadataIndex(index),
451 value,
452 });
453 }
454 }
455}
456
457fn validate_unique_indices(
458 entries: &[EntityMetadataEntry],
459) -> Result<(), DuplicateEntityMetadataIndex> {
460 let mut seen = [false; EntityMetadataIndex::TERMINATOR as usize];
461 for entry in entries {
462 let index = entry.index.get() as usize;
463 if seen[index] {
464 return Err(DuplicateEntityMetadataIndex { index: entry.index });
465 }
466 seen[index] = true;
467 }
468 Ok(())
469}