minetest_protocol/wire/
types.rs

1//! Minetest data types used inside of Commands / Packets.
2//!
3//! Derive macros MinetestSerialize and MinetestDeserialize are used to
4//! produce ser/deser methods for many of the structs below. The order of
5//! the fields inside the struct determines the order in which they are
6//! serialized/deserialized, so be careful modifying anything below.
7//! Their serialized representation must stay the same.
8//!
9//! NOTE: The derive macros currently do not work on structs with generic parameters.
10//!
11//! TODO(paradust): Having an assert!-like macro that generates Serialize/Deserialize
12//! errors instead of aborts may be helpful for cleaning this up.
13use anyhow::bail;
14use minetest_protocol_derive::MinetestDeserialize;
15use minetest_protocol_derive::MinetestSerialize;
16
17use crate::itos;
18
19use super::deser::Deserialize;
20use super::deser::DeserializeError;
21use super::deser::DeserializeResult;
22use super::deser::Deserializer;
23use super::packet::LATEST_PROTOCOL_VERSION;
24use super::packet::SER_FMT_HIGHEST_READ;
25use super::ser::Serialize;
26use super::ser::SerializeError;
27use super::ser::SerializeResult;
28use super::ser::Serializer;
29use super::ser::VecSerializer;
30use super::util::compress_zlib;
31use super::util::decompress_zlib;
32use super::util::deserialize_json_string_if_needed;
33use super::util::next_word;
34use super::util::serialize_json_string_if_needed;
35use super::util::skip_whitespace;
36use super::util::split_by_whitespace;
37use super::util::stoi;
38use super::util::zstd_compress;
39use super::util::zstd_decompress;
40use std::marker::PhantomData;
41use std::ops::Deref;
42use std::ops::DerefMut;
43use std::ops::Div;
44use std::ops::Mul;
45
46#[allow(non_camel_case_types)]
47pub type s8 = i8;
48
49#[allow(non_camel_case_types)]
50pub type s16 = i16;
51
52#[allow(non_camel_case_types)]
53pub type s32 = i32;
54
55pub type CommandId = u8;
56
57#[derive(Debug, Clone, Copy, PartialEq)]
58pub enum CommandDirection {
59    ToClient,
60    ToServer,
61}
62
63impl CommandDirection {
64    pub fn for_send(remote_is_server: bool) -> Self {
65        use CommandDirection::*;
66        match remote_is_server {
67            true => ToServer,
68            false => ToClient,
69        }
70    }
71
72    pub fn for_receive(remote_is_server: bool) -> Self {
73        Self::for_send(remote_is_server).flip()
74    }
75
76    pub fn flip(&self) -> Self {
77        use CommandDirection::*;
78        match self {
79            ToClient => ToServer,
80            ToServer => ToClient,
81        }
82    }
83}
84
85#[derive(Debug, Clone, Copy, PartialEq)]
86pub struct ProtocolContext {
87    pub dir: CommandDirection,
88    pub protocol_version: u16,
89    pub ser_fmt: u8,
90}
91
92impl ProtocolContext {
93    pub fn latest_for_receive(remote_is_server: bool) -> Self {
94        Self {
95            dir: CommandDirection::for_receive(remote_is_server),
96            protocol_version: LATEST_PROTOCOL_VERSION,
97            ser_fmt: SER_FMT_HIGHEST_READ,
98        }
99    }
100
101    pub fn latest_for_send(remote_is_server: bool) -> Self {
102        Self {
103            dir: CommandDirection::for_send(remote_is_server),
104            protocol_version: LATEST_PROTOCOL_VERSION,
105            ser_fmt: SER_FMT_HIGHEST_READ,
106        }
107    }
108}
109
110/// Rust String's must be valid UTF8. But Minetest's strings can contain arbitrary
111/// binary data. The only way to store arbitrary bytes is with something like Vec<u8>,
112/// which is not String-like. This provides a String-like alternative, that looks nice
113/// in debug output.
114#[derive(Clone, PartialEq)]
115pub struct ByteString(pub Vec<u8>);
116
117impl std::fmt::Debug for ByteString {
118    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119        // Format it as an escaped string
120        std::fmt::Debug::fmt(&self.escape_ascii(), f)
121    }
122}
123
124impl ByteString {
125    pub fn as_bytes(&self) -> &[u8] {
126        &self.0
127    }
128
129    pub fn len(&self) -> usize {
130        self.0.len()
131    }
132
133    pub fn is_empty(&self) -> bool {
134        self.0.is_empty()
135    }
136
137    pub fn escape_ascii(&self) -> String {
138        self.0.escape_ascii().to_string()
139    }
140}
141
142impl Deref for ByteString {
143    type Target = [u8];
144
145    fn deref(&self) -> &Self::Target {
146        self.as_bytes()
147    }
148}
149
150impl DerefMut for ByteString {
151    fn deref_mut(&mut self) -> &mut Self::Target {
152        self.0.as_mut_slice()
153    }
154}
155
156impl From<Vec<u8>> for ByteString {
157    fn from(value: Vec<u8>) -> Self {
158        Self(value)
159    }
160}
161
162impl From<&[u8]> for ByteString {
163    fn from(value: &[u8]) -> Self {
164        Self(value.to_vec())
165    }
166}
167
168// Basic types
169impl Serialize for bool {
170    type Input = Self;
171    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
172        let val: u8 = if *value { 1 } else { 0 };
173        ser.write_bytes(&val.to_be_bytes()[..])
174    }
175}
176
177impl Deserialize for bool {
178    type Output = Self;
179    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
180        let b = deser.take_n::<1>()?[0];
181        Ok(match b {
182            0 => false,
183            1 => true,
184            _ => bail!("Invalid bool: {}", b),
185        })
186    }
187}
188
189impl Serialize for u8 {
190    type Input = Self;
191    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
192        ser.write_bytes(&value.to_be_bytes()[..])
193    }
194}
195
196impl Deserialize for u8 {
197    type Output = Self;
198    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
199        Ok(deser.take_n::<1>()?[0])
200    }
201}
202
203impl Serialize for u16 {
204    type Input = Self;
205    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
206        ser.write_bytes(&value.to_be_bytes()[..])
207    }
208}
209
210impl Deserialize for u16 {
211    type Output = Self;
212    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
213        Ok(u16::from_be_bytes(deser.take_n::<2>()?))
214    }
215}
216
217impl Serialize for u32 {
218    type Input = Self;
219    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
220        ser.write_bytes(&value.to_be_bytes()[..])
221    }
222}
223
224impl Deserialize for u32 {
225    type Output = Self;
226    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
227        Ok(u32::from_be_bytes(deser.take_n::<4>()?))
228    }
229}
230
231impl Serialize for u64 {
232    type Input = Self;
233    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
234        ser.write_bytes(&value.to_be_bytes()[..])
235    }
236}
237
238impl Deserialize for u64 {
239    type Output = Self;
240    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
241        Ok(u64::from_be_bytes(deser.take_n::<8>()?))
242    }
243}
244
245impl Serialize for i8 {
246    type Input = Self;
247    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
248        ser.write_bytes(&value.to_be_bytes()[..])
249    }
250}
251
252impl Deserialize for i8 {
253    type Output = Self;
254    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
255        Ok(deser.take(1)?[0] as i8)
256    }
257}
258
259impl Serialize for i16 {
260    type Input = Self;
261    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
262        ser.write_bytes(&value.to_be_bytes()[..])
263    }
264}
265
266impl Deserialize for i16 {
267    type Output = Self;
268
269    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
270        Ok(u16::from_be_bytes(deser.take_n::<2>()?) as i16)
271    }
272}
273
274impl Serialize for i32 {
275    type Input = Self;
276    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
277        ser.write_bytes(&value.to_be_bytes()[..])
278    }
279}
280
281impl Deserialize for i32 {
282    type Output = Self;
283    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
284        Ok(u32::from_be_bytes(deser.take_n::<4>()?) as i32)
285    }
286}
287
288impl Serialize for f32 {
289    type Input = Self;
290    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
291        ser.write_bytes(&value.to_be_bytes()[..])
292    }
293}
294
295impl Deserialize for f32 {
296    type Output = Self;
297    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
298        Ok(f32::from_be_bytes(deser.take_n::<4>()?))
299    }
300}
301
302/// str implements Serialize but not Deserialize
303impl Serialize for str {
304    type Input = Self;
305
306    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
307        u16::serialize(&u16::try_from(value.len())?, ser)?;
308        ser.write_bytes(value.as_bytes())
309    }
310}
311
312impl Serialize for String {
313    type Input = Self;
314    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
315        <str as Serialize>::serialize(&value, ser)
316    }
317}
318
319impl Deserialize for String {
320    type Output = Self;
321    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
322        let num_bytes = u16::deserialize(deser)? as usize;
323        match std::str::from_utf8(deser.take(num_bytes)?) {
324            Ok(s) => Ok(s.to_string()),
325            Err(u) => bail!(DeserializeError::InvalidValue(u.to_string())),
326        }
327    }
328}
329
330#[derive(Debug, Clone, PartialEq)]
331pub struct LongString(PhantomData<String>);
332
333impl Serialize for LongString {
334    type Input = String;
335    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
336        u32::serialize(&u32::try_from(value.len())?, ser)?;
337        ser.write_bytes(&value.as_bytes())
338    }
339}
340
341impl Deserialize for LongString {
342    type Output = String;
343    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
344        let num_bytes = u32::deserialize(deser)? as usize;
345        match std::str::from_utf8(deser.take(num_bytes)?) {
346            Ok(s) => Ok(s.to_string()),
347            Err(u) => bail!(DeserializeError::InvalidValue(u.to_string())),
348        }
349    }
350}
351
352/// Corresponds to std::wstring in C++ land
353#[derive(Debug, Clone, PartialEq)]
354pub struct WString(PhantomData<String>);
355
356impl Serialize for WString {
357    type Input = String;
358    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
359        let enc: Vec<u16> = value.encode_utf16().collect();
360
361        u16::serialize(&u16::try_from(enc.len())?, ser)?;
362        // TODO: This could be made more efficient.
363        let mut buf: Vec<u8> = vec![0; 2 * enc.len()];
364        let mut index: usize = 0;
365        for codepoint in enc {
366            buf[index] = (codepoint >> 8) as u8;
367            buf[index + 1] = codepoint as u8;
368            index += 2;
369        }
370        ser.write_bytes(&buf)
371    }
372}
373
374impl Deserialize for WString {
375    type Output = String;
376    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
377        let length = u16::deserialize(deser)? as usize;
378        let raw = deser.take(2 * length)?;
379        let mut seq: Vec<u16> = vec![0; length];
380        for i in 0..length {
381            seq[i] = u16::from_be_bytes(raw[2 * i..2 * i + 2].try_into().unwrap());
382        }
383        match String::from_utf16(&seq) {
384            Ok(s) => Ok(s),
385            Err(err) => bail!(DeserializeError::InvalidValue(err.to_string())),
386        }
387    }
388}
389
390#[allow(non_camel_case_types)]
391#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
392pub struct v2f {
393    pub x: f32,
394    pub y: f32,
395}
396
397impl v2f {
398    pub fn new(x: f32, y: f32) -> Self {
399        Self { x, y }
400    }
401}
402
403#[allow(non_camel_case_types)]
404#[derive(Debug, Clone, Copy, PartialEq, MinetestSerialize, MinetestDeserialize)]
405pub struct v3f {
406    pub x: f32,
407    pub y: f32,
408    pub z: f32,
409}
410
411impl v3f {
412    pub fn new(x: f32, y: f32, z: f32) -> Self {
413        Self { x, y, z }
414    }
415
416    pub fn as_v3s32(&self) -> v3s32 {
417        v3s32 {
418            x: self.x.round() as i32,
419            y: self.y.round() as i32,
420            z: self.z.round() as i32,
421        }
422    }
423}
424
425impl Mul<f32> for v3f {
426    type Output = v3f;
427    fn mul(self, rhs: f32) -> Self::Output {
428        v3f {
429            x: self.x * rhs,
430            y: self.y * rhs,
431            z: self.z * rhs,
432        }
433    }
434}
435
436impl Div<f32> for v3f {
437    type Output = v3f;
438    fn div(self, rhs: f32) -> Self::Output {
439        v3f {
440            x: self.x / rhs,
441            y: self.y / rhs,
442            z: self.z / rhs,
443        }
444    }
445}
446
447#[allow(non_camel_case_types)]
448#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
449pub struct v2u32 {
450    pub x: u32,
451    pub y: u32,
452}
453
454impl v2u32 {
455    pub fn new(x: u32, y: u32) -> Self {
456        Self { x, y }
457    }
458}
459
460#[allow(non_camel_case_types)]
461#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
462pub struct v2s16 {
463    pub x: s16,
464    pub y: s16,
465}
466
467impl v2s16 {
468    pub fn new(x: s16, y: s16) -> Self {
469        Self { x, y }
470    }
471}
472
473#[allow(non_camel_case_types)]
474#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
475pub struct v3s16 {
476    pub x: s16,
477    pub y: s16,
478    pub z: s16,
479}
480
481impl v3s16 {
482    pub fn new(x: s16, y: s16, z: s16) -> Self {
483        Self { x, y, z }
484    }
485}
486
487#[allow(non_camel_case_types)]
488#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
489pub struct v2s32 {
490    pub x: s32,
491    pub y: s32,
492}
493
494impl v2s32 {
495    pub fn new(x: s32, y: s32) -> Self {
496        Self { x, y }
497    }
498}
499
500#[allow(non_camel_case_types)]
501#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
502pub struct v3s32 {
503    pub x: s32,
504    pub y: s32,
505    pub z: s32,
506}
507
508impl v3s32 {
509    pub fn as_v3f(&self) -> v3f {
510        v3f {
511            x: self.x as f32,
512            y: self.y as f32,
513            z: self.z as f32,
514        }
515    }
516}
517
518#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
519pub struct SColor {
520    pub r: u8,
521    pub g: u8,
522    pub b: u8,
523    pub a: u8,
524}
525
526impl SColor {
527    pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
528        Self { r, g, b, a }
529    }
530}
531
532// Wrapped in a String (really a BinaryData16) with a 16-bit length
533#[derive(Debug, Clone, PartialEq)]
534pub struct Wrapped16<T> {
535    phantom: PhantomData<T>,
536}
537
538impl<T: Serialize> Serialize for Wrapped16<T> {
539    type Input = T::Input;
540    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
541        let marker = ser.write_marker(2)?;
542        <T as Serialize>::serialize(value, ser)?;
543        let wlen: u16 = u16::try_from(ser.marker_distance(&marker))?;
544        ser.set_marker(marker, &wlen.to_be_bytes()[..])?;
545        Ok(())
546    }
547}
548
549impl<T: Deserialize> Deserialize for Wrapped16<T> {
550    type Output = T::Output;
551    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
552        let wlen = u16::deserialize(deser)?;
553        let mut restricted_deser = deser.slice(wlen as usize)?;
554        <T as Deserialize>::deserialize(&mut restricted_deser)
555    }
556}
557
558// Wrapped in a String (really a BinaryData16) with a 16-bit length
559#[derive(Debug, Clone, PartialEq)]
560pub struct Wrapped32<T> {
561    phantom: PhantomData<T>,
562}
563
564impl<T: Serialize> Serialize for Wrapped32<T> {
565    type Input = T::Input;
566    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
567        let marker = ser.write_marker(4)?;
568        <T as Serialize>::serialize(value, ser)?;
569        let wlen: u32 = u32::try_from(ser.marker_distance(&marker))?;
570        ser.set_marker(marker, &wlen.to_be_bytes()[..])?;
571        Ok(())
572    }
573}
574
575impl<T: Deserialize> Deserialize for Wrapped32<T> {
576    type Output = T::Output;
577    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
578        let wlen = u32::deserialize(deser)?;
579        let mut restricted_deser = deser.slice(wlen as usize)?;
580        <T as Deserialize>::deserialize(&mut restricted_deser)
581    }
582}
583
584#[derive(Debug, Clone, PartialEq)]
585pub struct BinaryData16;
586
587impl Serialize for BinaryData16 {
588    type Input = Vec<u8>;
589    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
590        u16::serialize(&u16::try_from(value.len())?, ser)?;
591        ser.write_bytes(value)?;
592        Ok(())
593    }
594}
595
596impl Deserialize for BinaryData16 {
597    type Output = Vec<u8>;
598    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
599        let num_bytes = u16::deserialize(deser)? as usize;
600        Ok(Vec::from(deser.take(num_bytes)?))
601    }
602}
603
604/// Binary data preceded by a U32 size
605#[derive(Debug, Clone, PartialEq)]
606pub struct BinaryData32;
607
608impl Serialize for BinaryData32 {
609    type Input = Vec<u8>;
610    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
611        u32::serialize(&u32::try_from(value.len())?, ser)?;
612        ser.write_bytes(value)?;
613        Ok(())
614    }
615}
616
617impl Deserialize for BinaryData32 {
618    type Output = Vec<u8>;
619    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
620        let num_bytes = u32::deserialize(deser)? as usize;
621        Ok(Vec::from(deser.take(num_bytes)?))
622    }
623}
624
625#[derive(Debug, Clone, PartialEq)]
626pub struct FixedArray<const COUNT: usize, T>
627where
628    T: Serialize<Input = T>,
629    T: Deserialize<Output = T>,
630{
631    phantom: PhantomData<T>,
632}
633
634impl<const COUNT: usize, T> Serialize for FixedArray<COUNT, T>
635where
636    T: Serialize<Input = T>,
637    T: Deserialize<Output = T>,
638{
639    type Input = [T; COUNT];
640    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
641        for ent in value.iter() {
642            <T as Serialize>::serialize(ent, ser)?;
643        }
644        Ok(())
645    }
646}
647
648impl<const COUNT: usize, T> Deserialize for FixedArray<COUNT, T>
649where
650    T: Serialize<Input = T>,
651    T: Deserialize<Output = T>,
652{
653    type Output = [T; COUNT];
654    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
655        let mut entries = Vec::with_capacity(COUNT);
656        for _ in 0..COUNT {
657            entries.push(<T as Deserialize>::deserialize(deser)?);
658        }
659        match entries.try_into() {
660            Ok(entries) => Ok(entries),
661            Err(_) => bail!(DeserializeError::InvalidValue("FixedArray bug".to_string())),
662        }
663    }
664}
665
666/// Option is used for optional values at the end of a structure.
667/// Once Option is used, all following must be Option as well.
668impl<T: Serialize> Serialize for Option<T>
669where
670    <T as Serialize>::Input: Sized,
671{
672    type Input = Option<T::Input>;
673    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
674        match value {
675            Some(ref v) => <T as Serialize>::serialize(v, ser),
676            None => Ok(()),
677        }
678    }
679}
680
681impl<T: Deserialize> Deserialize for Option<T> {
682    type Output = Option<T::Output>;
683    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
684        if deser.remaining() > 0 {
685            Ok(Some(<T as Deserialize>::deserialize(deser)?))
686        } else {
687            Ok(None)
688        }
689    }
690}
691
692// An Optional value controlled by a u16 size parameter.
693// Unlike Option, this can appear anywhere in the message.
694#[derive(Debug, Clone, PartialEq)]
695pub enum Option16<T> {
696    None,
697    Some(T),
698}
699impl<T: Serialize> Serialize for Option16<T>
700where
701    <T as Serialize>::Input: Sized,
702{
703    type Input = Option16<T::Input>;
704    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
705        match value {
706            Option16::None => u16::serialize(&0u16, ser),
707            Option16::Some(value) => {
708                let mut buf = VecSerializer::new(ser.context(), 64);
709                <T as Serialize>::serialize(value, &mut buf)?;
710                let buf = buf.take();
711                let num_bytes = u16::try_from(buf.len())?;
712                u16::serialize(&num_bytes, ser)?;
713                ser.write_bytes(&buf)?;
714                Ok(())
715            }
716        }
717    }
718}
719
720impl<T: Deserialize> Deserialize for Option16<T> {
721    type Output = Option16<T::Output>;
722    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
723        match u16::deserialize(deser)? {
724            0 => Ok(Option16::None),
725            num_bytes => {
726                let mut buf = deser.slice(num_bytes as usize)?;
727                Ok(Option16::Some(<T as Deserialize>::deserialize(&mut buf)?))
728            }
729        }
730    }
731}
732
733#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
734pub struct AddedObject {
735    pub id: u16,
736    pub typ: u8,
737    #[wrap(Wrapped32<GenericInitData>)]
738    pub init_data: GenericInitData,
739}
740
741/// This corresponds to GenericCAO::Initialize in minetest
742#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
743pub struct GenericInitData {
744    pub version: u8,
745    pub name: String,
746    pub is_player: bool,
747    pub id: u16,
748    pub position: v3f,
749    pub rotation: v3f,
750    pub hp: u16,
751    #[wrap(Array8<Wrapped32<ActiveObjectCommand>>)]
752    pub messages: Vec<ActiveObjectCommand>,
753}
754
755#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
756pub struct ActiveObjectMessage {
757    pub id: u16,
758    #[wrap(Wrapped16<ActiveObjectCommand>)]
759    pub data: ActiveObjectCommand,
760}
761
762// TODO(paradust): Handle this in derive macros
763#[derive(Debug, Clone, PartialEq)]
764pub enum ActiveObjectCommand {
765    SetProperties(AOCSetProperties),
766    UpdatePosition(AOCUpdatePosition),
767    SetTextureMod(AOCSetTextureMod),
768    SetSprite(AOCSetSprite),
769    SetPhysicsOverride(AOCSetPhysicsOverride),
770    SetAnimation(AOCSetAnimation),
771    SetAnimationSpeed(AOCSetAnimationSpeed),
772    SetBonePosition(AOCSetBonePosition),
773    AttachTo(AOCAttachTo),
774    Punched(AOCPunched),
775    UpdateArmorGroups(AOCUpdateArmorGroups),
776    SpawnInfant(AOCSpawnInfant),
777    Obsolete1(AOCObsolete1),
778}
779
780const AO_CMD_SET_PROPERTIES: u8 = 0;
781const AO_CMD_UPDATE_POSITION: u8 = 1;
782const AO_CMD_SET_TEXTURE_MOD: u8 = 2;
783const AO_CMD_SET_SPRITE: u8 = 3;
784const AO_CMD_PUNCHED: u8 = 4;
785const AO_CMD_UPDATE_ARMOR_GROUPS: u8 = 5;
786const AO_CMD_SET_ANIMATION: u8 = 6;
787const AO_CMD_SET_BONE_POSITION: u8 = 7;
788const AO_CMD_ATTACH_TO: u8 = 8;
789const AO_CMD_SET_PHYSICS_OVERRIDE: u8 = 9;
790const AO_CMD_OBSOLETE1: u8 = 10;
791const AO_CMD_SPAWN_INFANT: u8 = 11;
792const AO_CMD_SET_ANIMATION_SPEED: u8 = 12;
793
794impl ActiveObjectCommand {
795    fn get_command_prefix(&self) -> u8 {
796        match self {
797            ActiveObjectCommand::SetProperties(_) => AO_CMD_SET_PROPERTIES,
798            ActiveObjectCommand::UpdatePosition(_) => AO_CMD_UPDATE_POSITION,
799            ActiveObjectCommand::SetTextureMod(_) => AO_CMD_SET_TEXTURE_MOD,
800            ActiveObjectCommand::SetSprite(_) => AO_CMD_SET_SPRITE,
801            ActiveObjectCommand::SetPhysicsOverride(_) => AO_CMD_SET_PHYSICS_OVERRIDE,
802            ActiveObjectCommand::SetAnimation(_) => AO_CMD_SET_ANIMATION,
803            ActiveObjectCommand::SetAnimationSpeed(_) => AO_CMD_SET_ANIMATION_SPEED,
804            ActiveObjectCommand::SetBonePosition(_) => AO_CMD_SET_BONE_POSITION,
805            ActiveObjectCommand::AttachTo(_) => AO_CMD_ATTACH_TO,
806            ActiveObjectCommand::Punched(_) => AO_CMD_PUNCHED,
807            ActiveObjectCommand::UpdateArmorGroups(_) => AO_CMD_UPDATE_ARMOR_GROUPS,
808            ActiveObjectCommand::SpawnInfant(_) => AO_CMD_SPAWN_INFANT,
809            ActiveObjectCommand::Obsolete1(_) => AO_CMD_OBSOLETE1,
810        }
811    }
812}
813
814impl Serialize for ActiveObjectCommand {
815    type Input = Self;
816    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
817        u8::serialize(&value.get_command_prefix(), ser)?;
818        match value {
819            ActiveObjectCommand::SetProperties(v) => AOCSetProperties::serialize(v, ser)?,
820            ActiveObjectCommand::UpdatePosition(v) => AOCUpdatePosition::serialize(v, ser)?,
821            ActiveObjectCommand::SetTextureMod(v) => AOCSetTextureMod::serialize(v, ser)?,
822            ActiveObjectCommand::SetSprite(v) => AOCSetSprite::serialize(v, ser)?,
823            ActiveObjectCommand::SetPhysicsOverride(v) => AOCSetPhysicsOverride::serialize(v, ser)?,
824            ActiveObjectCommand::SetAnimation(v) => AOCSetAnimation::serialize(v, ser)?,
825            ActiveObjectCommand::SetAnimationSpeed(v) => AOCSetAnimationSpeed::serialize(v, ser)?,
826            ActiveObjectCommand::SetBonePosition(v) => AOCSetBonePosition::serialize(v, ser)?,
827            ActiveObjectCommand::AttachTo(v) => AOCAttachTo::serialize(v, ser)?,
828            ActiveObjectCommand::Punched(v) => AOCPunched::serialize(v, ser)?,
829            ActiveObjectCommand::UpdateArmorGroups(v) => AOCUpdateArmorGroups::serialize(v, ser)?,
830            ActiveObjectCommand::SpawnInfant(v) => AOCSpawnInfant::serialize(v, ser)?,
831            ActiveObjectCommand::Obsolete1(v) => AOCObsolete1::serialize(v, ser)?,
832        }
833        Ok(())
834    }
835}
836
837impl Deserialize for ActiveObjectCommand {
838    type Output = Self;
839    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
840        use ActiveObjectCommand::*;
841        let cmd = u8::deserialize(deser)?;
842        Ok(match cmd {
843            AO_CMD_SET_PROPERTIES => SetProperties(AOCSetProperties::deserialize(deser)?),
844            AO_CMD_UPDATE_POSITION => UpdatePosition(AOCUpdatePosition::deserialize(deser)?),
845            AO_CMD_SET_TEXTURE_MOD => SetTextureMod(AOCSetTextureMod::deserialize(deser)?),
846            AO_CMD_SET_SPRITE => SetSprite(AOCSetSprite::deserialize(deser)?),
847            AO_CMD_PUNCHED => Punched(AOCPunched::deserialize(deser)?),
848            AO_CMD_UPDATE_ARMOR_GROUPS => {
849                UpdateArmorGroups(AOCUpdateArmorGroups::deserialize(deser)?)
850            }
851            AO_CMD_SET_ANIMATION => SetAnimation(AOCSetAnimation::deserialize(deser)?),
852            AO_CMD_SET_BONE_POSITION => SetBonePosition(AOCSetBonePosition::deserialize(deser)?),
853            AO_CMD_ATTACH_TO => AttachTo(AOCAttachTo::deserialize(deser)?),
854            AO_CMD_SET_PHYSICS_OVERRIDE => {
855                SetPhysicsOverride(AOCSetPhysicsOverride::deserialize(deser)?)
856            }
857            AO_CMD_OBSOLETE1 => Obsolete1(AOCObsolete1::deserialize(deser)?),
858            AO_CMD_SPAWN_INFANT => SpawnInfant(AOCSpawnInfant::deserialize(deser)?),
859            AO_CMD_SET_ANIMATION_SPEED => {
860                SetAnimationSpeed(AOCSetAnimationSpeed::deserialize(deser)?)
861            }
862            _ => bail!("ActiveObjectCommand: Invalid cmd={}", cmd),
863        })
864    }
865}
866
867#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
868pub struct AOCSetProperties {
869    pub newprops: ObjectProperties,
870}
871
872#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
873pub struct ObjectProperties {
874    pub version: u8, // must be 4
875    pub hp_max: u16,
876    pub physical: bool,
877    pub _unused: u32,
878    pub collision_box: aabb3f,
879    pub selection_box: aabb3f,
880    pub pointable: bool,
881    pub visual: String,
882    pub visual_size: v3f,
883    #[wrap(Array16<String>)]
884    pub textures: Vec<String>,
885    pub spritediv: v2s16,
886    pub initial_sprite_basepos: v2s16,
887    pub is_visible: bool,
888    pub makes_footstep_sound: bool,
889    pub automatic_rotate: f32,
890    pub mesh: String,
891    #[wrap(Array16<SColor>)]
892    pub colors: Vec<SColor>,
893    pub collide_with_objects: bool,
894    pub stepheight: f32,
895    pub automatic_face_movement_dir: bool,
896    pub automatic_face_movement_dir_offset: f32,
897    pub backface_culling: bool,
898    pub nametag: String,
899    pub nametag_color: SColor,
900    pub automatic_face_movement_max_rotation_per_sec: f32,
901    pub infotext: String,
902    pub wield_item: String,
903    pub glow: s8,
904    pub breath_max: u16,
905    pub eye_height: f32,
906    pub zoom_fov: f32,
907    pub use_texture_alpha: bool,
908    pub damage_texture_modifier: Option<String>,
909    pub shaded: Option<bool>,
910    pub show_on_minimap: Option<bool>,
911    pub nametag_bgcolor: Option<SColor>,
912    pub rotate_selectionbox: Option<bool>,
913}
914
915#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
916pub struct AOCUpdatePosition {
917    pub position: v3f,
918    pub velocity: v3f,
919    pub acceleration: v3f,
920    pub rotation: v3f,
921    pub do_interpolate: bool,
922    pub is_end_position: bool,
923    pub update_interval: f32,
924}
925
926#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
927pub struct AOCSetTextureMod {
928    pub modifier: String,
929}
930
931#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
932pub struct AOCSetSprite {
933    pub base_pos: v2s16,
934    pub anum_num_frames: u16,
935    pub anim_frame_length: f32,
936    pub select_horiz_by_yawpitch: bool,
937}
938
939#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
940pub struct AOCSetPhysicsOverride {
941    pub override_speed: f32,
942    pub override_jump: f32,
943    pub override_gravity: f32,
944    pub not_sneak: bool,
945    pub not_sneak_glitch: bool,
946    pub not_new_move: bool,
947}
948
949#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
950pub struct AOCSetAnimation {
951    pub range: v2f, // this is always casted to v2s32 by minetest for some reason
952    pub speed: f32,
953    pub blend: f32,
954    pub no_loop: bool,
955}
956
957#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
958pub struct AOCSetAnimationSpeed {
959    pub speed: f32,
960}
961
962#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
963pub struct AOCSetBonePosition {
964    pub bone: String,
965    pub position: v3f,
966    pub rotation: v3f,
967}
968
969#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
970pub struct AOCAttachTo {
971    pub parent_id: s16,
972    pub bone: String,
973    pub position: v3f,
974    pub rotation: v3f,
975    pub force_visible: bool,
976}
977
978#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
979pub struct AOCPunched {
980    pub hp: u16,
981}
982
983#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
984pub struct AOCUpdateArmorGroups {
985    // name -> rating
986    #[wrap(Array16<Pair<String, s16>>)]
987    pub ratings: Vec<(String, s16)>,
988}
989
990#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
991pub struct AOCSpawnInfant {
992    pub child_id: u16,
993    pub typ: u8,
994}
995
996#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
997pub struct AOCObsolete1 {}
998
999/// An array of items with no specified length.
1000/// The length is determined by buffer end.
1001#[derive(Debug, Clone, PartialEq)]
1002pub struct Array0<T>(PhantomData<T>);
1003
1004impl<T: Serialize> Serialize for Array0<T>
1005where
1006    <T as Serialize>::Input: Sized,
1007{
1008    type Input = Vec<T::Input>;
1009    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1010        for v in value.iter() {
1011            <T as Serialize>::serialize(v, ser)?;
1012        }
1013        Ok(())
1014    }
1015}
1016
1017impl<T: Deserialize> Deserialize for Array0<T> {
1018    type Output = Vec<T::Output>;
1019    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
1020        let mut vec = Vec::new();
1021        while deser.remaining() > 0 {
1022            vec.push(<T as Deserialize>::deserialize(deser)?);
1023        }
1024        Ok(vec)
1025    }
1026}
1027
1028/// An array of items with a u8 length prefix
1029#[derive(Debug, Clone, PartialEq)]
1030pub struct Array8<T>(PhantomData<T>);
1031
1032impl<T: Serialize> Serialize for Array8<T>
1033where
1034    <T as Serialize>::Input: Sized,
1035{
1036    type Input = Vec<T::Input>;
1037    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1038        u8::serialize(&u8::try_from(value.len())?, ser)?;
1039        for v in value.iter() {
1040            <T as Serialize>::serialize(v, ser)?;
1041        }
1042        Ok(())
1043    }
1044}
1045
1046impl<T: Deserialize> Deserialize for Array8<T> {
1047    type Output = Vec<T::Output>;
1048    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
1049        let length = u8::deserialize(deser)? as usize;
1050        let mut vec = Vec::with_capacity(length);
1051        for _ in 0..length {
1052            vec.push(<T as Deserialize>::deserialize(deser)?);
1053        }
1054        Ok(vec)
1055    }
1056}
1057
1058/// An array of items with a u16 length prefix
1059#[derive(Debug, Clone, PartialEq)]
1060pub struct Array16<T>(PhantomData<T>);
1061
1062impl<T: Serialize> Serialize for Array16<T>
1063where
1064    <T as Serialize>::Input: Sized,
1065{
1066    type Input = Vec<T::Input>;
1067    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1068        u16::serialize(&u16::try_from(value.len())?, ser)?;
1069        for v in value.iter() {
1070            <T as Serialize>::serialize(v, ser)?;
1071        }
1072        Ok(())
1073    }
1074}
1075
1076impl<T: Deserialize> Deserialize for Array16<T> {
1077    type Output = Vec<T::Output>;
1078    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
1079        let length = u16::deserialize(deser)? as usize;
1080        let mut vec = Vec::with_capacity(length);
1081        for _ in 0..length {
1082            vec.push(<T as Deserialize>::deserialize(deser)?);
1083        }
1084        Ok(vec)
1085    }
1086}
1087
1088/// An array of items with a u32 length prefix
1089#[derive(Debug, Clone, PartialEq)]
1090pub struct Array32<T>(PhantomData<T>);
1091
1092impl<T: Serialize> Serialize for Array32<T>
1093where
1094    <T as Serialize>::Input: Sized,
1095{
1096    type Input = Vec<T::Input>;
1097    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1098        u32::serialize(&u32::try_from(value.len())?, ser)?;
1099        for v in value.iter() {
1100            <T as Serialize>::serialize(v, ser)?;
1101        }
1102        Ok(())
1103    }
1104}
1105
1106impl<T: Deserialize> Deserialize for Array32<T> {
1107    type Output = Vec<T::Output>;
1108    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
1109        let length = u32::deserialize(deser)? as usize;
1110        // Sanity check to prevent memory DoS
1111        if length > deser.remaining() {
1112            bail!(DeserializeError::InvalidValue(
1113                "Array32 length too long".to_string(),
1114            ));
1115        }
1116        let mut vec = Vec::with_capacity(length);
1117        for _ in 0..length {
1118            vec.push(<T as Deserialize>::deserialize(deser)?);
1119        }
1120        Ok(vec)
1121    }
1122}
1123
1124#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1125pub struct MediaFileData {
1126    pub name: String,
1127    #[wrap(BinaryData32)]
1128    pub data: Vec<u8>,
1129}
1130
1131#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1132pub struct MediaAnnouncement {
1133    pub name: String,
1134    pub sha1_base64: String,
1135}
1136
1137#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1138pub struct SkyColor {
1139    pub day_sky: SColor,
1140    pub day_horizon: SColor,
1141    pub dawn_sky: SColor,
1142    pub dawn_horizon: SColor,
1143    pub night_sky: SColor,
1144    pub night_horizon: SColor,
1145    pub indoors: SColor,
1146}
1147
1148#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1149pub struct SunParams {
1150    pub visible: bool,
1151    pub texture: String,
1152    pub tonemap: String,
1153    pub sunrise: String,
1154    pub sunrise_visible: bool,
1155    pub scale: f32,
1156}
1157
1158#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1159pub struct MoonParams {
1160    pub visible: bool,
1161    pub texture: String,
1162    pub tonemap: String,
1163    pub scale: f32,
1164}
1165#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1166pub struct StarParams {
1167    pub visible: bool,
1168    pub count: u32,
1169    pub starcolor: SColor,
1170    pub scale: f32,
1171    pub day_opacity: Option<f32>,
1172}
1173
1174#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1175pub struct MinimapMode {
1176    pub typ: u16,
1177    pub label: String,
1178    pub size: u16,
1179    pub texture: String,
1180    pub scale: u16,
1181}
1182
1183#[derive(Debug, Clone, PartialEq)]
1184pub struct PlayerPos {
1185    pub position: v3f,     // serialized as v3s32, *100.0f
1186    pub speed: v3f,        // serialzied as v3s32, *100.0f
1187    pub pitch: f32,        // serialized as s32, *100.0f
1188    pub yaw: f32,          // serialized as s32, *100.0f
1189    pub keys_pressed: u32, // bitset
1190    pub fov: f32,          // serialized as u8, *80.0f
1191    pub wanted_range: u8,
1192}
1193
1194impl Serialize for PlayerPos {
1195    type Input = Self;
1196    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1197        let s_position = (value.position * 100f32).as_v3s32();
1198        let s_speed = (value.speed * 100f32).as_v3s32();
1199        let s_pitch = (value.pitch * 100f32).round() as s32;
1200        let s_yaw = (value.yaw * 100f32).round() as s32;
1201        let s_fov = (value.fov * 80f32).round() as u8;
1202
1203        v3s32::serialize(&s_position, ser)?;
1204        v3s32::serialize(&s_speed, ser)?;
1205        i32::serialize(&s_pitch, ser)?;
1206        i32::serialize(&s_yaw, ser)?;
1207        u32::serialize(&value.keys_pressed, ser)?;
1208        u8::serialize(&s_fov, ser)?;
1209        u8::serialize(&value.wanted_range, ser)?;
1210        Ok(())
1211    }
1212}
1213
1214impl Deserialize for PlayerPos {
1215    type Output = Self;
1216    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
1217        let s_position = v3s32::deserialize(deser)?;
1218        let s_speed = v3s32::deserialize(deser)?;
1219        let s_pitch = s32::deserialize(deser)?;
1220        let s_yaw = s32::deserialize(deser)?;
1221        let keys_pressed = u32::deserialize(deser)?;
1222        let s_fov = u8::deserialize(deser)?;
1223        let wanted_range = u8::deserialize(deser)?;
1224        Ok(PlayerPos {
1225            position: s_position.as_v3f() / 100f32,
1226            speed: s_speed.as_v3f() / 100f32,
1227            pitch: (s_pitch as f32) / 100f32,
1228            yaw: (s_yaw as f32) / 100f32,
1229            keys_pressed: keys_pressed,
1230            fov: (s_fov as f32) / 80f32,
1231            wanted_range: wanted_range,
1232        })
1233    }
1234}
1235
1236#[derive(Debug, Clone, PartialEq)]
1237pub struct Pair<T1, T2>(PhantomData<(T1, T2)>);
1238
1239impl<T1: Serialize, T2: Serialize> Serialize for Pair<T1, T2>
1240where
1241    <T1 as Serialize>::Input: Sized,
1242    <T2 as Serialize>::Input: Sized,
1243{
1244    type Input = (T1::Input, T2::Input);
1245    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1246        <T1 as Serialize>::serialize(&value.0, ser)?;
1247        <T2 as Serialize>::serialize(&value.1, ser)?;
1248        Ok(())
1249    }
1250}
1251
1252impl<T1: Deserialize, T2: Deserialize> Deserialize for Pair<T1, T2> {
1253    type Output = (T1::Output, T2::Output);
1254    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
1255        Ok((
1256            <T1 as Deserialize>::deserialize(deser)?,
1257            <T2 as Deserialize>::deserialize(deser)?,
1258        ))
1259    }
1260}
1261
1262#[derive(Debug, Clone, PartialEq)]
1263pub enum AccessDeniedCode {
1264    WrongPassword,
1265    UnexpectedData,
1266    Singleplayer,
1267    WrongVersion,
1268    WrongCharsInName,
1269    WrongName,
1270    TooManyUsers,
1271    EmptyPassword,
1272    AlreadyConnected,
1273    ServerFail,
1274    CustomString(String),
1275    Shutdown(String, bool), // custom message (or blank), should_reconnect
1276    Crash(String, bool),    // custom message (or blank), should_reconnect
1277}
1278
1279impl Serialize for AccessDeniedCode {
1280    type Input = Self;
1281    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1282        use AccessDeniedCode::*;
1283        match value {
1284            WrongPassword => u8::serialize(&0, ser),
1285            UnexpectedData => u8::serialize(&1, ser),
1286            Singleplayer => u8::serialize(&2, ser),
1287            WrongVersion => u8::serialize(&3, ser),
1288            WrongCharsInName => u8::serialize(&4, ser),
1289            WrongName => u8::serialize(&5, ser),
1290            TooManyUsers => u8::serialize(&6, ser),
1291            EmptyPassword => u8::serialize(&7, ser),
1292            AlreadyConnected => u8::serialize(&8, ser),
1293            ServerFail => u8::serialize(&9, ser),
1294            CustomString(msg) => {
1295                u8::serialize(&10, ser)?;
1296                String::serialize(&msg, ser)?;
1297                Ok(())
1298            }
1299            Shutdown(msg, reconnect) => {
1300                u8::serialize(&11, ser)?;
1301                String::serialize(&msg, ser)?;
1302                bool::serialize(&reconnect, ser)?;
1303                Ok(())
1304            }
1305            Crash(msg, reconnect) => {
1306                u8::serialize(&12, ser)?;
1307                String::serialize(&msg, ser)?;
1308                bool::serialize(&reconnect, ser)?;
1309                Ok(())
1310            }
1311        }
1312    }
1313}
1314
1315impl Deserialize for AccessDeniedCode {
1316    type Output = Self;
1317    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
1318        use AccessDeniedCode::*;
1319        let deny_code = u8::deserialize(deser)?;
1320        match deny_code {
1321            0 => Ok(WrongPassword),
1322            1 => Ok(UnexpectedData),
1323            2 => Ok(Singleplayer),
1324            3 => Ok(WrongVersion),
1325            4 => Ok(WrongCharsInName),
1326            5 => Ok(WrongName),
1327            6 => Ok(TooManyUsers),
1328            7 => Ok(EmptyPassword),
1329            8 => Ok(AlreadyConnected),
1330            9 => Ok(ServerFail),
1331            10 => Ok(CustomString(String::deserialize(deser)?)),
1332            11 => Ok(Shutdown(
1333                String::deserialize(deser)?,
1334                (u8::deserialize(deser)? & 1) != 0,
1335            )),
1336            12 => Ok(Crash(
1337                String::deserialize(deser)?,
1338                (u8::deserialize(deser)? & 1) != 0,
1339            )),
1340            _ => Ok(CustomString(String::deserialize(deser)?)),
1341        }
1342    }
1343}
1344
1345impl AccessDeniedCode {
1346    pub fn to_str<'a>(&'a self) -> &'a str {
1347        use AccessDeniedCode::*;
1348        match self {
1349            WrongPassword => "Invalid password",
1350            UnexpectedData => "Your client sent something the server didn't expect.  Try reconnecting or updating your client.",
1351            Singleplayer => "The server is running in simple singleplayer mode.  You cannot connect.",
1352            WrongVersion => "Your client's version is not supported.\nPlease contact the server administrator.",
1353            WrongCharsInName => "Player name contains disallowed characters",
1354            WrongName => "Player name not allowed",
1355            TooManyUsers => "Too many users",
1356            EmptyPassword => "Empty passwords are disallowed.  Set a password and try again.",
1357            AlreadyConnected => "Another client is connected with this name.  If your client closed unexpectedly, try again in a minute.",
1358            ServerFail => "Internal server error",
1359            CustomString(msg) => if msg.is_empty() { "unknown" } else { msg },
1360            Shutdown(msg, _) => if msg.is_empty() { "Server shutting down" } else { msg },
1361            Crash(msg, _) => if msg.is_empty() { "The server has experienced an internal error.  You will now be disconnected." } else { msg },
1362        }
1363    }
1364}
1365
1366#[derive(Debug, Clone, PartialEq)]
1367pub enum HudStat {
1368    Pos(v2f),
1369    Name(String),
1370    Scale(v2f),
1371    Text(String),
1372    Number(u32),
1373    Item(u32),
1374    Dir(u32),
1375    Align(v2f),
1376    Offset(v2f),
1377    WorldPos(v3f),
1378    Size(v2s32),
1379    ZIndex(u32),
1380    Text2(String),
1381    Style(u32),
1382}
1383
1384impl Serialize for HudStat {
1385    type Input = Self;
1386    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1387        use HudStat::*;
1388        match value {
1389            Pos(v) => {
1390                u8::serialize(&0, ser)?;
1391                v2f::serialize(v, ser)?;
1392            }
1393            Name(v) => {
1394                u8::serialize(&1, ser)?;
1395                String::serialize(v, ser)?;
1396            }
1397            Scale(v) => {
1398                u8::serialize(&2, ser)?;
1399                v2f::serialize(v, ser)?;
1400            }
1401            Text(v) => {
1402                u8::serialize(&3, ser)?;
1403                String::serialize(v, ser)?;
1404            }
1405            Number(v) => {
1406                u8::serialize(&4, ser)?;
1407                u32::serialize(v, ser)?;
1408            }
1409            Item(v) => {
1410                u8::serialize(&5, ser)?;
1411                u32::serialize(v, ser)?;
1412            }
1413            Dir(v) => {
1414                u8::serialize(&6, ser)?;
1415                u32::serialize(v, ser)?;
1416            }
1417            Align(v) => {
1418                u8::serialize(&7, ser)?;
1419                v2f::serialize(v, ser)?;
1420            }
1421            Offset(v) => {
1422                u8::serialize(&8, ser)?;
1423                v2f::serialize(v, ser)?;
1424            }
1425            WorldPos(v) => {
1426                u8::serialize(&9, ser)?;
1427                v3f::serialize(v, ser)?;
1428            }
1429            Size(v) => {
1430                u8::serialize(&10, ser)?;
1431                v2s32::serialize(v, ser)?;
1432            }
1433            ZIndex(v) => {
1434                u8::serialize(&11, ser)?;
1435                u32::serialize(v, ser)?;
1436            }
1437            Text2(v) => {
1438                u8::serialize(&12, ser)?;
1439                String::serialize(v, ser)?;
1440            }
1441            Style(v) => {
1442                u8::serialize(&13, ser)?;
1443                u32::serialize(v, ser)?;
1444            }
1445        }
1446        Ok(())
1447    }
1448}
1449
1450impl Deserialize for HudStat {
1451    type Output = Self;
1452    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
1453        use HudStat::*;
1454        let stat = u8::deserialize(deser)?;
1455        match stat {
1456            0 => Ok(Pos(v2f::deserialize(deser)?)),
1457            1 => Ok(Name(String::deserialize(deser)?)),
1458            2 => Ok(Scale(v2f::deserialize(deser)?)),
1459            3 => Ok(Text(String::deserialize(deser)?)),
1460            4 => Ok(Number(u32::deserialize(deser)?)),
1461            5 => Ok(Item(u32::deserialize(deser)?)),
1462            6 => Ok(Dir(u32::deserialize(deser)?)),
1463            7 => Ok(Align(v2f::deserialize(deser)?)),
1464            8 => Ok(Offset(v2f::deserialize(deser)?)),
1465            9 => Ok(WorldPos(v3f::deserialize(deser)?)),
1466            10 => Ok(Size(v2s32::deserialize(deser)?)),
1467            11 => Ok(ZIndex(u32::deserialize(deser)?)),
1468            12 => Ok(Text2(String::deserialize(deser)?)),
1469            13 => Ok(Style(u32::deserialize(deser)?)),
1470            _ => bail!(DeserializeError::InvalidValue(String::from(
1471                "HudStat invalid stat",
1472            ))),
1473        }
1474    }
1475}
1476
1477#[derive(Debug, Clone, PartialEq)]
1478pub struct SkyboxParams {
1479    pub bgcolor: SColor,
1480    pub clouds: bool,
1481    pub fog_sun_tint: SColor,
1482    pub fog_moon_tint: SColor,
1483    pub fog_tint_type: String,
1484    pub data: SkyboxData,
1485    pub body_orbit_tilt: Option<f32>,
1486}
1487
1488#[derive(Debug, Clone, PartialEq)]
1489pub enum SkyboxData {
1490    None,                  // If skybox_type == "plain"
1491    Textures(Vec<String>), // If skybox_type == "skybox"
1492    Color(SkyColor),       // If skybox_type == "regular"
1493}
1494
1495impl Serialize for SkyboxParams {
1496    type Input = Self;
1497    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1498        SColor::serialize(&value.bgcolor, ser)?;
1499        let skybox_type = match &value.data {
1500            SkyboxData::None => "plain",
1501            SkyboxData::Textures(..) => "skybox",
1502            SkyboxData::Color(..) => "regular",
1503        };
1504        str::serialize(skybox_type, ser)?;
1505        bool::serialize(&value.clouds, ser)?;
1506        SColor::serialize(&value.fog_sun_tint, ser)?;
1507        SColor::serialize(&value.fog_moon_tint, ser)?;
1508        String::serialize(&value.fog_tint_type, ser)?;
1509        match &value.data {
1510            SkyboxData::None => (),
1511            SkyboxData::Textures(v) => <Array16<String> as Serialize>::serialize(v, ser)?,
1512            SkyboxData::Color(v) => SkyColor::serialize(v, ser)?,
1513        }
1514        <Option<f32> as Serialize>::serialize(&value.body_orbit_tilt, ser)?;
1515        Ok(())
1516    }
1517}
1518
1519impl Deserialize for SkyboxParams {
1520    type Output = Self;
1521    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
1522        let bgcolor = SColor::deserialize(deser)?;
1523        let typ = String::deserialize(deser)?;
1524        Ok(SkyboxParams {
1525            bgcolor: bgcolor,
1526            clouds: bool::deserialize(deser)?,
1527            fog_sun_tint: SColor::deserialize(deser)?,
1528            fog_moon_tint: SColor::deserialize(deser)?,
1529            fog_tint_type: String::deserialize(deser)?,
1530            data: {
1531                if typ == "skybox" {
1532                    SkyboxData::Textures(<Array16<String> as Deserialize>::deserialize(deser)?)
1533                } else if typ == "regular" {
1534                    SkyboxData::Color(SkyColor::deserialize(deser)?)
1535                } else if typ == "plain" {
1536                    SkyboxData::None
1537                } else {
1538                    bail!("Invalid skybox type: {:?}", typ)
1539                }
1540            },
1541            body_orbit_tilt: <Option<f32> as Deserialize>::deserialize(deser)?,
1542        })
1543    }
1544}
1545
1546#[derive(Debug, Clone, PartialEq)]
1547pub struct MinimapModeList {
1548    pub mode: u16,
1549    pub vec: Vec<MinimapMode>,
1550}
1551
1552impl Serialize for MinimapModeList {
1553    type Input = Self;
1554    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1555        // The length of the list is a u16 which precedes `mode`,
1556        // which makes the layout not fit into any usual pattern.
1557        u16::serialize(&u16::try_from(value.vec.len())?, ser)?;
1558        u16::serialize(&value.mode, ser)?;
1559        for v in value.vec.iter() {
1560            MinimapMode::serialize(v, ser)?;
1561        }
1562        Ok(())
1563    }
1564}
1565
1566impl Deserialize for MinimapModeList {
1567    type Output = Self;
1568    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
1569        let count = u16::deserialize(deser)?;
1570        let mode = u16::deserialize(deser)?;
1571        let mut vec: Vec<MinimapMode> = Vec::with_capacity(count as usize);
1572        for _ in 0..count {
1573            vec.push(MinimapMode::deserialize(deser)?);
1574        }
1575        Ok(MinimapModeList {
1576            mode: mode,
1577            vec: vec,
1578        })
1579    }
1580}
1581
1582#[derive(Debug, Clone, PartialEq)]
1583pub struct AuthMechsBitset {
1584    pub legacy_password: bool,
1585    pub srp: bool,
1586    pub first_srp: bool,
1587}
1588
1589impl Serialize for AuthMechsBitset {
1590    type Input = Self;
1591    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1592        let mut bits: u32 = 0;
1593        if value.legacy_password {
1594            bits |= 1;
1595        }
1596        if value.srp {
1597            bits |= 2;
1598        }
1599        if value.first_srp {
1600            bits |= 4;
1601        }
1602        u32::serialize(&bits, ser)
1603    }
1604}
1605
1606impl Deserialize for AuthMechsBitset {
1607    type Output = Self;
1608    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
1609        let value = u32::deserialize(deser)?;
1610        Ok(AuthMechsBitset {
1611            legacy_password: (value & 1) != 0,
1612            srp: (value & 2) != 0,
1613            first_srp: (value & 4) != 0,
1614        })
1615    }
1616}
1617
1618#[derive(Debug, Clone, PartialEq)]
1619pub struct ZLibCompressed<T>(PhantomData<T>);
1620
1621impl<T: Serialize> Serialize for ZLibCompressed<T> {
1622    type Input = T::Input;
1623    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1624        // TODO(paradust): Performance nightmare.
1625
1626        // Serialize 'value' to a temporary buffer, and then compress
1627        let mut tmp = VecSerializer::new(ser.context(), 1024);
1628        <T as Serialize>::serialize(&value, &mut tmp)?;
1629        let tmp = tmp.take();
1630        let tmp = miniz_oxide::deflate::compress_to_vec_zlib(&tmp, 6);
1631
1632        // Write the size as a u32, followed by the data
1633        u32::serialize(&u32::try_from(tmp.len())?, ser)?;
1634        ser.write_bytes(&tmp)?;
1635        Ok(())
1636    }
1637}
1638
1639impl<T: Deserialize> Deserialize for ZLibCompressed<T> {
1640    type Output = T::Output;
1641    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
1642        let num_bytes = u32::deserialize(deser)? as usize;
1643        let data = deser.take(num_bytes)?;
1644        // TODO(paradust): DANGEROUS. There is no decompression size bound.
1645        match miniz_oxide::inflate::decompress_to_vec_zlib(&data) {
1646            Ok(decompressed) => {
1647                let mut tmp = Deserializer::new(deser.context(), &decompressed);
1648                Ok(<T as Deserialize>::deserialize(&mut tmp)?)
1649            }
1650            Err(err) => bail!(DeserializeError::DecompressionFailed(err.to_string())),
1651        }
1652    }
1653}
1654
1655#[derive(Debug, Clone, PartialEq)]
1656pub struct ZStdCompressed<T>(PhantomData<T>);
1657
1658impl<T: Serialize> Serialize for ZStdCompressed<T> {
1659    type Input = T::Input;
1660    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1661        // Serialize 'value' into a temporary buffer
1662        // TODO(paradust): Performance concern, could stream instead
1663        let mut tmp = VecSerializer::new(ser.context(), 65536);
1664        <T as Serialize>::serialize(value, &mut tmp)?;
1665        let tmp = tmp.take();
1666        match zstd_compress(&tmp, |chunk| {
1667            ser.write_bytes(chunk)?;
1668            Ok(())
1669        }) {
1670            Ok(_) => Ok(()),
1671            Err(err) => bail!(SerializeError::CompressionFailed(err.to_string())),
1672        }
1673    }
1674}
1675
1676impl<T: Deserialize> Deserialize for ZStdCompressed<T> {
1677    type Output = T::Output;
1678    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self::Output> {
1679        // Decompress to a temporary buffer
1680        let mut tmp: Vec<u8> = Vec::with_capacity(65536);
1681        match zstd_decompress(deser.peek_all(), |chunk| {
1682            tmp.extend_from_slice(chunk);
1683            Ok(())
1684        }) {
1685            Ok(consumed) => {
1686                deser.take(consumed)?;
1687                let mut tmp_deser = Deserializer::new(deser.context(), &tmp);
1688                Ok(<T as Deserialize>::deserialize(&mut tmp_deser)?)
1689            }
1690            Err(err) => bail!(DeserializeError::DecompressionFailed(err.to_string())),
1691        }
1692    }
1693}
1694
1695#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1696pub struct ItemdefList {
1697    pub itemdef_manager_version: u8,
1698    #[wrap(Array16<Wrapped16<ItemDef>>)]
1699    pub defs: Vec<ItemDef>,
1700    #[wrap(Array16<ItemAlias>)]
1701    pub aliases: Vec<ItemAlias>,
1702}
1703
1704#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1705pub enum ItemType {
1706    None,
1707    Node,
1708    Craft,
1709    Tool,
1710}
1711
1712#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1713pub struct ToolGroupCap {
1714    pub uses: s16,
1715    pub maxlevel: s16,
1716    // (level, time)
1717    #[wrap(Array32<Pair<s16, f32>>)]
1718    pub times: Vec<(s16, f32)>,
1719}
1720
1721#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1722pub struct ToolCapabilities {
1723    pub version: u8,
1724    pub full_punch_interval: f32,
1725    pub max_drop_level: s16,
1726    // (name, tool group cap)
1727    #[wrap(Array32<Pair<String, ToolGroupCap>>)]
1728    pub group_caps: Vec<(String, ToolGroupCap)>,
1729    // (name, rating)
1730    #[wrap(Array32<Pair<String, s16>>)]
1731    pub damage_groups: Vec<(String, s16)>,
1732    pub punch_attack_uses: Option<u16>,
1733}
1734
1735#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1736pub struct SimpleSoundSpec {
1737    pub name: String,
1738    pub gain: f32,
1739    pub pitch: f32,
1740    pub fade: f32,
1741}
1742
1743#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1744pub struct ItemDef {
1745    pub version: u8,
1746    pub item_type: ItemType,
1747    pub name: String,
1748    pub description: String,
1749    pub inventory_image: String,
1750    pub wield_image: String,
1751    pub wield_scale: v3f,
1752    pub stack_max: s16,
1753    pub usable: bool,
1754    pub liquids_pointable: bool,
1755    pub tool_capabilities: Option16<ToolCapabilities>,
1756    #[wrap(Array16<Pair<String, s16>>)]
1757    pub groups: Vec<(String, s16)>,
1758    pub node_placement_prediction: String,
1759    pub sound_place: SimpleSoundSpec,
1760    pub sound_place_failed: SimpleSoundSpec,
1761    pub range: f32,
1762    pub palette_image: String,
1763    pub color: SColor,
1764    pub inventory_overlay: String,
1765    pub wield_overlay: String,
1766    pub short_description: Option<String>,
1767    pub place_param2: Option<u8>,
1768    pub sound_use: Option<SimpleSoundSpec>,
1769    pub sound_use_air: Option<SimpleSoundSpec>,
1770}
1771
1772#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1773pub struct ItemAlias {
1774    pub name: String,
1775    pub convert_to: String,
1776}
1777
1778#[derive(Debug, Clone, PartialEq)]
1779pub struct TileDef {
1780    pub name: String,
1781    pub animation: TileAnimationParams,
1782    // These are stored in a single u8 flags
1783    pub backface_culling: bool,
1784    pub tileable_horizontal: bool,
1785    pub tileable_vertical: bool,
1786    // The flags also determine which of these is present
1787    pub color_rgb: Option<(u8, u8, u8)>,
1788    pub scale: u8,
1789    pub align_style: AlignStyle,
1790}
1791
1792const TILE_FLAG_BACKFACE_CULLING: u16 = 1 << 0;
1793const TILE_FLAG_TILEABLE_HORIZONTAL: u16 = 1 << 1;
1794const TILE_FLAG_TILEABLE_VERTICAL: u16 = 1 << 2;
1795const TILE_FLAG_HAS_COLOR: u16 = 1 << 3;
1796const TILE_FLAG_HAS_SCALE: u16 = 1 << 4;
1797const TILE_FLAG_HAS_ALIGN_STYLE: u16 = 1 << 5;
1798
1799impl Serialize for TileDef {
1800    type Input = Self;
1801    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1802        u8::serialize(&6, ser)?; // tiledef version
1803        String::serialize(&value.name, ser)?;
1804        TileAnimationParams::serialize(&value.animation, ser)?;
1805        let mut flags: u16 = 0;
1806        if value.backface_culling {
1807            flags |= TILE_FLAG_BACKFACE_CULLING;
1808        }
1809        if value.tileable_horizontal {
1810            flags |= TILE_FLAG_TILEABLE_HORIZONTAL;
1811        }
1812        if value.tileable_vertical {
1813            flags |= TILE_FLAG_TILEABLE_VERTICAL;
1814        }
1815        if value.color_rgb.is_some() {
1816            flags |= TILE_FLAG_HAS_COLOR;
1817        }
1818        if value.scale != 0 {
1819            flags |= TILE_FLAG_HAS_SCALE;
1820        }
1821        if value.align_style != AlignStyle::Node {
1822            flags |= TILE_FLAG_HAS_ALIGN_STYLE;
1823        }
1824        u16::serialize(&flags, ser)?;
1825        if let Some(color) = &value.color_rgb {
1826            u8::serialize(&color.0, ser)?;
1827            u8::serialize(&color.1, ser)?;
1828            u8::serialize(&color.2, ser)?;
1829        }
1830        if value.scale != 0 {
1831            u8::serialize(&value.scale, ser)?;
1832        }
1833        if value.align_style != AlignStyle::Node {
1834            AlignStyle::serialize(&value.align_style, ser)?;
1835        }
1836        Ok(())
1837    }
1838}
1839
1840impl Deserialize for TileDef {
1841    type Output = Self;
1842    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
1843        let version: u8 = u8::deserialize(deser)?;
1844        if version != 6 {
1845            bail!(DeserializeError::InvalidValue(
1846                "Invalid TileDef version".to_string(),
1847            ));
1848        }
1849        let name = String::deserialize(deser)?;
1850        let animation = TileAnimationParams::deserialize(deser)?;
1851        let flags = u16::deserialize(deser)?;
1852        let color = if (flags & TILE_FLAG_HAS_COLOR) != 0 {
1853            Some((
1854                u8::deserialize(deser)?,
1855                u8::deserialize(deser)?,
1856                u8::deserialize(deser)?,
1857            ))
1858        } else {
1859            None
1860        };
1861        let scale = if (flags & TILE_FLAG_HAS_SCALE) != 0 {
1862            u8::deserialize(deser)?
1863        } else {
1864            0
1865        };
1866        let align_style = if (flags & TILE_FLAG_HAS_ALIGN_STYLE) != 0 {
1867            AlignStyle::deserialize(deser)?
1868        } else {
1869            AlignStyle::Node
1870        };
1871
1872        Ok(Self {
1873            name,
1874            animation,
1875            backface_culling: (flags & TILE_FLAG_BACKFACE_CULLING) != 0,
1876            tileable_horizontal: (flags & TILE_FLAG_TILEABLE_HORIZONTAL) != 0,
1877            tileable_vertical: (flags & TILE_FLAG_TILEABLE_VERTICAL) != 0,
1878            color_rgb: color,
1879            scale,
1880            align_style,
1881        })
1882    }
1883}
1884
1885#[derive(Debug, Clone, PartialEq)]
1886pub enum TileAnimationParams {
1887    None,
1888    VerticalFrames {
1889        aspect_w: u16,
1890        aspect_h: u16,
1891        length: f32,
1892    },
1893    Sheet2D {
1894        frames_w: u8,
1895        frames_h: u8,
1896        frame_length: f32,
1897    },
1898}
1899
1900// TileAnimationType
1901const TAT_NONE: u8 = 0;
1902const TAT_VERTICAL_FRAMES: u8 = 1;
1903const TAT_SHEET_2D: u8 = 2;
1904
1905impl Serialize for TileAnimationParams {
1906    type Input = Self;
1907    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
1908        let typ = match value {
1909            TileAnimationParams::None => TAT_NONE,
1910            TileAnimationParams::VerticalFrames { .. } => TAT_VERTICAL_FRAMES,
1911            TileAnimationParams::Sheet2D { .. } => TAT_SHEET_2D,
1912        };
1913        u8::serialize(&typ, ser)?;
1914        match value {
1915            TileAnimationParams::None => {}
1916            TileAnimationParams::VerticalFrames {
1917                aspect_w,
1918                aspect_h,
1919                length,
1920            } => {
1921                u16::serialize(&aspect_w, ser)?;
1922                u16::serialize(&aspect_h, ser)?;
1923                f32::serialize(&length, ser)?;
1924            }
1925            TileAnimationParams::Sheet2D {
1926                frames_w,
1927                frames_h,
1928                frame_length,
1929            } => {
1930                u8::serialize(&frames_w, ser)?;
1931                u8::serialize(&frames_h, ser)?;
1932                f32::serialize(&frame_length, ser)?;
1933            }
1934        };
1935        Ok(())
1936    }
1937}
1938
1939impl Deserialize for TileAnimationParams {
1940    type Output = Self;
1941    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
1942        let typ = u8::deserialize(deser)?;
1943        match typ {
1944            TAT_NONE => Ok(TileAnimationParams::None),
1945            TAT_VERTICAL_FRAMES => Ok(TileAnimationParams::VerticalFrames {
1946                aspect_w: u16::deserialize(deser)?,
1947                aspect_h: u16::deserialize(deser)?,
1948                length: f32::deserialize(deser)?,
1949            }),
1950            TAT_SHEET_2D => Ok(TileAnimationParams::Sheet2D {
1951                frames_w: u8::deserialize(deser)?,
1952                frames_h: u8::deserialize(deser)?,
1953                frame_length: f32::deserialize(deser)?,
1954            }),
1955            _ => bail!(DeserializeError::InvalidValue(format!(
1956                "Invalid TileAnimationParams type {} at: {:?}",
1957                typ, deser.data
1958            ))),
1959        }
1960    }
1961}
1962
1963#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1964pub enum AlignStyle {
1965    Node,
1966    World,
1967    UserDefined,
1968}
1969
1970#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1971pub enum DrawType {
1972    Normal,
1973    AirLike,
1974    Liquid,
1975    FlowingLiquid,
1976    GlassLike,
1977    AllFaces,
1978    AllFacesOptional,
1979    TorchLike,
1980    SignLike,
1981    PlantLike,
1982    FenceLike,
1983    RailLike,
1984    NodeBox,
1985    GlassLikeFramed,
1986    FireLike,
1987    GlassLikeFramedOptional,
1988    Mesh,
1989    PlantLikeRooted,
1990}
1991
1992#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
1993pub struct ContentFeatures {
1994    pub version: u8,
1995    pub name: String,
1996    #[wrap(Array16<Pair<String, s16>>)]
1997    pub groups: Vec<(String, s16)>,
1998    pub param_type: u8,
1999    pub param_type_2: u8,
2000    pub drawtype: DrawType,
2001    pub mesh: String,
2002    pub visual_scale: f32,
2003    // this was an attempt to be tiledef length, but then they added an extra 6 tiledefs without fixing it
2004    pub unused_six: u8,
2005    #[wrap(FixedArray<6, TileDef>)]
2006    pub tiledef: [TileDef; 6],
2007    #[wrap(FixedArray<6, TileDef>)]
2008    pub tiledef_overlay: [TileDef; 6],
2009    #[wrap(Array8<TileDef>)]
2010    pub tiledef_special: Vec<TileDef>,
2011    pub alpha_for_legacy: u8,
2012    pub red: u8,
2013    pub green: u8,
2014    pub blue: u8,
2015    pub palette_name: String,
2016    pub waving: u8,
2017    pub connect_sides: u8,
2018    #[wrap(Array16<u16>)]
2019    pub connects_to_ids: Vec<u16>,
2020    pub post_effect_color: SColor,
2021    pub leveled: u8,
2022    pub light_propagates: u8,
2023    pub sunlight_propagates: u8,
2024    pub light_source: u8,
2025    pub is_ground_content: bool,
2026    pub walkable: bool,
2027    pub pointable: bool,
2028    pub diggable: bool,
2029    pub climbable: bool,
2030    pub buildable_to: bool,
2031    pub rightclickable: bool,
2032    pub damage_per_second: u32,
2033    pub liquid_type_bc: u8,
2034    pub liquid_alternative_flowing: String,
2035    pub liquid_alternative_source: String,
2036    pub liquid_viscosity: u8,
2037    pub liquid_renewable: bool,
2038    pub liquid_range: u8,
2039    pub drowning: u8,
2040    pub floodable: bool,
2041    pub node_box: NodeBox,
2042    pub selection_box: NodeBox,
2043    pub collision_box: NodeBox,
2044    pub sound_footstep: SimpleSoundSpec,
2045    pub sound_dig: SimpleSoundSpec,
2046    pub sound_dug: SimpleSoundSpec,
2047    pub legacy_facedir_simple: bool,
2048    pub legacy_wallmounted: bool,
2049    pub node_dig_prediction: Option<String>,
2050    pub leveled_max: Option<u8>,
2051    pub alpha: Option<AlphaMode>,
2052    pub move_resistance: Option<u8>,
2053    pub liquid_move_physics: Option<bool>,
2054}
2055
2056#[derive(Debug, Clone, PartialEq)]
2057pub enum NodeBox {
2058    Regular,
2059    Fixed(NodeBoxFixed),
2060    Wallmounted(NodeBoxWallmounted),
2061    Leveled(NodeBoxLeveled),
2062    Connected(NodeBoxConnected),
2063}
2064
2065impl Serialize for NodeBox {
2066    type Input = Self;
2067    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
2068        // Unused version number, always 6
2069        u8::serialize(&6, ser)?;
2070
2071        let typ = match value {
2072            NodeBox::Regular => 0,
2073            NodeBox::Fixed(_) => 1,
2074            NodeBox::Wallmounted(_) => 2,
2075            NodeBox::Leveled(_) => 3,
2076            NodeBox::Connected(_) => 4,
2077        };
2078        u8::serialize(&typ, ser)?;
2079        match value {
2080            NodeBox::Regular => Ok(()),
2081            NodeBox::Fixed(v) => NodeBoxFixed::serialize(v, ser),
2082            NodeBox::Wallmounted(v) => NodeBoxWallmounted::serialize(v, ser),
2083            NodeBox::Leveled(v) => NodeBoxLeveled::serialize(v, ser),
2084            NodeBox::Connected(v) => NodeBoxConnected::serialize(v, ser),
2085        }
2086    }
2087}
2088
2089impl Deserialize for NodeBox {
2090    type Output = Self;
2091    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
2092        let ver = u8::deserialize(deser)?;
2093        if ver != 6 {
2094            bail!(DeserializeError::InvalidValue(
2095                "Invalid NodeBox ver".to_string(),
2096            ));
2097        }
2098        let typ = u8::deserialize(deser)?;
2099        match typ {
2100            0 => Ok(NodeBox::Regular),
2101            1 => Ok(NodeBox::Fixed(NodeBoxFixed::deserialize(deser)?)),
2102            2 => Ok(NodeBox::Wallmounted(NodeBoxWallmounted::deserialize(
2103                deser,
2104            )?)),
2105            3 => Ok(NodeBox::Leveled(NodeBoxLeveled::deserialize(deser)?)),
2106            4 => Ok(NodeBox::Connected(NodeBoxConnected::deserialize(deser)?)),
2107            _ => bail!(DeserializeError::InvalidValue(
2108                "Invalid NodeBox type".to_string(),
2109            )),
2110        }
2111    }
2112}
2113
2114#[allow(non_camel_case_types)]
2115#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
2116pub struct aabb3f {
2117    pub min_edge: v3f,
2118    pub max_edge: v3f,
2119}
2120
2121#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
2122pub struct NodeBoxLeveled {
2123    #[wrap(Array16<aabb3f>)]
2124    pub fixed: Vec<aabb3f>,
2125}
2126
2127#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
2128pub struct NodeBoxFixed {
2129    #[wrap(Array16<aabb3f>)]
2130    pub fixed: Vec<aabb3f>,
2131}
2132
2133#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
2134pub struct NodeBoxWallmounted {
2135    pub wall_top: aabb3f,
2136    pub wall_bottom: aabb3f,
2137    pub wall_side: aabb3f,
2138}
2139
2140#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
2141pub struct NodeBoxConnected {
2142    #[wrap(Array16<aabb3f>)]
2143    pub fixed: Vec<aabb3f>,
2144    #[wrap(Array16<aabb3f>)]
2145    pub connect_top: Vec<aabb3f>,
2146    #[wrap(Array16<aabb3f>)]
2147    pub connect_bottom: Vec<aabb3f>,
2148    #[wrap(Array16<aabb3f>)]
2149    pub connect_front: Vec<aabb3f>,
2150    #[wrap(Array16<aabb3f>)]
2151    pub connect_left: Vec<aabb3f>,
2152    #[wrap(Array16<aabb3f>)]
2153    pub connect_back: Vec<aabb3f>,
2154    #[wrap(Array16<aabb3f>)]
2155    pub connect_right: Vec<aabb3f>,
2156    #[wrap(Array16<aabb3f>)]
2157    pub disconnected_top: Vec<aabb3f>,
2158    #[wrap(Array16<aabb3f>)]
2159    pub disconnected_bottom: Vec<aabb3f>,
2160    #[wrap(Array16<aabb3f>)]
2161    pub disconnected_front: Vec<aabb3f>,
2162    #[wrap(Array16<aabb3f>)]
2163    pub disconnected_left: Vec<aabb3f>,
2164    #[wrap(Array16<aabb3f>)]
2165    pub disconnected_back: Vec<aabb3f>,
2166    #[wrap(Array16<aabb3f>)]
2167    pub disconnected_right: Vec<aabb3f>,
2168    #[wrap(Array16<aabb3f>)]
2169    pub disconnected: Vec<aabb3f>,
2170    #[wrap(Array16<aabb3f>)]
2171    pub disconnected_sides: Vec<aabb3f>,
2172}
2173
2174#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
2175pub enum AlphaMode {
2176    Blend,
2177    Clip,
2178    Opaque,
2179    LegacyCompat,
2180}
2181
2182#[derive(Debug, Clone, PartialEq)]
2183pub struct NodeDefManager {
2184    pub content_features: Vec<(u16, ContentFeatures)>,
2185}
2186
2187/// The way this structure is encoded is really unusual, in order to
2188/// allow the ContentFeatures to be extended in the future without
2189/// changing the encoding.
2190impl Serialize for NodeDefManager {
2191    type Input = Self;
2192    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
2193        // Version
2194        u8::serialize(&1, ser)?;
2195        let count: u16 = u16::try_from(value.content_features.len())?;
2196        u16::serialize(&count, ser)?;
2197        // The serialization of content_features is wrapped in a String32
2198        // Write a marker so we can write the size later
2199        let string32_wrapper = ser.write_marker(4)?;
2200        for (i, f) in value.content_features.iter() {
2201            u16::serialize(i, ser)?;
2202            // The contents of each feature is wrapped in a String16.
2203            let string16_wrapper = ser.write_marker(2)?;
2204            ContentFeatures::serialize(f, ser)?;
2205            let wlen: u16 = u16::try_from(ser.marker_distance(&string16_wrapper))?;
2206            ser.set_marker(string16_wrapper, &wlen.to_be_bytes()[..])?;
2207        }
2208        let wlen: u32 = u32::try_from(ser.marker_distance(&string32_wrapper))?;
2209        ser.set_marker(string32_wrapper, &wlen.to_be_bytes()[..])?;
2210        Ok(())
2211    }
2212}
2213
2214impl Deserialize for NodeDefManager {
2215    type Output = Self;
2216    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
2217        let version = u8::deserialize(deser)?;
2218        if version != 1 {
2219            bail!(DeserializeError::InvalidValue(
2220                "Bad NodeDefManager version".to_string(),
2221            ));
2222        }
2223        let count: u16 = u16::deserialize(deser)?;
2224        let string32_wrapper_len: u32 = u32::deserialize(deser)?;
2225        // Shadow deser with a restricted deserializer
2226        let mut deser = deser.slice(string32_wrapper_len as usize)?;
2227        let mut content_features: Vec<(u16, ContentFeatures)> = Vec::with_capacity(count as usize);
2228        for _ in 0..count {
2229            let i = u16::deserialize(&mut deser)?;
2230            let string16_wrapper_len: u16 = u16::deserialize(&mut deser)?;
2231            let mut inner_deser = deser.slice(string16_wrapper_len as usize)?;
2232            let f = ContentFeatures::deserialize(&mut inner_deser)?;
2233            content_features.push((i, f));
2234        }
2235        Ok(Self { content_features })
2236    }
2237}
2238
2239// A "block" is 16x16x16 "nodes"
2240const MAP_BLOCKSIZE: u16 = 16;
2241
2242// Number of nodes in a block
2243const NODECOUNT: u16 = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
2244
2245#[derive(Debug, Clone, PartialEq)]
2246pub struct MapBlock {
2247    pub is_underground: bool,
2248    pub day_night_diff: bool,
2249    pub generated: bool,
2250    pub lighting_complete: Option<u16>,
2251    pub nodes: MapNodesBulk,
2252    pub node_metadata: NodeMetadataList, // m_node_metadata.serialize(os, version, disk);
2253}
2254
2255impl Serialize for MapBlock {
2256    /// MapBlock is a bit of a nightmare, because the compression algorithm
2257    /// and where the compression is applied (to the whole struct, or to
2258    /// parts of it) depends on the serialization format version.
2259    ///
2260    /// For now, only ser_fmt >= 28 is supported.
2261    /// For ver 28, only the nodes and nodemeta are compressed using zlib.
2262    /// For >= 29, the entire thing is compressed using zstd.
2263    type Input = Self;
2264    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
2265        let ver = ser.context().ser_fmt;
2266        let real_ser = ser;
2267        let mut tmp_ser = VecSerializer::new(real_ser.context(), 32768);
2268        let ser = &mut tmp_ser;
2269        let header = MapBlockHeader {
2270            is_underground: value.is_underground,
2271            day_night_diff: value.day_night_diff,
2272            generated: value.generated,
2273            lighting_complete: value.lighting_complete,
2274        };
2275        MapBlockHeader::serialize(&header, ser)?;
2276        if ver >= 29 {
2277            MapNodesBulk::serialize(&value.nodes, ser)?;
2278        } else {
2279            // Serialize and compress using zlib
2280            let mut inner = VecSerializer::new(ser.context(), 32768);
2281            MapNodesBulk::serialize(&value.nodes, &mut inner)?;
2282            let compressed = compress_zlib(&inner.take());
2283            ser.write_bytes(&compressed)?;
2284        }
2285        if ver >= 29 {
2286            NodeMetadataList::serialize(&value.node_metadata, ser)?;
2287        } else {
2288            // Serialize and compress using zlib
2289            let mut inner = VecSerializer::new(ser.context(), 32768);
2290            NodeMetadataList::serialize(&value.node_metadata, &mut inner)?;
2291            let compressed = compress_zlib(&inner.take());
2292            ser.write_bytes(&compressed)?;
2293        }
2294        if ver >= 29 {
2295            // The whole thing is zstd compressed
2296            let tmp = tmp_ser.take();
2297            zstd_compress(&tmp, |chunk| real_ser.write_bytes(chunk))?;
2298        } else {
2299            // Just write it directly
2300            let tmp = tmp_ser.take();
2301            real_ser.write_bytes(&tmp)?;
2302        }
2303        Ok(())
2304    }
2305}
2306
2307///
2308/// This is a helper for MapBlock ser/deser
2309/// Not exposed publicly.
2310struct MapBlockHeader {
2311    pub is_underground: bool,
2312    pub day_night_diff: bool,
2313    pub generated: bool,
2314    pub lighting_complete: Option<u16>,
2315}
2316
2317impl Serialize for MapBlockHeader {
2318    type Input = Self;
2319    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
2320        let mut flags: u8 = 0;
2321        if value.is_underground {
2322            flags |= 0x1;
2323        }
2324        if value.day_night_diff {
2325            flags |= 0x2;
2326        }
2327        if !value.generated {
2328            flags |= 0x8;
2329        }
2330        u8::serialize(&flags, ser)?;
2331        if ser.context().ser_fmt >= 27 {
2332            if let Some(lighting_complete) = value.lighting_complete {
2333                u16::serialize(&lighting_complete, ser)?;
2334            } else {
2335                bail!("lighting_complete must be set for ver >= 27");
2336            }
2337        }
2338        u8::serialize(&2, ser)?; // content_width == 2
2339        u8::serialize(&2, ser)?; // params_width == 2
2340        Ok(())
2341    }
2342}
2343
2344impl Deserialize for MapBlockHeader {
2345    type Output = Self;
2346    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
2347        let flags = u8::deserialize(deser)?;
2348        if flags != (flags & (0x1 | 0x2 | 0x8)) {
2349            bail!(DeserializeError::InvalidValue(
2350                "Invalid MapBlock flags".to_string(),
2351            ));
2352        }
2353        let lighting_complete = if deser.context().ser_fmt >= 27 {
2354            Some(u16::deserialize(deser)?)
2355        } else {
2356            None
2357        };
2358        let content_width = u8::deserialize(deser)?;
2359        let params_width = u8::deserialize(deser)?;
2360        if content_width != 2 || params_width != 2 {
2361            bail!(DeserializeError::InvalidValue(
2362                "Corrupt MapBlock: content_width and params_width not both 2".to_string(),
2363            ));
2364        }
2365        Ok(Self {
2366            is_underground: (flags & 0x1) != 0,
2367            day_night_diff: (flags & 0x2) != 0,
2368            generated: (flags & 0x8) == 0,
2369            lighting_complete: lighting_complete,
2370        })
2371    }
2372}
2373
2374impl Deserialize for MapBlock {
2375    type Output = Self;
2376    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
2377        let ver = deser.context().ser_fmt;
2378        if ver < 28 {
2379            bail!("Unsupported ser fmt");
2380        }
2381        // TODO(paradust): I can't make the borrow checker happy with sharing
2382        // code here, so for now the code has two different paths.
2383        if ver >= 29 {
2384            let mut tmp: Vec<u8> = Vec::new();
2385            // Decompress to a temporary buffer
2386            let bytes_taken = zstd_decompress(deser.peek_all(), |chunk| {
2387                tmp.extend_from_slice(chunk);
2388                Ok(())
2389            })?;
2390            deser.take(bytes_taken)?;
2391            let deser = &mut Deserializer::new(deser.context(), &tmp);
2392            let header = MapBlockHeader::deserialize(deser)?;
2393            let nodes = MapNodesBulk::deserialize(deser)?;
2394            let node_metadata = NodeMetadataList::deserialize(deser)?;
2395            Ok(Self {
2396                is_underground: header.is_underground,
2397                day_night_diff: header.day_night_diff,
2398                generated: header.generated,
2399                lighting_complete: header.lighting_complete,
2400                nodes,
2401                node_metadata,
2402            })
2403        } else {
2404            let header = MapBlockHeader::deserialize(deser)?;
2405            let (consumed, nodes_raw) = decompress_zlib(deser.peek_all())?;
2406            deser.take(consumed)?;
2407            let nodes = {
2408                let mut tmp = Deserializer::new(deser.context(), &nodes_raw);
2409                MapNodesBulk::deserialize(&mut tmp)?
2410            };
2411            let (consumed, metadata_raw) = decompress_zlib(deser.peek_all())?;
2412            deser.take(consumed)?;
2413            let node_metadata = {
2414                let mut tmp = Deserializer::new(deser.context(), &metadata_raw);
2415                NodeMetadataList::deserialize(&mut tmp)?
2416            };
2417            Ok(Self {
2418                is_underground: header.is_underground,
2419                day_night_diff: header.day_night_diff,
2420                generated: header.generated,
2421                lighting_complete: header.lighting_complete,
2422                nodes,
2423                node_metadata,
2424            })
2425        }
2426    }
2427}
2428
2429/// This has a special serialization, presumably to make it compress better.
2430/// Each param is stored in a separate array.
2431#[derive(Debug, Clone, PartialEq)]
2432pub struct MapNodesBulk {
2433    pub nodes: [MapNode; NODECOUNT as usize],
2434}
2435
2436impl Serialize for MapNodesBulk {
2437    type Input = Self;
2438    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
2439        let nodecount = NODECOUNT as usize;
2440        // Write all param0 first
2441        ser.write(2 * nodecount as usize, |buf| {
2442            assert!(buf.len() == 2 * nodecount as usize);
2443            for i in 0..nodecount {
2444                let v = value.nodes[i].param0.to_be_bytes();
2445                buf[2 * i] = v[0];
2446                buf[2 * i + 1] = v[1];
2447            }
2448        })?;
2449        // Write all param1
2450        ser.write(nodecount, |buf| {
2451            assert!(buf.len() == nodecount);
2452            for i in 0..nodecount {
2453                buf[i] = value.nodes[i].param1;
2454            }
2455        })?;
2456        // Write all param2
2457        ser.write(nodecount, |buf| {
2458            assert!(buf.len() == nodecount);
2459            for i in 0..nodecount {
2460                buf[i] = value.nodes[i].param2;
2461            }
2462        })?;
2463        Ok(())
2464    }
2465}
2466
2467impl Deserialize for MapNodesBulk {
2468    type Output = Self;
2469    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
2470        let nodecount = NODECOUNT as usize;
2471        let data = deser.take(4 * nodecount)?;
2472        let mut nodes: Vec<MapNode> = Vec::with_capacity(nodecount);
2473        let param1_offset = 2 * nodecount;
2474        let param2_offset = 3 * nodecount;
2475        for i in 0..nodecount {
2476            nodes.push(MapNode {
2477                param0: u16::from_be_bytes(data[2 * i..2 * i + 2].try_into().unwrap()),
2478                param1: data[param1_offset + i],
2479                param2: data[param2_offset + i],
2480            })
2481        }
2482        Ok(Self {
2483            nodes: match nodes.try_into() {
2484                Ok(value) => value,
2485                Err(_) => bail!("Bug in MapNodesBulk"),
2486            },
2487        })
2488    }
2489}
2490
2491/// The default serialization is used for single nodes.
2492/// But for transferring entire blocks, MapNodeBulk is used instead.
2493#[derive(Debug, Clone, Copy, PartialEq, MinetestSerialize, MinetestDeserialize)]
2494pub struct MapNode {
2495    pub param0: u16,
2496    pub param1: u8,
2497    pub param2: u8,
2498}
2499
2500#[derive(Debug, Clone, PartialEq)]
2501pub struct NodeMetadataList {
2502    pub metadata: Vec<(BlockPos, NodeMetadata)>,
2503}
2504
2505impl Serialize for NodeMetadataList {
2506    type Input = Self;
2507    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
2508        if value.metadata.len() == 0 {
2509            u8::serialize(&0, ser)?; // version 0 indicates no data
2510            return Ok(());
2511        }
2512        u8::serialize(&2, ser)?; // version == 2
2513        <Array16<Pair<BlockPos, NodeMetadata>> as Serialize>::serialize(&value.metadata, ser)?;
2514        Ok(())
2515    }
2516}
2517
2518impl Deserialize for NodeMetadataList {
2519    type Output = Self;
2520    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
2521        let ver = u8::deserialize(deser)?;
2522        if ver == 0 {
2523            return Ok(Self {
2524                metadata: Vec::new(),
2525            });
2526        } else if ver == 2 {
2527            Ok(Self {
2528                metadata: <Array16<Pair<BlockPos, NodeMetadata>> as Deserialize>::deserialize(
2529                    deser,
2530                )?,
2531            })
2532        } else {
2533            bail!(DeserializeError::InvalidValue(
2534                "Invalid NodeMetadataList version".to_string(),
2535            ))
2536        }
2537    }
2538}
2539
2540#[derive(Debug, Clone, PartialEq)]
2541pub struct AbsNodeMetadataList {
2542    pub metadata: Vec<(AbsBlockPos, NodeMetadata)>,
2543}
2544
2545impl Serialize for AbsNodeMetadataList {
2546    type Input = Self;
2547    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
2548        if value.metadata.len() == 0 {
2549            u8::serialize(&0, ser)?; // version 0 indicates no data
2550            return Ok(());
2551        }
2552        u8::serialize(&2, ser)?; // version == 2
2553        <Array16<Pair<AbsBlockPos, NodeMetadata>> as Serialize>::serialize(&value.metadata, ser)?;
2554        Ok(())
2555    }
2556}
2557
2558impl Deserialize for AbsNodeMetadataList {
2559    type Output = Self;
2560    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
2561        let ver = u8::deserialize(deser)?;
2562        if ver == 0 {
2563            return Ok(Self {
2564                metadata: Vec::new(),
2565            });
2566        } else if ver == 2 {
2567            Ok(Self {
2568                metadata: <Array16<Pair<AbsBlockPos, NodeMetadata>> as Deserialize>::deserialize(
2569                    deser,
2570                )?,
2571            })
2572        } else {
2573            bail!(DeserializeError::InvalidValue(
2574                "Invalid AbsNodeMetadataList version".to_string(),
2575            ))
2576        }
2577    }
2578}
2579
2580#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
2581pub struct AbsBlockPos {
2582    pos: v3s16,
2583}
2584
2585/// BlockPos addresses a node within a block
2586/// It is equivalent to (16*z + y)*16 + x, where x,y,z are from 0 to 15.
2587#[derive(Debug, Clone, PartialEq)]
2588pub struct BlockPos {
2589    pub raw: u16,
2590}
2591
2592impl BlockPos {
2593    pub fn new(x: s16, y: s16, z: s16) -> Self {
2594        let valid = 0..(MAP_BLOCKSIZE as s16);
2595        assert!(valid.contains(&x) && valid.contains(&y) && valid.contains(&z));
2596        let x = x as u16;
2597        let y = y as u16;
2598        let z = z as u16;
2599        Self {
2600            raw: (MAP_BLOCKSIZE * z + y) * MAP_BLOCKSIZE + x,
2601        }
2602    }
2603
2604    pub fn from_xyz(pos: v3s16) -> Self {
2605        Self::new(pos.x, pos.y, pos.z)
2606    }
2607
2608    pub fn to_xyz(&self) -> v3s16 {
2609        let x = self.raw % 16;
2610        let y = (self.raw / 16) % 16;
2611        let z = (self.raw / 256) % 16;
2612        v3s16::new(x as i16, y as i16, z as i16)
2613    }
2614}
2615
2616impl Serialize for BlockPos {
2617    type Input = Self;
2618    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
2619        u16::serialize(&value.raw, ser)?;
2620        Ok(())
2621    }
2622}
2623
2624impl Deserialize for BlockPos {
2625    type Output = Self;
2626    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
2627        let raw = u16::deserialize(deser)?;
2628        if raw >= 4096 {
2629            bail!(DeserializeError::InvalidValue(
2630                "Invalid BlockPos".to_string(),
2631            ))
2632        }
2633        Ok(Self { raw })
2634    }
2635}
2636
2637#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
2638pub struct NodeMetadata {
2639    #[wrap(Array32<StringVar>)]
2640    pub stringvars: Vec<StringVar>,
2641    pub inventory: Inventory,
2642}
2643
2644#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
2645pub struct StringVar {
2646    pub name: String,
2647    #[wrap(BinaryData32)]
2648    pub value: Vec<u8>,
2649    pub is_private: bool,
2650}
2651
2652#[derive(Debug, Clone, PartialEq)]
2653pub struct Inventory {
2654    pub entries: Vec<InventoryEntry>,
2655}
2656
2657#[derive(Debug, Clone, PartialEq)]
2658pub enum InventoryEntry {
2659    // Inventory lists to keep
2660    KeepList(String),
2661    // Inventory lists to add or update
2662    Update(InventoryList),
2663}
2664
2665/// Inventory is sent as a "almost" line-based text format.
2666/// Unfortutely there's no way to simplify this code, it has to mirror
2667/// the way Minetest does it exactly, because it is so arbitrary.
2668impl Serialize for Inventory {
2669    type Input = Self;
2670    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
2671        for entry in &value.entries {
2672            match entry {
2673                InventoryEntry::KeepList(list_name) => {
2674                    // TODO(paradust): Performance. A format!-like macro that
2675                    //                 writes directly to ser could be faster.
2676                    ser.write_bytes(b"KeepList ")?;
2677                    ser.write_bytes(list_name.as_bytes())?;
2678                    ser.write_bytes(b"\n")?;
2679                }
2680                InventoryEntry::Update(list) => {
2681                    // Takes care of the List header line
2682                    InventoryList::serialize(list, ser)?;
2683                }
2684            }
2685        }
2686        ser.write_bytes(b"EndInventory\n")?;
2687        Ok(())
2688    }
2689}
2690
2691impl Deserialize for Inventory {
2692    type Output = Self;
2693    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
2694        let mut result = Self {
2695            entries: Vec::new(),
2696        };
2697        while deser.remaining() > 0 {
2698            // Peek the line, but don't take it yet.
2699            let line = deser.peek_line()?;
2700            let words = split_by_whitespace(line);
2701            if words.len() == 0 {
2702                deser.take_line()?;
2703                continue;
2704            }
2705            let name = words[0];
2706            if name == b"EndInventory" || name == b"End" {
2707                // Take the line
2708                deser.take_line()?;
2709                return Ok(result);
2710            } else if name == b"List" {
2711                // InventoryList will take the line
2712                result
2713                    .entries
2714                    .push(InventoryEntry::Update(InventoryList::deserialize(deser)?));
2715            } else if name == b"KeepList" {
2716                if words.len() < 2 {
2717                    bail!(DeserializeError::InvalidValue(
2718                        "KeepList missing name".to_string(),
2719                    ));
2720                }
2721                match std::str::from_utf8(&words[1]) {
2722                    Ok(s) => result.entries.push(InventoryEntry::KeepList(s.to_string())),
2723                    Err(_) => {
2724                        bail!(DeserializeError::InvalidValue(
2725                            "KeepList name is invalid UTF8".to_string(),
2726                        ))
2727                    }
2728                }
2729                // Take the line
2730                deser.take_line()?;
2731            } else {
2732                // Anything else is supposed to be ignored. Gross.
2733                deser.take_line()?;
2734            }
2735        }
2736        // If we ran out before seeing the end marker, it's an error
2737        bail!(DeserializeError::Eof)
2738    }
2739}
2740
2741#[derive(Debug, Clone, PartialEq)]
2742pub struct InventoryList {
2743    pub name: String,
2744    pub width: u32,
2745    pub items: Vec<ItemStackUpdate>,
2746}
2747
2748#[derive(Debug, Clone, PartialEq)]
2749pub enum ItemStackUpdate {
2750    Empty,
2751    Keep, // this seems to not be used yet
2752    Item(ItemStack),
2753}
2754
2755impl Serialize for InventoryList {
2756    type Input = Self;
2757    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
2758        // List <name> <size>
2759        ser.write_bytes(b"List ")?;
2760        ser.write_bytes(value.name.as_bytes())?;
2761        ser.write_bytes(b" ")?;
2762        ser.write_bytes(value.items.len().to_string().as_bytes())?;
2763        ser.write_bytes(b"\n")?;
2764
2765        // Width <width>
2766        ser.write_bytes(b"Width ")?;
2767        ser.write_bytes(value.width.to_string().as_bytes())?;
2768        ser.write_bytes(b"\n")?;
2769
2770        for item in value.items.iter() {
2771            match item {
2772                ItemStackUpdate::Empty => ser.write_bytes(b"Empty\n")?,
2773                ItemStackUpdate::Keep => ser.write_bytes(b"Keep\n")?,
2774                ItemStackUpdate::Item(itemstack) => {
2775                    // Writes Item line
2776                    ItemStack::serialize(itemstack, ser)?;
2777                }
2778            }
2779        }
2780        ser.write_bytes(b"EndInventoryList\n")?;
2781        Ok(())
2782    }
2783}
2784
2785impl Deserialize for InventoryList {
2786    type Output = Self;
2787    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
2788        // First line should be: List <name> <item_count>
2789        let line = deser.take_line()?;
2790        let words = split_by_whitespace(line);
2791        if words.len() != 3 || words[0] != b"List" {
2792            bail!(DeserializeError::InvalidValue(
2793                "Broken List tag".to_string(),
2794            ));
2795        }
2796        let list_name = std::str::from_utf8(words[1])?;
2797        let _count: u32 = stoi(words[2])?;
2798        let mut result = Self {
2799            name: list_name.to_string(),
2800            width: 0,
2801            items: Vec::new(),
2802        };
2803        while deser.remaining() > 0 {
2804            // Peek the line, but don't take it yet.
2805            let line = deser.peek_line()?;
2806            let words = split_by_whitespace(line);
2807            if words.len() == 0 {
2808                deser.take_line()?;
2809                continue;
2810            }
2811            let name = words[0];
2812            if name == b"EndInventoryList" || name == b"end" {
2813                deser.take_line()?;
2814                return Ok(result);
2815            } else if name == b"Width" {
2816                if words.len() < 2 {
2817                    bail!(DeserializeError::InvalidValue(
2818                        "Width value missing".to_string(),
2819                    ));
2820                }
2821                result.width = stoi(words[1])?;
2822                deser.take_line()?;
2823            } else if name == b"Item" {
2824                // ItemStack takes the line
2825                result
2826                    .items
2827                    .push(ItemStackUpdate::Item(ItemStack::deserialize(deser)?));
2828            } else if name == b"Empty" {
2829                result.items.push(ItemStackUpdate::Empty);
2830                deser.take_line()?;
2831            } else if name == b"Keep" {
2832                result.items.push(ItemStackUpdate::Keep);
2833                deser.take_line()?;
2834            } else {
2835                // Ignore unrecognized lines
2836                deser.take_line()?;
2837            }
2838        }
2839        bail!(DeserializeError::Eof)
2840    }
2841}
2842
2843// Custom deserialization, part of Inventory
2844#[derive(Debug, Clone, PartialEq)]
2845pub struct ItemStack {
2846    pub name: String,
2847    pub count: u16,
2848    pub wear: u16,
2849    pub metadata: ItemStackMetadata,
2850}
2851
2852impl Serialize for ItemStack {
2853    type Input = Self;
2854    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
2855        // Item <name_json> [count] [wear] [metadata]
2856        ser.write_bytes(b"Item ")?;
2857        serialize_json_string_if_needed(&value.name.as_bytes(), |chunk| {
2858            Ok(ser.write_bytes(chunk)?)
2859        })?;
2860
2861        let mut parts = 1;
2862        if !value.metadata.string_vars.is_empty() {
2863            parts = 4;
2864        } else if value.wear != 0 {
2865            parts = 3;
2866        } else if value.count != 1 {
2867            parts = 2;
2868        }
2869
2870        if parts >= 2 {
2871            ser.write_bytes(b" ")?;
2872            ser.write_bytes(value.count.to_string().as_bytes())?;
2873        }
2874        if parts >= 3 {
2875            ser.write_bytes(b" ")?;
2876            ser.write_bytes(value.wear.to_string().as_bytes())?;
2877        }
2878        if parts >= 4 {
2879            ser.write_bytes(b" ")?;
2880            ItemStackMetadata::serialize(&value.metadata, ser)?;
2881        }
2882        ser.write_bytes(b"\n")?;
2883        Ok(())
2884    }
2885}
2886
2887impl Deserialize for ItemStack {
2888    type Output = Self;
2889    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
2890        // Item "name maybe escaped" [count] [wear] ["metadata escaped"]
2891        let line = deser.take_line()?;
2892        let err = DeserializeError::InvalidValue("Truncated Item line".to_string());
2893        let (word, line) = next_word(line).ok_or(err)?;
2894        if word != b"Item" {
2895            bail!(DeserializeError::InvalidValue(
2896                "Invalid Item line".to_string(),
2897            ));
2898        }
2899        let line = skip_whitespace(line);
2900        let (name, skip) = deserialize_json_string_if_needed(line)?;
2901        let line = skip_whitespace(&line[skip..]);
2902
2903        let mut result = Self {
2904            name: std::str::from_utf8(&name)?.to_string(),
2905            count: 1,
2906            wear: 0,
2907            metadata: ItemStackMetadata {
2908                string_vars: Vec::new(),
2909            },
2910        };
2911        if let Some((word, line)) = next_word(line) {
2912            result.count = stoi(word)?;
2913            if let Some((word, line)) = next_word(line) {
2914                result.wear = stoi(word)?;
2915                let line = skip_whitespace(line);
2916                if line.len() > 0 {
2917                    let mut tmp_deser = Deserializer::new(deser.context(), line);
2918                    result.metadata = ItemStackMetadata::deserialize(&mut tmp_deser)?;
2919                }
2920            }
2921        }
2922        Ok(result)
2923    }
2924}
2925
2926// Custom deserialization as json blob
2927#[derive(Debug, Clone, PartialEq)]
2928pub struct ItemStackMetadata {
2929    pub string_vars: Vec<(ByteString, ByteString)>,
2930}
2931
2932const DESERIALIZE_START: &[u8; 1] = b"\x01";
2933const DESERIALIZE_KV_DELIM: &[u8; 1] = b"\x02";
2934const DESERIALIZE_PAIR_DELIM: &[u8; 1] = b"\x03";
2935
2936impl Serialize for ItemStackMetadata {
2937    type Input = Self;
2938    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
2939        let mut buf: Vec<u8> = Vec::new();
2940        buf.extend(DESERIALIZE_START);
2941        for (key, val) in value.string_vars.iter() {
2942            if !key.is_empty() || !val.is_empty() {
2943                buf.extend(key.as_bytes());
2944                buf.extend(DESERIALIZE_KV_DELIM);
2945                buf.extend(val.as_bytes());
2946                buf.extend(DESERIALIZE_PAIR_DELIM);
2947            }
2948        }
2949        serialize_json_string_if_needed(&buf, |chunk| ser.write_bytes(chunk))?;
2950        Ok(())
2951    }
2952}
2953
2954impl Deserialize for ItemStackMetadata {
2955    type Output = Self;
2956    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
2957        let (raw, count) = deserialize_json_string_if_needed(deser.peek_all())?;
2958        deser.take(count)?;
2959        let mut result = Self {
2960            string_vars: Vec::new(),
2961        };
2962        let raw = &raw[..]; // easier to work with slice
2963        if raw.len() == 0 {
2964            return Ok(result);
2965        }
2966        if raw[0] != DESERIALIZE_START[0] {
2967            bail!(DeserializeError::InvalidValue(
2968                "ItemStackMetadata bad start".to_string(),
2969            ));
2970        }
2971        let mut raw = &raw[1..];
2972        // This is odd, but matches the behavior of ItemStackMetadata::deSerialize
2973        while raw.len() != 0 {
2974            let kv_delim_pos = raw
2975                .iter()
2976                .position(|ch| *ch == DESERIALIZE_KV_DELIM[0])
2977                .unwrap_or(raw.len());
2978            let name = &raw[..kv_delim_pos];
2979            raw = &raw[kv_delim_pos..];
2980            if raw.len() > 0 {
2981                raw = &raw[1..];
2982            }
2983            let pair_delim_pos = raw
2984                .iter()
2985                .position(|ch| *ch == DESERIALIZE_PAIR_DELIM[0])
2986                .unwrap_or(raw.len());
2987            let var = &raw[..pair_delim_pos];
2988            raw = &raw[pair_delim_pos..];
2989            if raw.len() > 0 {
2990                raw = &raw[1..];
2991            }
2992            result.string_vars.push((name.into(), var.into()));
2993        }
2994        Ok(result)
2995    }
2996}
2997
2998/// This is the way ADD_PARTICLESPAWNER is serialized.
2999/// It seems to be an older version of ParticleParameters
3000#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
3001pub struct AddParticleSpawnerLegacy {
3002    pub amount: u16,
3003    pub time: f32,
3004
3005    // start only
3006    pub pos_start: RangedParameterLegacy<v3f>,
3007    pub vel_start: RangedParameterLegacy<v3f>,
3008    pub acc_start: RangedParameterLegacy<v3f>,
3009    pub exptime_start: RangedParameterLegacy<f32>,
3010    pub size_start: RangedParameterLegacy<f32>,
3011
3012    pub collision_detection: bool,
3013    #[wrap(LongString)]
3014    pub texture_string: String,
3015    pub id: u32,
3016    pub vertical: bool,
3017    pub collision_removal: bool,
3018    pub attached_id: u16,
3019    pub animation: TileAnimationParams,
3020    pub glow: u8,
3021    pub object_collision: bool,
3022    pub node_param0: u16,
3023    pub node_param2: u8,
3024    pub node_tile: u8,
3025
3026    // Only present in protocol_ver >= 40
3027    pub extra: Option<AddParticleSpawnerExtra>,
3028}
3029
3030#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
3031pub struct AddParticleSpawnerExtra {
3032    pub pos_start_bias: f32,
3033    pub vel_start_bias: f32,
3034    pub acc_start_bias: f32,
3035    pub exptime_start_bias: f32,
3036    pub size_start_bias: f32,
3037
3038    pub pos_end: RangedParameter<v3f>,
3039    pub vel_end: RangedParameter<v3f>,
3040    pub acc_end: RangedParameter<v3f>,
3041    pub exptime_end: RangedParameter<f32>,
3042    pub size_end: RangedParameter<f32>,
3043
3044    pub texture: ServerParticleTextureNewPropsOnly,
3045
3046    pub drag: TweenedParameter<RangedParameter<v3f>>,
3047    pub jitter: TweenedParameter<RangedParameter<v3f>>,
3048    pub bounce: TweenedParameter<RangedParameter<f32>>,
3049    pub attractor: Attractor, // attract_kind, followed by p.attract.serialize, p.attract_origin.ser, etc
3050    pub radius: TweenedParameter<RangedParameter<v3f>>,
3051    #[wrap(Array16<ServerParticleTexture>)]
3052    pub texpool: Vec<ServerParticleTexture>,
3053}
3054
3055#[derive(Debug, Clone, PartialEq)]
3056pub enum Attractor {
3057    None,
3058    Point(PointAttractor),
3059    Line(LineAttractor),
3060    Plane(PlaneAttractor),
3061}
3062
3063impl Serialize for Attractor {
3064    type Input = Self;
3065    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
3066        let kind: u8 = match value {
3067            Attractor::None => 0,
3068            Attractor::Point(_) => 1,
3069            Attractor::Line(_) => 2,
3070            Attractor::Plane(_) => 3,
3071        };
3072        u8::serialize(&kind, ser)?;
3073        match value {
3074            Attractor::None => (),
3075            Attractor::Point(v) => PointAttractor::serialize(v, ser)?,
3076            Attractor::Line(v) => LineAttractor::serialize(v, ser)?,
3077            Attractor::Plane(v) => PlaneAttractor::serialize(v, ser)?,
3078        }
3079        Ok(())
3080    }
3081}
3082
3083impl Deserialize for Attractor {
3084    type Output = Self;
3085    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
3086        let kind = u8::deserialize(deser)?;
3087        Ok(match kind {
3088            0 => Attractor::None,
3089            1 => Attractor::Point(PointAttractor::deserialize(deser)?),
3090            2 => Attractor::Line(LineAttractor::deserialize(deser)?),
3091            3 => Attractor::Plane(PlaneAttractor::deserialize(deser)?),
3092            _ => bail!("Invalid AttractorKind: {}", kind),
3093        })
3094    }
3095}
3096
3097#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
3098pub struct PointAttractor {
3099    pub attract: TweenedParameter<RangedParameter<f32>>,
3100    pub origin: TweenedParameter<v3f>,
3101    pub attachment: u16,
3102    pub kill: u8,
3103}
3104
3105#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
3106pub struct LineAttractor {
3107    pub attract: TweenedParameter<RangedParameter<f32>>,
3108    pub origin: TweenedParameter<v3f>,
3109    pub attachment: u16,
3110    pub kill: u8,
3111    pub direction: TweenedParameter<v3f>,
3112    pub direction_attachment: u16,
3113}
3114
3115#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
3116pub struct PlaneAttractor {
3117    pub attract: TweenedParameter<RangedParameter<f32>>,
3118    pub origin: TweenedParameter<v3f>,
3119    pub attachment: u16,
3120    pub kill: u8,
3121    pub direction: TweenedParameter<v3f>,
3122    pub direction_attachment: u16,
3123}
3124
3125/// This is serialized as part of a combined 'flags' field on
3126/// ServerParticleTexture, so it doesn't implement the  methods
3127/// on its own.
3128#[derive(Debug, Clone, PartialEq)]
3129pub enum BlendMode {
3130    Alpha,
3131    Add,
3132    Sub,
3133    Screen,
3134}
3135
3136impl BlendMode {
3137    fn to_u8(&self) -> u8 {
3138        match self {
3139            BlendMode::Alpha => 0,
3140            BlendMode::Add => 1,
3141            BlendMode::Sub => 2,
3142            BlendMode::Screen => 3,
3143        }
3144    }
3145
3146    fn from_u8(value: u8) -> DeserializeResult<BlendMode> {
3147        Ok(match value {
3148            0 => BlendMode::Alpha,
3149            1 => BlendMode::Add,
3150            2 => BlendMode::Sub,
3151            3 => BlendMode::Screen,
3152            _ => bail!("Invalid BlendMode u8: {}", value),
3153        })
3154    }
3155}
3156
3157#[derive(Debug, Clone, PartialEq)]
3158pub struct ServerParticleTextureNewPropsOnly {
3159    pub blend_mode: BlendMode,
3160    pub alpha: TweenedParameter<f32>,
3161    pub scale: TweenedParameter<v2f>,
3162    pub animation: Option<TileAnimationParams>,
3163}
3164
3165impl Serialize for ServerParticleTextureNewPropsOnly {
3166    type Input = Self;
3167    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
3168        let mut flags: u8 = value.blend_mode.to_u8() << 1;
3169        if value.animation.is_some() {
3170            flags |= 1;
3171        }
3172        u8::serialize(&flags, ser)?;
3173        <TweenedParameter<f32>>::serialize(&value.alpha, ser)?;
3174        <TweenedParameter<v2f>>::serialize(&value.scale, ser)?;
3175        <Option<TileAnimationParams>>::serialize(&value.animation, ser)?;
3176        Ok(())
3177    }
3178}
3179
3180impl Deserialize for ServerParticleTextureNewPropsOnly {
3181    type Output = Self;
3182    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
3183        let flags: u8 = u8::deserialize(deser)?;
3184        let animated: bool = (flags & 1) != 0;
3185        let blend_mode = BlendMode::from_u8(flags >> 1)?;
3186        Ok(Self {
3187            blend_mode,
3188            alpha: <TweenedParameter<f32>>::deserialize(deser)?,
3189            scale: <TweenedParameter<v2f>>::deserialize(deser)?,
3190            animation: if animated {
3191                <Option<TileAnimationParams>>::deserialize(deser)?
3192            } else {
3193                None
3194            },
3195        })
3196    }
3197}
3198
3199#[derive(Debug, Clone, PartialEq)]
3200pub struct ServerParticleTexture {
3201    pub blend_mode: BlendMode,
3202    pub alpha: TweenedParameter<f32>,
3203    pub scale: TweenedParameter<v2f>,
3204    pub string: String, // LongString
3205    pub animation: Option<TileAnimationParams>,
3206}
3207
3208impl Serialize for ServerParticleTexture {
3209    type Input = Self;
3210    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
3211        let mut flags: u8 = value.blend_mode.to_u8() << 1;
3212        if value.animation.is_some() {
3213            flags |= 1;
3214        }
3215        u8::serialize(&flags, ser)?;
3216        <TweenedParameter<f32>>::serialize(&value.alpha, ser)?;
3217        <TweenedParameter<v2f>>::serialize(&value.scale, ser)?;
3218        LongString::serialize(&value.string, ser)?;
3219        <Option<TileAnimationParams>>::serialize(&value.animation, ser)?;
3220        Ok(())
3221    }
3222}
3223
3224impl Deserialize for ServerParticleTexture {
3225    type Output = Self;
3226    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
3227        let flags: u8 = u8::deserialize(deser)?;
3228        let animated: bool = (flags & 1) != 0;
3229        let blend_mode = BlendMode::from_u8(flags >> 1)?;
3230        Ok(Self {
3231            blend_mode,
3232            alpha: <TweenedParameter<f32>>::deserialize(deser)?,
3233            scale: <TweenedParameter<v2f>>::deserialize(deser)?,
3234            string: LongString::deserialize(deser)?,
3235            animation: if animated {
3236                <Option<TileAnimationParams>>::deserialize(deser)?
3237            } else {
3238                None
3239            },
3240        })
3241    }
3242}
3243
3244#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
3245pub enum TweenStyle {
3246    Fwd,
3247    Rev,
3248    Pulse,
3249    Flicker,
3250}
3251
3252#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
3253pub struct TweenedParameter<T: Serialize + Deserialize>
3254where
3255    T: Serialize<Input = T>,
3256    T: Deserialize<Output = T>,
3257{
3258    pub style: TweenStyle,
3259    pub reps: u16,
3260    pub beginning: f32,
3261    pub start: T,
3262    pub end: T,
3263}
3264
3265/// This is the send format used by SendSpawnParticle
3266/// See ParticleParameters::serialize
3267#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
3268pub struct ParticleParameters {
3269    pub pos: v3f,
3270    pub vel: v3f,
3271    pub acc: v3f,
3272    pub expiration_time: f32,
3273    pub size: f32,
3274    pub collision_detection: bool,
3275    #[wrap(LongString)]
3276    pub texture: String, // ServerParticleTexture.string
3277    pub vertical: bool,
3278    pub collision_removal: bool,
3279    pub animation: TileAnimationParams,
3280    pub glow: u8,
3281    pub object_collision: bool,
3282    // These are omitted in earlier protocol versions
3283    pub node_param0: Option<u16>,
3284    pub node_param2: Option<u8>,
3285    pub node_tile: Option<u8>,
3286    pub drag: Option<v3f>,
3287    pub jitter: Option<RangedParameter<v3f>>,
3288    pub bounce: Option<RangedParameter<f32>>,
3289}
3290
3291#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
3292pub struct RangedParameter<T: Serialize + Deserialize>
3293where
3294    T: Serialize<Input = T>,
3295    T: Deserialize<Output = T>,
3296{
3297    pub min: T,
3298    pub max: T,
3299    pub bias: f32,
3300}
3301
3302#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
3303pub struct RangedParameterLegacy<T: Serialize + Deserialize>
3304where
3305    T: Serialize<Input = T>,
3306    T: Deserialize<Output = T>,
3307{
3308    pub min: T,
3309    pub max: T,
3310}
3311
3312#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
3313pub struct Lighting {
3314    pub shadow_intensity: f32,
3315    pub saturation: f32,
3316    pub exposure: AutoExposure,
3317}
3318
3319#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
3320pub struct AutoExposure {
3321    pub luminance_min: f32,
3322    pub luminance_max: f32,
3323    pub exposure_correction: f32,
3324    pub speed_dark_bright: f32,
3325    pub speed_bright_dark: f32,
3326    pub center_weight_power: f32,
3327}
3328
3329#[derive(Debug, Clone, PartialEq)]
3330pub enum HudSetParam {
3331    SetHotBarItemCount(s32),
3332    SetHotBarImage(String),
3333    SetHotBarSelectedImage(String),
3334}
3335
3336impl Serialize for HudSetParam {
3337    type Input = Self;
3338    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
3339        use HudSetParam::*;
3340        let param: u16 = match value {
3341            SetHotBarItemCount(_) => 1,
3342            SetHotBarImage(_) => 2,
3343            SetHotBarSelectedImage(_) => 3,
3344        };
3345        u16::serialize(&param, ser)?;
3346        match value {
3347            SetHotBarItemCount(v) => {
3348                // The value is wrapped in a a String16
3349                u16::serialize(&4, ser)?;
3350                s32::serialize(v, ser)?;
3351            }
3352            SetHotBarImage(v) => String::serialize(v, ser)?,
3353            SetHotBarSelectedImage(v) => String::serialize(v, ser)?,
3354        };
3355        Ok(())
3356    }
3357}
3358
3359impl Deserialize for HudSetParam {
3360    type Output = Self;
3361    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
3362        use HudSetParam::*;
3363        let param = u16::deserialize(deser)?;
3364        Ok(match param {
3365            1 => {
3366                let size = u16::deserialize(deser)?;
3367                if size != 4 {
3368                    bail!("Invalid size in SetHotBarItemCount: {}", size);
3369                }
3370                SetHotBarItemCount(s32::deserialize(deser)?)
3371            }
3372            2 => SetHotBarImage(String::deserialize(deser)?),
3373            3 => SetHotBarSelectedImage(String::deserialize(deser)?),
3374            _ => bail!("Invalid HudSetParam param: {}", param),
3375        })
3376    }
3377}
3378
3379#[derive(Debug, Clone, PartialEq)]
3380pub struct HudFlags {
3381    pub hotbar_visible: bool,
3382    pub healthbar_visible: bool,
3383    pub crosshair_visible: bool,
3384    pub wielditem_visible: bool,
3385    pub breathbar_visible: bool,
3386    pub minimap_visible: bool,
3387    pub minimap_radar_visible: bool,
3388    pub basic_debug: bool,
3389    pub chat_visible: bool,
3390}
3391
3392impl HudFlags {
3393    pub fn to_u32(&self) -> u32 {
3394        let mut flags: u32 = 0;
3395        flags |= (self.hotbar_visible as u32) << 0;
3396        flags |= (self.healthbar_visible as u32) << 1;
3397        flags |= (self.crosshair_visible as u32) << 2;
3398        flags |= (self.wielditem_visible as u32) << 3;
3399        flags |= (self.breathbar_visible as u32) << 4;
3400        flags |= (self.minimap_visible as u32) << 5;
3401        flags |= (self.minimap_radar_visible as u32) << 6;
3402        flags |= (self.basic_debug as u32) << 7;
3403        flags |= (self.chat_visible as u32) << 8;
3404        flags
3405    }
3406
3407    pub fn from_u32(flags: u32) -> Self {
3408        Self {
3409            hotbar_visible: (flags & (1 << 0)) != 0,
3410            healthbar_visible: (flags & (1 << 1)) != 0,
3411            crosshair_visible: (flags & (1 << 2)) != 0,
3412            wielditem_visible: (flags & (1 << 3)) != 0,
3413            breathbar_visible: (flags & (1 << 4)) != 0,
3414            minimap_visible: (flags & (1 << 5)) != 0,
3415            minimap_radar_visible: (flags & (1 << 6)) != 0,
3416            basic_debug: (flags & (1 << 7)) != 0,
3417            chat_visible: (flags & (1 << 8)) != 0,
3418        }
3419    }
3420}
3421
3422impl Serialize for HudFlags {
3423    type Input = Self;
3424    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
3425        let value = value.to_u32();
3426        u32::serialize(&value, ser)
3427    }
3428}
3429
3430impl Deserialize for HudFlags {
3431    type Output = Self;
3432    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
3433        let value = u32::deserialize(deser)?;
3434        if (value & !0b111111111) != 0 {
3435            bail!("Invalid HudFlags: {}", value);
3436        }
3437        Ok(HudFlags::from_u32(value))
3438    }
3439}
3440
3441#[derive(Debug, Clone, PartialEq, MinetestSerialize, MinetestDeserialize)]
3442pub enum InteractAction {
3443    StartDigging,
3444    StopDigging,
3445    DiggingCompleted,
3446    Place,
3447    Use,
3448    Activate,
3449}
3450
3451#[derive(Debug, Clone, PartialEq)]
3452pub enum PointedThing {
3453    Nothing,
3454    Node {
3455        under_surface: v3s16,
3456        above_surface: v3s16,
3457    },
3458    Object {
3459        object_id: u16,
3460    },
3461}
3462
3463impl Serialize for PointedThing {
3464    type Input = Self;
3465    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
3466        // version, always 0
3467        u8::serialize(&0, ser)?;
3468
3469        let typ: u8 = match value {
3470            PointedThing::Nothing => 0,
3471            PointedThing::Node { .. } => 1,
3472            PointedThing::Object { .. } => 2,
3473        };
3474        u8::serialize(&typ, ser)?;
3475
3476        match value {
3477            PointedThing::Nothing => (),
3478            PointedThing::Node {
3479                under_surface,
3480                above_surface,
3481            } => {
3482                v3s16::serialize(under_surface, ser)?;
3483                v3s16::serialize(above_surface, ser)?;
3484            }
3485            PointedThing::Object { object_id } => {
3486                u16::serialize(object_id, ser)?;
3487            }
3488        }
3489        Ok(())
3490    }
3491}
3492
3493impl Deserialize for PointedThing {
3494    type Output = Self;
3495    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
3496        let ver = u8::deserialize(deser)?;
3497        if ver != 0 {
3498            bail!("Invalid PointedThing version: {}", ver);
3499        }
3500        let typ = u8::deserialize(deser)?;
3501        Ok(match typ {
3502            0 => PointedThing::Nothing,
3503            1 => PointedThing::Node {
3504                under_surface: v3s16::deserialize(deser)?,
3505                above_surface: v3s16::deserialize(deser)?,
3506            },
3507            2 => PointedThing::Object {
3508                object_id: u16::deserialize(deser)?,
3509            },
3510            _ => bail!("Invalid PointedThing type: {}", typ),
3511        })
3512    }
3513}
3514
3515#[derive(Debug, Clone, PartialEq)]
3516pub enum InventoryAction {
3517    Move {
3518        count: u16,
3519        from_inv: InventoryLocation,
3520        from_list: String,
3521        from_i: s16,
3522        to_inv: InventoryLocation,
3523        to_list: String,
3524        to_i: Option<s16>,
3525    },
3526    Craft {
3527        count: u16,
3528        craft_inv: InventoryLocation,
3529    },
3530    Drop {
3531        count: u16,
3532        from_inv: InventoryLocation,
3533        from_list: String,
3534        from_i: s16,
3535    },
3536}
3537
3538impl Serialize for InventoryAction {
3539    type Input = Self;
3540    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
3541        match value {
3542            InventoryAction::Move {
3543                count,
3544                from_inv,
3545                from_list,
3546                from_i,
3547                to_inv,
3548                to_list,
3549                to_i,
3550            } => {
3551                if to_i.is_some() {
3552                    ser.write_bytes(b"Move ")?;
3553                } else {
3554                    ser.write_bytes(b"MoveSomewhere ")?;
3555                }
3556                ser.write_bytes(itos!(count))?;
3557                ser.write_bytes(b" ")?;
3558                InventoryLocation::serialize(from_inv, ser)?;
3559                ser.write_bytes(b" ")?;
3560                ser.write_bytes(from_list.as_bytes())?;
3561                ser.write_bytes(b" ")?;
3562                ser.write_bytes(itos!(from_i))?;
3563                ser.write_bytes(b" ")?;
3564                InventoryLocation::serialize(to_inv, ser)?;
3565                ser.write_bytes(b" ")?;
3566                ser.write_bytes(to_list.as_bytes())?;
3567                if let Some(to_i) = to_i {
3568                    ser.write_bytes(b" ")?;
3569                    ser.write_bytes(itos!(to_i))?;
3570                }
3571            }
3572            InventoryAction::Craft { count, craft_inv } => {
3573                ser.write_bytes(b"Craft ")?;
3574                ser.write_bytes(itos!(count))?;
3575                ser.write_bytes(b" ")?;
3576                InventoryLocation::serialize(craft_inv, ser)?;
3577                // This extra space is present in Minetest
3578                ser.write_bytes(b" ")?;
3579            }
3580            InventoryAction::Drop {
3581                count,
3582                from_inv,
3583                from_list,
3584                from_i,
3585            } => {
3586                ser.write_bytes(b"Drop ")?;
3587                ser.write_bytes(itos!(count))?;
3588                ser.write_bytes(b" ")?;
3589                InventoryLocation::serialize(from_inv, ser)?;
3590                ser.write_bytes(b" ")?;
3591                ser.write_bytes(from_list.as_bytes())?;
3592                ser.write_bytes(b" ")?;
3593                ser.write_bytes(itos!(from_i))?;
3594            }
3595        }
3596        Ok(())
3597    }
3598}
3599
3600impl Deserialize for InventoryAction {
3601    type Output = Self;
3602    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
3603        let word = deser.take_word(true);
3604        if word == b"Move" || word == b"MoveSomewhere" {
3605            Ok(InventoryAction::Move {
3606                count: stoi(deser.take_word(true))?,
3607                from_inv: InventoryLocation::deserialize(deser)?,
3608                from_list: std::str::from_utf8(deser.take_word(true))?.to_owned(),
3609                from_i: stoi(deser.take_word(true))?,
3610                to_inv: InventoryLocation::deserialize(deser)?,
3611                to_list: std::str::from_utf8(deser.take_word(true))?.to_owned(),
3612                to_i: if word == b"Move" {
3613                    Some(stoi(deser.take_word(true))?)
3614                } else {
3615                    None
3616                },
3617            })
3618        } else if word == b"Drop" {
3619            Ok(InventoryAction::Drop {
3620                count: stoi(deser.take_word(true))?,
3621                from_inv: InventoryLocation::deserialize(deser)?,
3622                from_list: std::str::from_utf8(deser.take_word(true))?.to_owned(),
3623                from_i: stoi(deser.take_word(true))?,
3624            })
3625        } else if word == b"Craft" {
3626            Ok(InventoryAction::Craft {
3627                count: stoi(deser.take_word(true))?,
3628                craft_inv: InventoryLocation::deserialize(deser)?,
3629            })
3630        } else {
3631            bail!("Invalid InventoryAction kind");
3632        }
3633    }
3634}
3635
3636#[derive(Debug, Clone, PartialEq)]
3637pub enum InventoryLocation {
3638    Undefined,
3639    CurrentPlayer,
3640    Player { name: String },
3641    NodeMeta { pos: v3s16 },
3642    Detached { name: String },
3643}
3644
3645impl Serialize for InventoryLocation {
3646    type Input = Self;
3647    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
3648        match value {
3649            InventoryLocation::Undefined => ser.write_bytes(b"undefined")?,
3650            InventoryLocation::CurrentPlayer => ser.write_bytes(b"current_player")?,
3651            InventoryLocation::Player { name } => {
3652                ser.write_bytes(b"player:")?;
3653                ser.write_bytes(name.as_bytes())?;
3654            }
3655            InventoryLocation::NodeMeta { pos } => {
3656                ser.write_bytes(format!("nodemeta:{},{},{}", pos.x, pos.y, pos.z).as_bytes())?;
3657            }
3658            InventoryLocation::Detached { name } => {
3659                ser.write_bytes(b"detached:")?;
3660                ser.write_bytes(name.as_bytes())?;
3661            }
3662        }
3663        Ok(())
3664    }
3665}
3666
3667impl Deserialize for InventoryLocation {
3668    type Output = Self;
3669    fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
3670        let word = deser.take_word(true);
3671        if word == b"undefined" {
3672            return Ok(InventoryLocation::Undefined);
3673        } else if word == b"current_player" {
3674            return Ok(InventoryLocation::CurrentPlayer);
3675        } else if word.starts_with(b"player:") {
3676            return Ok(InventoryLocation::Player {
3677                name: std::str::from_utf8(&word[7..])?.to_string(),
3678            });
3679        } else if word.starts_with(b"nodemeta:") {
3680            let coords: Vec<&[u8]> = word[9..].split(|&ch| ch == b',').collect();
3681            if coords.len() != 3 {
3682                bail!("Corrupted nodemeta InventoryLocation");
3683            }
3684            let mut xyz = [0i16; 3];
3685            for (i, &n) in coords.iter().enumerate() {
3686                xyz[i] = stoi(n)?;
3687            }
3688            let pos = v3s16::new(xyz[0], xyz[1], xyz[2]);
3689            return Ok(InventoryLocation::NodeMeta { pos });
3690        } else if word.starts_with(b"detached:") {
3691            return Ok(InventoryLocation::Detached {
3692                name: std::str::from_utf8(&word[9..])?.to_string(),
3693            });
3694        } else {
3695            bail!("Unknown InventoryLocation: {:?}", word)
3696        }
3697    }
3698}