azalea_world/palette/
mod.rs

1mod container;
2
3#[cfg(test)]
4mod tests;
5
6use std::{
7    fmt::Debug,
8    io::{self, Cursor, Write},
9};
10
11use azalea_buf::{AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
12pub use container::*;
13
14/// A representation of the different types of chunk palettes Minecraft uses.
15#[derive(Clone, Debug)]
16pub enum Palette<S: PalletedContainerKind> {
17    /// ID of the corresponding entry in its global palette
18    SingleValue(S),
19    // in vanilla this keeps a `size` field that might be less than the length, but i'm not sure
20    // it's actually needed?
21    Linear(Vec<S>),
22    Hashmap(Vec<S>),
23    Global,
24}
25
26impl<S: PalletedContainerKind> Palette<S> {
27    pub fn value_for(&self, id: usize) -> S {
28        match self {
29            Palette::SingleValue(v) => *v,
30            Palette::Linear(v) => v.get(id).copied().unwrap_or_default(),
31            Palette::Hashmap(v) => v.get(id).copied().unwrap_or_default(),
32            Palette::Global => S::try_from(id as u32).unwrap_or_default(),
33        }
34    }
35}
36
37impl<S: PalletedContainerKind> AzaleaWrite for Palette<S> {
38    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
39        match self {
40            Palette::SingleValue(value) => {
41                (*value).into().azalea_write_var(buf)?;
42            }
43            Palette::Linear(values) => {
44                (values.len() as u32).azalea_write_var(buf)?;
45                for value in values {
46                    (*value).into().azalea_write_var(buf)?;
47                }
48            }
49            Palette::Hashmap(values) => {
50                (values.len() as u32).azalea_write_var(buf)?;
51                for value in values {
52                    (*value).into().azalea_write_var(buf)?;
53                }
54            }
55            Palette::Global => {}
56        }
57        Ok(())
58    }
59}
60
61impl PaletteKind {
62    pub fn read<S: PalletedContainerKind>(
63        &self,
64        buf: &mut Cursor<&[u8]>,
65    ) -> Result<Palette<S>, BufReadError> {
66        Ok(match self {
67            // since they're read as varints it's actually fine to just use BlockStateIntegerRepr
68            // instead of the correct type (u32)
69            PaletteKind::SingleValue => {
70                Palette::SingleValue(S::try_from(u32::azalea_read_var(buf)?).unwrap_or_default())
71            }
72            PaletteKind::Linear => Palette::Linear(
73                Vec::<u32>::azalea_read_var(buf)?
74                    .into_iter()
75                    .map(|v| S::try_from(v).unwrap_or_default())
76                    .collect(),
77            ),
78            PaletteKind::Hashmap => Palette::Hashmap(
79                Vec::<u32>::azalea_read_var(buf)?
80                    .into_iter()
81                    .map(|v| S::try_from(v).unwrap_or_default())
82                    .collect(),
83            ),
84            PaletteKind::Global => Palette::Global,
85        })
86    }
87
88    pub fn as_empty_palette<S: PalletedContainerKind>(&self) -> Palette<S> {
89        match self {
90            PaletteKind::SingleValue => Palette::SingleValue(S::default()),
91            PaletteKind::Linear => Palette::Linear(Vec::new()),
92            PaletteKind::Hashmap => Palette::Hashmap(Vec::new()),
93            PaletteKind::Global => Palette::Global,
94        }
95    }
96}
97
98impl<S: PalletedContainerKind> From<&Palette<S>> for PaletteKind {
99    fn from(palette: &Palette<S>) -> Self {
100        match palette {
101            Palette::SingleValue(_) => PaletteKind::SingleValue,
102            Palette::Linear(_) => PaletteKind::Linear,
103            Palette::Hashmap(_) => PaletteKind::Hashmap,
104            Palette::Global => PaletteKind::Global,
105        }
106    }
107}
108
109#[derive(Clone, Debug, PartialEq, Eq)]
110pub enum PaletteKind {
111    SingleValue,
112    Linear,
113    Hashmap,
114    Global,
115}