1use anyhow::bail;
2use luanti_protocol_derive::{LuantiDeserialize, LuantiSerialize};
3
4use crate::wire::{
5 deser::{Deserialize, DeserializeError, DeserializeResult, Deserializer},
6 ser::{Serialize, SerializeResult, Serializer},
7};
8
9use super::{Array16, v3f};
10
11#[derive(Debug, Clone, PartialEq)]
12#[expect(
13 clippy::large_enum_variant,
14 reason = "// TODO consider `Box`ing variants"
15)]
16pub enum NodeBox {
17 Regular,
18 Fixed(NodeBoxFixed),
19 Wallmounted(NodeBoxWallmounted),
20 Leveled(NodeBoxLeveled),
21 Connected(NodeBoxConnected),
22}
23
24impl Serialize for NodeBox {
25 type Input = Self;
26 fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
27 u8::serialize(&6, ser)?;
29
30 let typ = match value {
31 NodeBox::Regular => 0,
32 NodeBox::Fixed(_) => 1,
33 NodeBox::Wallmounted(_) => 2,
34 NodeBox::Leveled(_) => 3,
35 NodeBox::Connected(_) => 4,
36 };
37 u8::serialize(&typ, ser)?;
38 match value {
39 NodeBox::Regular => Ok(()),
40 NodeBox::Fixed(value) => NodeBoxFixed::serialize(value, ser),
41 NodeBox::Wallmounted(value) => NodeBoxWallmounted::serialize(value, ser),
42 NodeBox::Leveled(value) => NodeBoxLeveled::serialize(value, ser),
43 NodeBox::Connected(value) => NodeBoxConnected::serialize(value, ser),
44 }
45 }
46}
47
48impl Deserialize for NodeBox {
49 type Output = Self;
50 fn deserialize(deser: &mut Deserializer<'_>) -> DeserializeResult<Self> {
51 let ver = u8::deserialize(deser)?;
52 if ver != 6 {
53 bail!(DeserializeError::InvalidValue("Invalid NodeBox ver".into(),));
54 }
55 let typ = u8::deserialize(deser)?;
56 match typ {
57 0 => Ok(NodeBox::Regular),
58 1 => Ok(NodeBox::Fixed(NodeBoxFixed::deserialize(deser)?)),
59 2 => Ok(NodeBox::Wallmounted(NodeBoxWallmounted::deserialize(
60 deser,
61 )?)),
62 3 => Ok(NodeBox::Leveled(NodeBoxLeveled::deserialize(deser)?)),
63 4 => Ok(NodeBox::Connected(NodeBoxConnected::deserialize(deser)?)),
64 _ => bail!(DeserializeError::InvalidValue(
65 "Invalid NodeBox type".into(),
66 )),
67 }
68 }
69}
70
71#[allow(non_camel_case_types, reason = "aligns with the original C++ codebase")]
72#[derive(Debug, Clone, PartialEq, LuantiSerialize, LuantiDeserialize)]
73pub struct aabb3f {
74 pub min_edge: v3f,
75 pub max_edge: v3f,
76}
77
78#[derive(Debug, Clone, PartialEq, LuantiSerialize, LuantiDeserialize)]
79pub struct NodeBoxLeveled {
80 #[wrap(Array16<aabb3f>)]
81 pub fixed: Vec<aabb3f>,
82}
83
84#[derive(Debug, Clone, PartialEq, LuantiSerialize, LuantiDeserialize)]
85pub struct NodeBoxFixed {
86 #[wrap(Array16<aabb3f>)]
87 pub fixed: Vec<aabb3f>,
88}
89
90#[derive(Debug, Clone, PartialEq, LuantiSerialize, LuantiDeserialize)]
91pub struct NodeBoxWallmounted {
92 pub wall_top: aabb3f,
93 pub wall_bottom: aabb3f,
94 pub wall_side: aabb3f,
95}
96
97#[derive(Debug, Clone, PartialEq, LuantiSerialize, LuantiDeserialize)]
98pub struct NodeBoxConnected {
99 #[wrap(Array16<aabb3f>)]
100 pub fixed: Vec<aabb3f>,
101 #[wrap(Array16<aabb3f>)]
102 pub connect_top: Vec<aabb3f>,
103 #[wrap(Array16<aabb3f>)]
104 pub connect_bottom: Vec<aabb3f>,
105 #[wrap(Array16<aabb3f>)]
106 pub connect_front: Vec<aabb3f>,
107 #[wrap(Array16<aabb3f>)]
108 pub connect_left: Vec<aabb3f>,
109 #[wrap(Array16<aabb3f>)]
110 pub connect_back: Vec<aabb3f>,
111 #[wrap(Array16<aabb3f>)]
112 pub connect_right: Vec<aabb3f>,
113 #[wrap(Array16<aabb3f>)]
114 pub disconnected_top: Vec<aabb3f>,
115 #[wrap(Array16<aabb3f>)]
116 pub disconnected_bottom: Vec<aabb3f>,
117 #[wrap(Array16<aabb3f>)]
118 pub disconnected_front: Vec<aabb3f>,
119 #[wrap(Array16<aabb3f>)]
120 pub disconnected_left: Vec<aabb3f>,
121 #[wrap(Array16<aabb3f>)]
122 pub disconnected_back: Vec<aabb3f>,
123 #[wrap(Array16<aabb3f>)]
124 pub disconnected_right: Vec<aabb3f>,
125 #[wrap(Array16<aabb3f>)]
126 pub disconnected: Vec<aabb3f>,
127 #[wrap(Array16<aabb3f>)]
128 pub disconnected_sides: Vec<aabb3f>,
129}