diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2025-08-10 18:55:23 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-10 18:55:23 -0500 |
| commit | 7120842f9d2c659a2f12d8922299c2a761bc5582 (patch) | |
| tree | 0d7976ceec82d914e4c75f23adcdd5839f9960a4 /azalea-core/src/codec_utils.rs | |
| parent | 3b659833c1ad4cca89b4cd553193edcb6d223163 (diff) | |
| download | azalea-drasl-7120842f9d2c659a2f12d8922299c2a761bc5582.tar.xz | |
Send correct data component checksums (#234)
* start implementing data component crc32 hashes
* start doing serde impls for checksums
* make more components hashable
* make all data components serializable
* support recursive components
* fix simdnbt dep
* update changelog
* clippy
Diffstat (limited to 'azalea-core/src/codec_utils.rs')
| -rw-r--r-- | azalea-core/src/codec_utils.rs | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/azalea-core/src/codec_utils.rs b/azalea-core/src/codec_utils.rs new file mode 100644 index 00000000..0014f86d --- /dev/null +++ b/azalea-core/src/codec_utils.rs @@ -0,0 +1,83 @@ +//! Some functions that are useful to have when implementing +//! `Serialize`/`Deserialize`, which Azalea uses to imitate Minecraft codecs. + +use azalea_buf::SerializableUuid; +use serde::{Serialize, Serializer, ser::SerializeTupleStruct}; +use uuid::Uuid; + +/// Intended to be used for skipping serialization if the value is the default. +/// +/// ```no_run +/// #[serde(skip_serializing_if = "is_default")] +/// ``` +pub fn is_default<T: Default + PartialEq>(t: &T) -> bool { + *t == Default::default() +} + +/// Intended to be used for skipping serialization if the value is `true`. +/// +/// ```no_run +/// #[serde(skip_serializing_if = "is_true")] +/// ``` +pub fn is_true(t: &bool) -> bool { + *t +} + +/// If the array has a single item, don't serialize as an array +/// +/// ```no_run +/// #[serde(serialize_with = "flatten_array")] +/// ``` +pub fn flatten_array<S: Serializer, T: Serialize>(x: &Vec<T>, s: S) -> Result<S::Ok, S::Error> { + if x.len() == 1 { + x[0].serialize(s) + } else { + x.serialize(s) + } +} + +/// Minecraft writes UUIDs as an IntArray<4> +pub fn uuid<'a, S: Serializer>( + uuid: impl Into<&'a Option<Uuid>>, + serializer: S, +) -> Result<S::Ok, S::Error> { + if let Some(uuid) = uuid.into() { + let arr: [u32; 4] = uuid.to_int_array(); + let arr: [i32; 4] = [arr[0] as i32, arr[1] as i32, arr[2] as i32, arr[3] as i32]; + IntArray(arr).serialize(serializer) + } else { + serializer.serialize_unit() + } +} + +/// An internal type that makes the i32 array be serialized differently. +/// +/// Azalea currently only uses this when writing checksums, but Minecraft also +/// uses this internally when converting types to NBT. +pub struct IntArray<const N: usize>(pub [i32; N]); +/// An internal type that makes the i64 array be serialized differently. +/// +/// Azalea currently only uses this when writing checksums, but Minecraft also +/// uses this internally when converting types to NBT. +pub struct LongArray<const N: usize>(pub [i64; N]); + +impl<const N: usize> Serialize for IntArray<N> { + fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { + // see checksum::serialize_tuple_struct + let mut seq = serializer.serialize_tuple_struct("azalea:int_array", N)?; + for &item in &self.0 { + seq.serialize_field(&item)?; + } + seq.end() + } +} +impl<const N: usize> Serialize for LongArray<N> { + fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { + // see checksum::serialize_tuple_struct + let mut seq = serializer.serialize_tuple_struct("azalea:long_array", N)?; + for &item in &self.0 { + seq.serialize_field(&item)?; + } + seq.end() + } +} |
