1use std::{fmt, io::Read};
4
5use mcproto_codec::error::{CodecError, CodecKind, CodecOperation, InvalidEncodingReason};
6
7use crate::{
8 Float, GlobalPosition, Position, PrefixedOptional, ProtocolEnum, TextComponent, TypeCodec,
9 TypeStructCodec, Uuid, VarInt,
10};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub struct InvalidRegistryIdValue {
15 value: i64,
16}
17
18impl InvalidRegistryIdValue {
19 #[must_use]
21 pub const fn value(self) -> i64 {
22 self.value
23 }
24}
25
26impl fmt::Display for InvalidRegistryIdValue {
27 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
28 write!(
29 formatter,
30 "registry ID must be between 0 and {}, got {}",
31 i32::MAX,
32 self.value
33 )
34 }
35}
36
37impl std::error::Error for InvalidRegistryIdValue {}
38
39macro_rules! registry_id_type {
40 ($(#[$meta:meta])* $name:ident) => {
41 $(#[$meta])*
42 #[repr(transparent)]
43 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
44 pub struct $name(u32);
45
46 impl $name {
47 pub const MAX: u32 = i32::MAX as u32;
49
50 pub const fn new(value: u32) -> Result<Self, InvalidRegistryIdValue> {
52 if value <= Self::MAX {
53 Ok(Self(value))
54 } else {
55 Err(InvalidRegistryIdValue {
56 value: value as i64,
57 })
58 }
59 }
60
61 #[must_use]
63 pub const fn get(self) -> u32 {
64 self.0
65 }
66 }
67
68 impl TryFrom<u32> for $name {
69 type Error = InvalidRegistryIdValue;
70
71 fn try_from(value: u32) -> Result<Self, Self::Error> {
72 Self::new(value)
73 }
74 }
75
76 impl From<$name> for u32 {
77 fn from(value: $name) -> Self {
78 value.get()
79 }
80 }
81
82 impl TypeCodec for $name {
83 fn encode(
84 &self,
85 writer: &mut impl std::io::Write,
86 ) -> Result<(), CodecError> {
87 VarInt(self.0 as i32)
88 .encode(writer)
89 .map_err(|error| error.with_context(CodecKind::RegistryId))
90 }
91
92 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
93 let value = VarInt::decode(reader)
94 .map_err(|error| error.with_context(CodecKind::RegistryId))?
95 .0;
96 if value < 0 {
97 return Err(CodecError::invalid_encoding(
98 CodecKind::RegistryId,
99 0,
100 InvalidEncodingReason::InvalidRegistryId {
101 value,
102 max: i32::MAX,
103 },
104 ));
105 }
106 Ok(Self(value as u32))
107 }
108 }
109 };
110}
111
112registry_id_type!(BlockStateId);
114registry_id_type!(CatVariantId);
116registry_id_type!(CatSoundVariantId);
118registry_id_type!(CowVariantId);
120registry_id_type!(CowSoundVariantId);
122registry_id_type!(WolfVariantId);
124registry_id_type!(WolfSoundVariantId);
126registry_id_type!(FrogVariantId);
128registry_id_type!(PigVariantId);
130registry_id_type!(PigSoundVariantId);
132registry_id_type!(ChickenVariantId);
134registry_id_type!(ChickenSoundVariantId);
136registry_id_type!(ZombieNautilusVariantId);
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
141pub enum InvalidNonAirBlockStateId {
142 Air,
144 OutOfRange(u32),
146}
147
148impl fmt::Display for InvalidNonAirBlockStateId {
149 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
150 match self {
151 Self::Air => formatter.write_str(
152 "block state ID 0 is air and cannot be represented as a present optional state",
153 ),
154 Self::OutOfRange(value) => write!(
155 formatter,
156 "block state ID must be between 1 and {}, got {value}",
157 i32::MAX
158 ),
159 }
160 }
161}
162
163impl std::error::Error for InvalidNonAirBlockStateId {}
164
165#[repr(transparent)]
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
168pub struct NonAirBlockStateId(BlockStateId);
169
170impl NonAirBlockStateId {
171 pub const fn new(value: u32) -> Result<Self, InvalidNonAirBlockStateId> {
173 if value == 0 {
174 Err(InvalidNonAirBlockStateId::Air)
175 } else if value > i32::MAX as u32 {
176 Err(InvalidNonAirBlockStateId::OutOfRange(value))
177 } else {
178 Ok(Self(BlockStateId(value)))
179 }
180 }
181
182 #[must_use]
184 pub const fn get(self) -> u32 {
185 self.0.get()
186 }
187
188 #[must_use]
190 pub const fn block_state_id(self) -> BlockStateId {
191 self.0
192 }
193}
194
195#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
200pub enum OptionalBlockState {
201 #[default]
203 Absent,
204 Present(NonAirBlockStateId),
206}
207
208impl TypeCodec for OptionalBlockState {
209 fn encode(&self, writer: &mut impl std::io::Write) -> Result<(), CodecError> {
210 let value = match self {
211 Self::Absent => 0,
212 Self::Present(state) => state.get() as i32,
213 };
214 VarInt(value)
215 .encode(writer)
216 .map_err(|error| error.with_context(CodecKind::EntityMetadataValue))
217 }
218
219 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
220 let value = VarInt::decode(reader)
221 .map_err(|error| error.with_context(CodecKind::EntityMetadataValue))?
222 .0;
223 match value {
224 0 => Ok(Self::Absent),
225 1.. => Ok(Self::Present(NonAirBlockStateId(BlockStateId(
226 value as u32,
227 )))),
228 _ => Err(CodecError::invalid_encoding(
229 CodecKind::EntityMetadataValue,
230 0,
231 InvalidEncodingReason::InvalidRegistryId {
232 value,
233 max: i32::MAX,
234 },
235 )),
236 }
237 }
238}
239
240#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
242pub struct InvalidOptionalVarIntValue {
243 value: i32,
244}
245
246impl InvalidOptionalVarIntValue {
247 #[must_use]
249 pub const fn value(self) -> i32 {
250 self.value
251 }
252}
253
254impl fmt::Display for InvalidOptionalVarIntValue {
255 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
256 write!(
257 formatter,
258 "Optional VarInt cannot represent present value {}",
259 self.value
260 )
261 }
262}
263
264impl std::error::Error for InvalidOptionalVarIntValue {}
265
266#[repr(transparent)]
272#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
273pub struct OptionalVarInt(Option<i32>);
274
275impl OptionalVarInt {
276 #[must_use]
278 pub const fn none() -> Self {
279 Self(None)
280 }
281
282 pub const fn some(value: i32) -> Result<Self, InvalidOptionalVarIntValue> {
284 if value == -1 || value == i32::MAX {
285 Err(InvalidOptionalVarIntValue { value })
286 } else {
287 Ok(Self(Some(value)))
288 }
289 }
290
291 #[must_use]
293 pub const fn value(self) -> Option<i32> {
294 self.0
295 }
296
297 #[must_use]
299 pub const fn is_some(self) -> bool {
300 self.0.is_some()
301 }
302
303 #[must_use]
305 pub const fn is_none(self) -> bool {
306 self.0.is_none()
307 }
308}
309
310impl TryFrom<Option<i32>> for OptionalVarInt {
311 type Error = InvalidOptionalVarIntValue;
312
313 fn try_from(value: Option<i32>) -> Result<Self, Self::Error> {
314 match value {
315 Some(value) => Self::some(value),
316 None => Ok(Self::none()),
317 }
318 }
319}
320
321impl TypeCodec for OptionalVarInt {
322 fn encode(&self, writer: &mut impl std::io::Write) -> Result<(), CodecError> {
323 let selector = match self.0 {
324 None => 0,
325 Some(value) => value.checked_add(1).ok_or_else(|| {
326 CodecError::invalid_encoding_for_operation(
327 CodecKind::EntityMetadataValue,
328 CodecOperation::Write,
329 0,
330 InvalidEncodingReason::InvalidOptionalVarInt { value },
331 )
332 })?,
333 };
334 VarInt(selector)
335 .encode(writer)
336 .map_err(|error| error.with_context(CodecKind::EntityMetadataValue))
337 }
338
339 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
340 let selector = VarInt::decode(reader)
341 .map_err(|error| error.with_context(CodecKind::EntityMetadataValue))?
342 .0;
343 if selector == 0 {
344 return Ok(Self::none());
345 }
346 let value = selector.checked_sub(1).ok_or_else(|| {
347 CodecError::invalid_encoding(
348 CodecKind::EntityMetadataValue,
349 0,
350 InvalidEncodingReason::InvalidOptionalVarInt { value: selector },
351 )
352 })?;
353 Ok(Self(Some(value)))
354 }
355}
356
357macro_rules! prefixed_optional_metadata_type {
358 ($(#[$meta:meta])* $name:ident, $inner:ty) => {
359 $(#[$meta])*
360 #[repr(transparent)]
361 #[derive(Debug, Clone, PartialEq, TypeStructCodec)]
362 #[type_struct_codec(kind = EntityMetadataValue)]
363 pub struct $name(PrefixedOptional<$inner>);
364
365 impl $name {
366 #[must_use]
368 pub const fn some(value: $inner) -> Self {
369 Self(PrefixedOptional::some(value))
370 }
371
372 #[must_use]
374 pub const fn none() -> Self {
375 Self(PrefixedOptional::none())
376 }
377
378 #[must_use]
380 pub fn value(&self) -> Option<&$inner> {
381 self.0.0.0.as_ref()
382 }
383
384 #[must_use]
386 pub fn into_option(self) -> Option<$inner> {
387 self.0.into_option()
388 }
389
390 #[must_use]
392 pub const fn is_some(&self) -> bool {
393 self.0.is_some()
394 }
395
396 #[must_use]
398 pub const fn is_none(&self) -> bool {
399 self.0.is_none()
400 }
401 }
402
403 impl From<Option<$inner>> for $name {
404 fn from(value: Option<$inner>) -> Self {
405 Self(value.into())
406 }
407 }
408
409 impl From<$name> for Option<$inner> {
410 fn from(value: $name) -> Self {
411 value.into_option()
412 }
413 }
414
415 impl Default for $name {
416 fn default() -> Self {
417 Self::none()
418 }
419 }
420 };
421}
422
423prefixed_optional_metadata_type!(OptionalTextComponent, TextComponent);
425prefixed_optional_metadata_type!(OptionalPosition, Position);
427prefixed_optional_metadata_type!(OptionalLivingEntityReference, Uuid);
429prefixed_optional_metadata_type!(OptionalGlobalPosition, GlobalPosition);
431
432#[derive(Debug, Clone, Copy, PartialEq, Default, TypeStructCodec)]
434#[type_struct_codec(kind = EntityMetadataValue)]
435pub struct Rotations {
436 pub x: Float,
438 pub y: Float,
440 pub z: Float,
442}
443
444#[derive(Debug, Clone, Copy, PartialEq, Default, TypeStructCodec)]
446#[type_struct_codec(kind = EntityMetadataValue)]
447pub struct Vector3 {
448 pub x: Float,
450 pub y: Float,
452 pub z: Float,
454}
455
456#[derive(Debug, Clone, Copy, PartialEq, Default, TypeStructCodec)]
458#[type_struct_codec(kind = EntityMetadataValue)]
459pub struct Quaternion {
460 pub x: Float,
462 pub y: Float,
464 pub z: Float,
466 pub w: Float,
468}
469
470#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ProtocolEnum)]
472#[protocol_enum(repr = VarInt)]
473pub enum Direction {
474 Down = 0,
475 Up = 1,
476 North = 2,
477 South = 3,
478 West = 4,
479 East = 5,
480}
481
482#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ProtocolEnum)]
484#[protocol_enum(repr = VarInt)]
485pub enum Pose {
486 Standing = 0,
487 FallFlying = 1,
488 Sleeping = 2,
489 Swimming = 3,
490 SpinAttack = 4,
491 Sneaking = 5,
492 LongJumping = 6,
493 Dying = 7,
494 Croaking = 8,
495 UsingTongue = 9,
496 Sitting = 10,
497 Roaring = 11,
498 Sniffing = 12,
499 Emerging = 13,
500 Digging = 14,
501 Sliding = 15,
502 Shooting = 16,
503 Inhaling = 17,
504}
505
506#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ProtocolEnum)]
508#[protocol_enum(repr = VarInt)]
509pub enum VillagerType {
510 Desert = 0,
511 Jungle = 1,
512 Plains = 2,
513 Savanna = 3,
514 Snow = 4,
515 Swamp = 5,
516 Taiga = 6,
517}
518
519#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ProtocolEnum)]
521#[protocol_enum(repr = VarInt)]
522pub enum VillagerProfession {
523 None = 0,
524 Armorer = 1,
525 Butcher = 2,
526 Cartographer = 3,
527 Cleric = 4,
528 Farmer = 5,
529 Fisherman = 6,
530 Fletcher = 7,
531 Leatherworker = 8,
532 Librarian = 9,
533 Mason = 10,
534 Nitwit = 11,
535 Shepherd = 12,
536 Toolsmith = 13,
537 Weaponsmith = 14,
538}
539
540#[derive(Debug, Clone, Copy, PartialEq, Eq, TypeStructCodec)]
542#[type_struct_codec(kind = EntityMetadataValue)]
543pub struct VillagerData {
544 pub villager_type: VillagerType,
546 pub profession: VillagerProfession,
548 pub level: VarInt,
550}
551
552#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ProtocolEnum)]
554#[protocol_enum(repr = VarInt)]
555pub enum SnifferState {
556 Idling = 0,
557 FeelingHappy = 1,
558 Scenting = 2,
559 Sniffing = 3,
560 Searching = 4,
561 Digging = 5,
562 Rising = 6,
563}
564
565#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ProtocolEnum)]
567#[protocol_enum(repr = VarInt)]
568pub enum ArmadilloState {
569 Idle = 0,
570 Rolling = 1,
571 Scared = 2,
572 Unrolling = 3,
573}
574
575#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ProtocolEnum)]
577#[protocol_enum(repr = VarInt)]
578pub enum CopperGolemState {
579 Idle = 0,
580 GettingItem = 1,
581 GettingNoItem = 2,
582 DroppingItem = 3,
583 DroppingNoItem = 4,
584}
585
586#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ProtocolEnum)]
588#[protocol_enum(repr = VarInt)]
589pub enum WeatheringCopperState {
590 Unaffected = 0,
591 Exposed = 1,
592 Weathered = 2,
593 Oxidized = 3,
594}
595
596#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ProtocolEnum)]
598#[protocol_enum(repr = VarInt)]
599pub enum HumanoidArm {
600 Left = 0,
601 Right = 1,
602}