1use std::io;
8
9use steel_utils::{
10 PackedBlockPos,
11 codec::{VarInt, VarLong},
12 serial::{PrefixedWrite, WriteTo},
13};
14
15use steel_utils::Identifier;
16
17use super::{EntityData, EntityDataSerializerRegistry, ParticleData, ParticleOptions};
18
19macro_rules! ser_write {
21 ($name:ident, $variant:ident) => {
22 fn $name(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
23 match data {
24 EntityData::$variant(v) => v.write(buf),
25 _ => Err(io::Error::other(concat!("Expected ", stringify!($variant)))),
26 }
27 }
28 };
29}
30
31macro_rules! ser_varint {
33 ($name:ident, $variant:ident) => {
34 fn $name(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
35 match data {
36 EntityData::$variant(v) => VarInt(*v).write(buf),
37 _ => Err(io::Error::other(concat!("Expected ", stringify!($variant)))),
38 }
39 }
40 };
41}
42
43macro_rules! ser_enum_varint {
45 ($name:ident, $variant:ident) => {
46 fn $name(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
47 match data {
48 EntityData::$variant(v) => VarInt(*v as i32).write(buf),
49 _ => Err(io::Error::other(concat!("Expected ", stringify!($variant)))),
50 }
51 }
52 };
53}
54
55ser_write!(ser_byte, Byte);
57ser_write!(ser_float, Float);
58ser_write!(ser_component, Component);
59ser_write!(ser_item_stack, ItemStack);
60ser_write!(ser_boolean, Boolean);
61ser_write!(ser_block_state, BlockState);
62
63ser_varint!(ser_int, Int);
65ser_varint!(ser_cat_variant, CatVariant);
66ser_varint!(ser_cat_sound_variant, CatSoundVariant);
67ser_varint!(ser_cow_variant, CowVariant);
68ser_varint!(ser_cow_sound_variant, CowSoundVariant);
69ser_varint!(ser_wolf_variant, WolfVariant);
70ser_varint!(ser_wolf_sound_variant, WolfSoundVariant);
71ser_varint!(ser_frog_variant, FrogVariant);
72ser_varint!(ser_pig_variant, PigVariant);
73ser_varint!(ser_pig_sound_variant, PigSoundVariant);
74ser_varint!(ser_chicken_variant, ChickenVariant);
75ser_varint!(ser_chicken_sound_variant, ChickenSoundVariant);
76ser_varint!(ser_zombie_nautilus_variant, ZombieNautilusVariant);
77ser_varint!(ser_painting_variant, PaintingVariant);
78ser_varint!(ser_copper_golem_state, CopperGolemState);
79ser_varint!(ser_weathering_copper_state, WeatheringCopperState);
80
81ser_enum_varint!(ser_direction, Direction);
83ser_enum_varint!(ser_pose, Pose);
84ser_enum_varint!(ser_sniffer_state, SnifferState);
85ser_enum_varint!(ser_armadillo_state, ArmadilloState);
86
87fn ser_long(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
88 match data {
89 EntityData::Long(v) => VarLong(*v).write(buf),
90 _ => Err(io::Error::other("Expected Long")),
91 }
92}
93
94fn ser_string(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
95 match data {
96 EntityData::String(v) => v.write_prefixed::<VarInt>(buf),
97 _ => Err(io::Error::other("Expected String")),
98 }
99}
100
101fn ser_optional_component(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
102 match data {
103 EntityData::OptionalComponent(v) => match v {
104 Some(comp) => {
105 true.write(buf)?;
106 comp.write(buf)
107 }
108 None => false.write(buf),
109 },
110 _ => Err(io::Error::other("Expected OptionalComponent")),
111 }
112}
113
114fn ser_rotations(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
115 match data {
116 EntityData::Rotations(v) => {
117 v.x.write(buf)?;
118 v.y.write(buf)?;
119 v.z.write(buf)
120 }
121 _ => Err(io::Error::other("Expected Rotations")),
122 }
123}
124
125fn ser_block_pos(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
126 match data {
127 EntityData::BlockPos(v) => PackedBlockPos::from(*v).write(buf),
128 _ => Err(io::Error::other("Expected BlockPos")),
129 }
130}
131
132fn ser_optional_block_pos(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
133 match data {
134 EntityData::OptionalBlockPos(v) => match v {
135 Some(pos) => {
136 true.write(buf)?;
137 PackedBlockPos::from(*pos).write(buf)
138 }
139 None => false.write(buf),
140 },
141 _ => Err(io::Error::other("Expected OptionalBlockPos")),
142 }
143}
144
145fn ser_optional_living_entity_reference(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
146 match data {
147 EntityData::OptionalLivingEntityRef(v) => match v {
148 Some(uuid) => {
149 true.write(buf)?;
150 uuid.write(buf)
151 }
152 None => false.write(buf),
153 },
154 _ => Err(io::Error::other("Expected OptionalLivingEntityRef")),
155 }
156}
157
158fn ser_optional_block_state(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
159 match data {
160 EntityData::OptionalBlockState(v) => {
161 match v {
163 Some(state) => VarInt(i32::from(state.0)).write(buf),
164 None => VarInt(0).write(buf),
165 }
166 }
167 _ => Err(io::Error::other("Expected OptionalBlockState")),
168 }
169}
170
171fn write_particle(particle: &ParticleData, buf: &mut Vec<u8>) -> io::Result<()> {
172 VarInt(particle.particle_type).write(buf)?;
173 match &particle.options {
174 ParticleOptions::None => Ok(()),
175 ParticleOptions::Color { color } => color.write(buf),
176 }
177}
178
179fn ser_particle(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
180 match data {
181 EntityData::Particle(v) => write_particle(v, buf),
182 _ => Err(io::Error::other("Expected Particle")),
183 }
184}
185
186fn ser_particles(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
187 match data {
188 EntityData::Particles(v) => {
189 VarInt(v.particles.len() as i32).write(buf)?;
190 for particle in &v.particles {
191 write_particle(particle, buf)?;
192 }
193 Ok(())
194 }
195 _ => Err(io::Error::other("Expected Particles")),
196 }
197}
198
199fn ser_villager_data(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
200 match data {
201 EntityData::VillagerData(v) => {
202 VarInt(v.villager_type).write(buf)?;
203 VarInt(v.profession).write(buf)?;
204 VarInt(v.level).write(buf)
205 }
206 _ => Err(io::Error::other("Expected VillagerData")),
207 }
208}
209
210fn ser_optional_unsigned_int(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
211 match data {
212 EntityData::OptionalUnsignedInt(v) => {
213 VarInt(v.map(|x| x as i32 + 1).unwrap_or(0)).write(buf)
215 }
216 _ => Err(io::Error::other("Expected OptionalUnsignedInt")),
217 }
218}
219
220fn ser_optional_global_pos(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
221 match data {
222 EntityData::OptionalGlobalPos(v) => match v {
223 Some(global_pos) => {
224 true.write(buf)?;
225 global_pos.dimension.write(buf)?;
226 PackedBlockPos::from(global_pos.pos).write(buf)
227 }
228 None => false.write(buf),
229 },
230 _ => Err(io::Error::other("Expected OptionalGlobalPos")),
231 }
232}
233
234fn ser_vector3(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
235 match data {
236 EntityData::Vector3(v) => {
237 v.x.write(buf)?;
238 v.y.write(buf)?;
239 v.z.write(buf)
240 }
241 _ => Err(io::Error::other("Expected Vector3")),
242 }
243}
244
245fn ser_quaternion(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
246 match data {
247 EntityData::Quaternion(v) => {
248 v.x.write(buf)?;
249 v.y.write(buf)?;
250 v.z.write(buf)?;
251 v.w.write(buf)
252 }
253 _ => Err(io::Error::other("Expected Quaternion")),
254 }
255}
256
257fn ser_resolvable_profile(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
258 match data {
259 EntityData::ResolvableProfile(_v) => {
260 false.write(buf)?;
263 false.write(buf)?;
264 false.write(buf)?;
265 VarInt(0).write(buf)?;
266 false.write(buf)?;
267 false.write(buf)?;
268 false.write(buf)?;
269 false.write(buf)
270 }
271 _ => Err(io::Error::other("Expected ResolvableProfile")),
272 }
273}
274
275fn ser_humanoid_arm(data: &EntityData, buf: &mut Vec<u8>) -> io::Result<()> {
276 match data {
277 EntityData::HumanoidArm(v) => VarInt(*v as i32).write(buf),
279 _ => Err(io::Error::other("Expected HumanoidArm")),
280 }
281}
282
283pub fn register_vanilla_entity_data_serializers(registry: &mut EntityDataSerializerRegistry) {
288 macro_rules! reg {
291 ($name:literal, $writer:expr) => {
292 registry.register(Identifier::vanilla_static($name), $writer);
293 };
294 }
295
296 reg!("byte", ser_byte); reg!("int", ser_int); reg!("long", ser_long); reg!("float", ser_float); reg!("string", ser_string); reg!("component", ser_component); reg!("optional_component", ser_optional_component); reg!("item_stack", ser_item_stack); reg!("boolean", ser_boolean); reg!("rotations", ser_rotations); reg!("block_pos", ser_block_pos); reg!("optional_block_pos", ser_optional_block_pos); reg!("direction", ser_direction); reg!(
310 "optional_living_entity_reference",
311 ser_optional_living_entity_reference
312 ); reg!("block_state", ser_block_state); reg!("optional_block_state", ser_optional_block_state); reg!("particle", ser_particle); reg!("particles", ser_particles); reg!("villager_data", ser_villager_data); reg!("optional_unsigned_int", ser_optional_unsigned_int); reg!("pose", ser_pose); reg!("cat_variant", ser_cat_variant); reg!("cat_sound_variant", ser_cat_sound_variant); reg!("cow_variant", ser_cow_variant); reg!("cow_sound_variant", ser_cow_sound_variant); reg!("wolf_variant", ser_wolf_variant); reg!("wolf_sound_variant", ser_wolf_sound_variant); reg!("frog_variant", ser_frog_variant); reg!("pig_variant", ser_pig_variant); reg!("pig_sound_variant", ser_pig_sound_variant); reg!("chicken_variant", ser_chicken_variant); reg!("chicken_sound_variant", ser_chicken_sound_variant); reg!("zombie_nautilus_variant", ser_zombie_nautilus_variant); reg!("optional_global_pos", ser_optional_global_pos); reg!("painting_variant", ser_painting_variant); reg!("sniffer_state", ser_sniffer_state); reg!("armadillo_state", ser_armadillo_state); reg!("copper_golem_state", ser_copper_golem_state); reg!("weathering_copper_state", ser_weathering_copper_state); reg!("vector3", ser_vector3); reg!("quaternion", ser_quaternion); reg!("resolvable_profile", ser_resolvable_profile); reg!("humanoid_arm", ser_humanoid_arm); }
343
344#[cfg(test)]
345mod tests {
346 use crate::RegistryExt;
347 use crate::entity_data::ResolvableProfile;
348
349 use super::*;
350
351 macro_rules! id {
352 ($name:expr) => {
353 Identifier::vanilla_static($name)
354 };
355 }
356
357 #[test]
358 fn test_serializer_registration_order() {
359 let mut registry = EntityDataSerializerRegistry::new();
360 register_vanilla_entity_data_serializers(&mut registry);
361
362 let expected_names = [
363 "byte",
364 "int",
365 "long",
366 "float",
367 "string",
368 "component",
369 "optional_component",
370 "item_stack",
371 "boolean",
372 "rotations",
373 "block_pos",
374 "optional_block_pos",
375 "direction",
376 "optional_living_entity_reference",
377 "block_state",
378 "optional_block_state",
379 "particle",
380 "particles",
381 "villager_data",
382 "optional_unsigned_int",
383 "pose",
384 "cat_variant",
385 "cat_sound_variant",
386 "cow_variant",
387 "cow_sound_variant",
388 "wolf_variant",
389 "wolf_sound_variant",
390 "frog_variant",
391 "pig_variant",
392 "pig_sound_variant",
393 "chicken_variant",
394 "chicken_sound_variant",
395 "zombie_nautilus_variant",
396 "optional_global_pos",
397 "painting_variant",
398 "sniffer_state",
399 "armadillo_state",
400 "copper_golem_state",
401 "weathering_copper_state",
402 "vector3",
403 "quaternion",
404 "resolvable_profile",
405 "humanoid_arm",
406 ];
407 for (expected_id, name) in expected_names.iter().enumerate() {
408 assert_eq!(
409 registry.id_from_key(&id!(name)),
410 Some(expected_id),
411 "serializer {name} must keep vanilla id {expected_id}"
412 );
413 }
414
415 assert_eq!(registry.len(), 43);
417 }
418
419 #[test]
420 fn test_serializers_write_correctly() {
421 let mut registry = EntityDataSerializerRegistry::new();
422 register_vanilla_entity_data_serializers(&mut registry);
423
424 let writer = registry.get_writer(0).unwrap();
426 let mut buf = Vec::new();
427 writer(&EntityData::Byte(42), &mut buf).unwrap();
428 assert_eq!(buf, vec![42]);
429
430 let writer = registry.get_writer(1).unwrap();
432 let mut buf = Vec::new();
433 writer(&EntityData::Int(300), &mut buf).unwrap();
434 assert_eq!(buf, vec![0xAC, 0x02]); let writer = registry.get_writer(3).unwrap();
438 let mut buf = Vec::new();
439 writer(&EntityData::Float(1.5), &mut buf).unwrap();
440 assert_eq!(buf, 1.5f32.to_be_bytes().to_vec());
441
442 let writer = registry.get_writer(8).unwrap();
444 let mut buf = Vec::new();
445 writer(&EntityData::Boolean(true), &mut buf).unwrap();
446 assert_eq!(buf, vec![1]);
447 }
448
449 #[test]
450 fn empty_resolvable_profile_matches_vanilla_static_empty_shape() {
451 let mut buf = Vec::new();
452 ser_resolvable_profile(
453 &EntityData::ResolvableProfile(ResolvableProfile::default()),
454 &mut buf,
455 )
456 .unwrap();
457
458 assert_eq!(buf, vec![0, 0, 0, 0, 0, 0, 0, 0]);
459 }
460}