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