azalea_core/
checksum.rs

1use std::{cmp::Ordering, fmt, hash::Hasher};
2
3use azalea_buf::AzBuf;
4use crc32c::Crc32cHasher;
5use serde::{Serialize, ser};
6use thiserror::Error;
7use tracing::error;
8
9use crate::{registry_holder::RegistryHolder, resource_location::ResourceLocation};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, AzBuf)]
12pub struct Checksum(pub u32);
13
14pub struct ChecksumSerializer<'a, 'r> {
15    hasher: &'a mut Crc32cHasher,
16    registries: &'r RegistryHolder,
17}
18impl<'a, 'r> ChecksumSerializer<'a, 'r> {
19    pub fn checksum(&mut self) -> Checksum {
20        Checksum(self.hasher.finish() as u32)
21    }
22}
23
24impl<'a, 'r> ser::Serializer for ChecksumSerializer<'a, 'r> {
25    type Ok = ();
26
27    // The error type when some error occurs during serialization.
28    type Error = ChecksumError;
29
30    type SerializeSeq = ChecksumListSerializer<'a, 'r>;
31    type SerializeTuple = ChecksumListSerializer<'a, 'r>;
32    type SerializeTupleStruct = ChecksumListSerializer<'a, 'r>;
33    type SerializeTupleVariant = ChecksumMapSerializer<'a, 'r>;
34    type SerializeMap = ChecksumMapSerializer<'a, 'r>;
35    type SerializeStruct = ChecksumMapSerializer<'a, 'r>;
36    type SerializeStructVariant = ChecksumMapSerializer<'a, 'r>;
37
38    fn serialize_bool(self, v: bool) -> Result<()> {
39        assert!(self.hasher.finish() == 0);
40        self.hasher.write_u8(13);
41        self.hasher.write(&[v as u8]);
42        Ok(())
43    }
44
45    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
46        assert!(self.hasher.finish() == 0);
47        Ok(ChecksumMapSerializer {
48            hasher: self.hasher,
49            registries: self.registries,
50            entries: Vec::new(),
51        })
52    }
53    fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
54        assert!(self.hasher.finish() == 0);
55        self.serialize_map(Some(len))
56    }
57
58    fn serialize_i8(self, v: i8) -> Result<()> {
59        assert!(self.hasher.finish() == 0);
60        self.hasher.write_u8(6);
61        self.hasher.write(&v.to_le_bytes());
62        Ok(())
63    }
64
65    fn serialize_i16(self, v: i16) -> Result<()> {
66        assert!(self.hasher.finish() == 0);
67        self.hasher.write_u8(7);
68        self.hasher.write(&v.to_le_bytes());
69        Ok(())
70    }
71
72    fn serialize_i32(self, v: i32) -> Result<()> {
73        assert!(self.hasher.finish() == 0);
74        self.hasher.write_u8(8);
75        self.hasher.write(&v.to_le_bytes());
76        Ok(())
77    }
78
79    fn serialize_i64(self, v: i64) -> Result<()> {
80        assert!(self.hasher.finish() == 0);
81        self.hasher.write_u8(9);
82        self.hasher.write(&v.to_le_bytes());
83        Ok(())
84    }
85
86    fn serialize_u8(self, v: u8) -> Result<()> {
87        assert!(self.hasher.finish() == 0);
88        self.serialize_i8(v as i8)
89    }
90
91    fn serialize_u16(self, v: u16) -> Result<()> {
92        assert!(self.hasher.finish() == 0);
93        self.serialize_i16(v as i16)
94    }
95
96    fn serialize_u32(self, v: u32) -> Result<()> {
97        assert!(self.hasher.finish() == 0);
98        self.serialize_i32(v as i32)
99    }
100
101    fn serialize_u64(self, v: u64) -> Result<()> {
102        assert!(self.hasher.finish() == 0);
103        self.serialize_i64(v as i64)
104    }
105
106    fn serialize_f32(self, v: f32) -> Result<()> {
107        assert!(self.hasher.finish() == 0);
108        self.hasher.write_u8(10);
109        self.hasher.write(&v.to_le_bytes());
110        Ok(())
111    }
112
113    fn serialize_f64(self, v: f64) -> Result<()> {
114        assert!(self.hasher.finish() == 0);
115        self.hasher.write_u8(11);
116        self.hasher.write(&v.to_le_bytes());
117        Ok(())
118    }
119
120    fn serialize_char(self, v: char) -> Result<()> {
121        assert!(self.hasher.finish() == 0);
122        self.serialize_u32(v as u32)
123    }
124
125    fn serialize_str(self, v: &str) -> Result<()> {
126        assert!(self.hasher.finish() == 0);
127        self.hasher.write_u8(12);
128        let utf16 = v.encode_utf16().collect::<Vec<_>>();
129        self.hasher.write(&(utf16.len() as u32).to_le_bytes());
130        for c in utf16 {
131            self.hasher.write(&c.to_le_bytes());
132        }
133        Ok(())
134    }
135
136    fn serialize_bytes(self, v: &[u8]) -> Result<()> {
137        assert!(self.hasher.finish() == 0);
138        self.hasher.write_u8(14);
139        self.hasher.write(v);
140        self.hasher.write_u8(15);
141        Ok(())
142    }
143
144    fn serialize_none(self) -> Result<()> {
145        assert!(self.hasher.finish() == 0);
146        self.hasher.write_u8(1);
147        Ok(())
148    }
149
150    fn serialize_some<T>(self, value: &T) -> Result<()>
151    where
152        T: ?Sized + Serialize,
153    {
154        // check if t
155
156        value.serialize(self)?;
157        Ok(())
158    }
159
160    fn serialize_unit(self) -> Result<()> {
161        assert!(self.hasher.finish() == 0);
162        Ok(())
163    }
164
165    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
166        assert!(self.hasher.finish() == 0);
167        update_hasher_for_map(self.hasher, &[]);
168        Ok(())
169    }
170
171    fn serialize_unit_variant(
172        self,
173        _name: &'static str,
174        _variant_index: u32,
175        variant: &'static str,
176    ) -> Result<()> {
177        self.serialize_str(variant)
178    }
179
180    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<()>
181    where
182        T: ?Sized + Serialize,
183    {
184        value.serialize(self)
185    }
186
187    fn serialize_newtype_variant<T>(
188        self,
189        name: &'static str,
190        variant_index: u32,
191        _variant: &'static str,
192        value: &T,
193    ) -> Result<()>
194    where
195        T: ?Sized + Serialize,
196    {
197        // we can't have custom handlers with serde's traits, so we use this silly hack
198        // to make serializing data-driven registries work
199        if name.starts_with("minecraft:") {
200            let value = self
201                .registries
202                .map
203                .get(&ResourceLocation::from(name))
204                .and_then(|r| r.get_index(variant_index as usize))
205                .map(|r| r.0.to_string())
206                .unwrap_or_default();
207            self.serialize_str(&value)?;
208            return Ok(());
209        }
210
211        value.serialize(ChecksumSerializer {
212            hasher: self.hasher,
213            registries: self.registries,
214        })
215    }
216
217    fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
218        assert!(self.hasher.finish() == 0);
219        Ok(ChecksumListSerializer {
220            hasher: self.hasher,
221            registries: self.registries,
222            values: Vec::with_capacity(len.unwrap_or_default()),
223            list_kind: ListKind::Normal,
224        })
225    }
226
227    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
228        assert!(self.hasher.finish() == 0);
229        Ok(ChecksumListSerializer {
230            hasher: self.hasher,
231            registries: self.registries,
232            values: Vec::with_capacity(len),
233            list_kind: ListKind::Normal,
234        })
235    }
236
237    fn serialize_tuple_struct(
238        self,
239        name: &'static str,
240        len: usize,
241    ) -> Result<Self::SerializeTupleStruct> {
242        assert!(self.hasher.finish() == 0);
243        let list_kind = if name == "azalea:int_array" {
244            self.hasher.write_u8(16);
245            ListKind::Int
246        } else if name == "azalea:long_array" {
247            self.hasher.write_u8(18);
248            ListKind::Long
249        } else {
250            ListKind::Normal
251        };
252        Ok(ChecksumListSerializer {
253            hasher: self.hasher,
254            registries: self.registries,
255            values: Vec::with_capacity(len),
256            list_kind,
257        })
258    }
259
260    fn serialize_tuple_variant(
261        self,
262        _name: &'static str,
263        _variant_index: u32,
264        _variant: &'static str,
265        len: usize,
266    ) -> Result<Self::SerializeTupleVariant> {
267        assert!(self.hasher.finish() == 0);
268        Ok(ChecksumMapSerializer {
269            hasher: self.hasher,
270            registries: self.registries,
271            entries: Vec::with_capacity(len),
272        })
273    }
274
275    fn serialize_struct_variant(
276        self,
277        _name: &'static str,
278        _variant_index: u32,
279        _variant: &'static str,
280        len: usize,
281    ) -> Result<Self::SerializeStructVariant> {
282        Ok(ChecksumMapSerializer {
283            hasher: self.hasher,
284            registries: self.registries,
285            entries: Vec::with_capacity(len),
286        })
287    }
288}
289
290pub struct ChecksumListSerializer<'a, 'r> {
291    hasher: &'a mut Crc32cHasher,
292    registries: &'r RegistryHolder,
293    values: Vec<Checksum>,
294    /// If you set this to not be the default, you should also update the hasher
295    /// before creating the list serializer.
296    list_kind: ListKind,
297}
298impl<'a, 'r> ser::SerializeSeq for ChecksumListSerializer<'a, 'r> {
299    type Ok = ();
300    type Error = ChecksumError;
301
302    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
303    where
304        T: ?Sized + Serialize,
305    {
306        if self.list_kind == ListKind::Normal {
307            // elements are hashed individually
308            self.values.push(get_checksum(value, self.registries)?);
309        } else {
310            value.serialize(IntOrLongArrayChecksumSerializer {
311                hasher: self.hasher,
312            })?;
313        }
314
315        Ok(())
316    }
317
318    fn end(self) -> Result<()> {
319        match self.list_kind {
320            ListKind::Normal => {
321                assert!(self.hasher.finish() == 0);
322                update_hasher_for_list(self.hasher, &self.values);
323            }
324            ListKind::Int => {
325                self.hasher.write_u8(17);
326            }
327            ListKind::Long => {
328                self.hasher.write_u8(19);
329            }
330        }
331
332        Ok(())
333    }
334}
335/// Minecraft sometimes serializes u8/i32/i64 lists differently, so we have to
336/// keep track of that when serializing the arrays.
337///
338/// Byte arrays aren't included here as they're handled with `serialize_bytes`.
339#[derive(Default, PartialEq, Eq)]
340enum ListKind {
341    #[default]
342    Normal,
343    Int,
344    Long,
345}
346
347impl<'a, 'r> ser::SerializeTuple for ChecksumListSerializer<'a, 'r> {
348    type Ok = ();
349    type Error = ChecksumError;
350
351    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
352    where
353        T: ?Sized + Serialize,
354    {
355        ser::SerializeSeq::serialize_element(self, value)
356    }
357
358    fn end(self) -> Result<()> {
359        ser::SerializeSeq::end(self)
360    }
361}
362impl<'a, 'r> ser::SerializeTupleStruct for ChecksumListSerializer<'a, 'r> {
363    type Ok = ();
364    type Error = ChecksumError;
365
366    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
367    where
368        T: ?Sized + Serialize,
369    {
370        ser::SerializeSeq::serialize_element(self, value)
371    }
372
373    fn end(self) -> Result<()> {
374        ser::SerializeSeq::end(self)
375    }
376}
377
378pub struct ChecksumMapSerializer<'a, 'r> {
379    // this is only written to at the end
380    hasher: &'a mut Crc32cHasher,
381    registries: &'r RegistryHolder,
382    // we have to keep track of the elements like this because they're sorted at the end
383    entries: Vec<(Checksum, Checksum)>,
384}
385impl<'a, 'r> ser::SerializeMap for ChecksumMapSerializer<'a, 'r> {
386    type Ok = ();
387    type Error = ChecksumError;
388
389    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
390    where
391        T: ?Sized + Serialize,
392    {
393        // this 0 is a placeholder
394        self.entries
395            .push((get_checksum(key, self.registries)?, Checksum(0)));
396        Ok(())
397    }
398
399    // It doesn't make a difference whether the colon is printed at the end of
400    // `serialize_key` or at the beginning of `serialize_value`. In this case
401    // the code is a bit simpler having it here.
402    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
403    where
404        T: ?Sized + Serialize,
405    {
406        // placeholder gets replaced here
407        self.entries
408            .last_mut()
409            .expect("entry should've already been added")
410            .1 = get_checksum(value, self.registries)?;
411        Ok(())
412    }
413
414    fn end(self) -> Result<()> {
415        assert!(self.hasher.finish() == 0);
416        update_hasher_for_map(self.hasher, &self.entries);
417        Ok(())
418    }
419}
420impl<'a, 'r> ser::SerializeTupleVariant for ChecksumMapSerializer<'a, 'r> {
421    type Ok = ();
422    type Error = ChecksumError;
423
424    fn serialize_field<T>(&mut self, _value: &T) -> Result<()>
425    where
426        T: ?Sized + Serialize,
427    {
428        // TODO
429        error!("tuple variants are not supported when serializing checksums");
430        Ok(())
431    }
432
433    fn end(self) -> Result<()> {
434        assert!(self.hasher.finish() == 0);
435        Ok(())
436    }
437}
438impl<'a, 'r> ser::SerializeStruct for ChecksumMapSerializer<'a, 'r> {
439    type Ok = ();
440    type Error = ChecksumError;
441
442    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
443    where
444        T: ?Sized + Serialize,
445    {
446        self.entries.push((
447            get_checksum(key, self.registries)?,
448            get_checksum(value, self.registries)?,
449        ));
450        Ok(())
451    }
452
453    fn end(self) -> Result<()> {
454        assert!(self.hasher.finish() == 0);
455        update_hasher_for_map(self.hasher, &self.entries);
456        Ok(())
457    }
458}
459impl<'a, 'r> ser::SerializeStructVariant for ChecksumMapSerializer<'a, 'r> {
460    type Ok = ();
461    type Error = ChecksumError;
462
463    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
464    where
465        T: ?Sized + Serialize,
466    {
467        self.entries.push((
468            get_checksum(key, self.registries)?,
469            get_checksum(value, self.registries)?,
470        ));
471        Ok(())
472    }
473
474    fn end(self) -> Result<()> {
475        assert!(self.hasher.finish() == 0);
476        update_hasher_for_map(self.hasher, &self.entries);
477        Ok(())
478    }
479}
480
481/// A hasher that can only serialize i32 and i64.
482struct IntOrLongArrayChecksumSerializer<'a> {
483    hasher: &'a mut Crc32cHasher,
484}
485impl<'a> ser::Serializer for IntOrLongArrayChecksumSerializer<'a> {
486    type Ok = ();
487    type Error = ChecksumError;
488    // unused
489    type SerializeSeq = ChecksumListSerializer<'a, 'a>;
490    type SerializeTuple = ChecksumListSerializer<'a, 'a>;
491    type SerializeTupleStruct = ChecksumListSerializer<'a, 'a>;
492    type SerializeTupleVariant = ChecksumMapSerializer<'a, 'a>;
493    type SerializeMap = ChecksumMapSerializer<'a, 'a>;
494    type SerializeStruct = ChecksumMapSerializer<'a, 'a>;
495    type SerializeStructVariant = ChecksumMapSerializer<'a, 'a>;
496
497    fn serialize_bool(self, _v: bool) -> Result<()> {
498        unimplemented!()
499    }
500    fn serialize_i8(self, _v: i8) -> Result<()> {
501        unimplemented!()
502    }
503    fn serialize_i16(self, _v: i16) -> Result<()> {
504        unimplemented!()
505    }
506    fn serialize_i32(self, v: i32) -> Result<()> {
507        self.hasher.write(&v.to_le_bytes());
508        Ok(())
509    }
510    fn serialize_i64(self, v: i64) -> Result<()> {
511        self.hasher.write(&v.to_le_bytes());
512        Ok(())
513    }
514    fn serialize_u8(self, _v: u8) -> Result<()> {
515        unimplemented!()
516    }
517    fn serialize_u16(self, _v: u16) -> Result<()> {
518        unimplemented!()
519    }
520    fn serialize_u32(self, v: u32) -> Result<()> {
521        self.serialize_i32(v as i32)
522    }
523    fn serialize_u64(self, v: u64) -> Result<()> {
524        self.serialize_i64(v as i64)
525    }
526    fn serialize_f32(self, _v: f32) -> Result<()> {
527        unimplemented!()
528    }
529    fn serialize_f64(self, _v: f64) -> Result<()> {
530        unimplemented!()
531    }
532    fn serialize_char(self, _v: char) -> Result<()> {
533        unimplemented!()
534    }
535    fn serialize_str(self, _v: &str) -> Result<()> {
536        unimplemented!()
537    }
538    fn serialize_bytes(self, _v: &[u8]) -> Result<()> {
539        unimplemented!()
540    }
541    fn serialize_none(self) -> Result<()> {
542        unimplemented!()
543    }
544    fn serialize_some<T>(self, _v: &T) -> Result<()>
545    where
546        T: ?Sized + Serialize,
547    {
548        unimplemented!()
549    }
550    fn serialize_unit(self) -> Result<()> {
551        unimplemented!()
552    }
553    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
554        unimplemented!()
555    }
556    fn serialize_unit_variant(
557        self,
558        _name: &'static str,
559        _variant_index: u32,
560        _variant: &'static str,
561    ) -> Result<()> {
562        unimplemented!()
563    }
564    fn serialize_newtype_struct<T>(self, _name: &'static str, _value: &T) -> Result<()>
565    where
566        T: ?Sized + Serialize,
567    {
568        unimplemented!()
569    }
570    fn serialize_newtype_variant<T>(
571        self,
572        _name: &'static str,
573        _variant_index: u32,
574        _variant: &'static str,
575        _value: &T,
576    ) -> Result<()>
577    where
578        T: ?Sized + Serialize,
579    {
580        unimplemented!()
581    }
582    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
583        unimplemented!()
584    }
585    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
586        unimplemented!()
587    }
588    fn serialize_tuple_struct(
589        self,
590        _name: &'static str,
591        _len: usize,
592    ) -> Result<Self::SerializeTupleStruct> {
593        unimplemented!()
594    }
595    fn serialize_tuple_variant(
596        self,
597        _name: &'static str,
598        _variant_index: u32,
599        _variant: &'static str,
600        _len: usize,
601    ) -> Result<Self::SerializeTupleVariant> {
602        unimplemented!()
603    }
604    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
605        unimplemented!()
606    }
607    fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
608        unimplemented!()
609    }
610    fn serialize_struct_variant(
611        self,
612        _name: &'static str,
613        _variant_index: u32,
614        _variant: &'static str,
615        _len: usize,
616    ) -> Result<Self::SerializeStructVariant> {
617        unimplemented!()
618    }
619}
620
621#[derive(Error, Debug)]
622#[error("Checksum serialization error")]
623pub struct ChecksumError;
624impl ser::Error for ChecksumError {
625    fn custom<T>(msg: T) -> Self
626    where
627        T: fmt::Display,
628    {
629        eprintln!("Serialization error: {msg}");
630        ChecksumError
631    }
632}
633type Result<T> = std::result::Result<T, ChecksumError>;
634
635pub fn get_checksum<T: Serialize + ?Sized>(
636    value: &T,
637    registries: &RegistryHolder,
638) -> Result<Checksum> {
639    let mut hasher = Crc32cHasher::default();
640    value.serialize(ChecksumSerializer {
641        hasher: &mut hasher,
642        registries,
643    })?;
644    Ok(Checksum(hasher.finish() as u32))
645}
646
647fn update_hasher_for_list(h: &mut Crc32cHasher, values: &[Checksum]) {
648    h.write_u8(4);
649    for v in values {
650        h.write(&v.0.to_le_bytes());
651    }
652    h.write_u8(5);
653}
654fn update_hasher_for_map(h: &mut Crc32cHasher, entries: &[(Checksum, Checksum)]) {
655    h.write_u8(2);
656    let mut entries = entries.to_vec();
657    entries.sort_by(|a, b| match a.0.cmp(&b.0) {
658        Ordering::Equal => a.1.cmp(&b.1),
659        other => other,
660    });
661    for (k, v) in entries {
662        h.write(&k.0.to_le_bytes());
663        h.write(&v.0.to_le_bytes());
664    }
665    h.write_u8(3);
666}