Skip to main content

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::{AzBufVar, BufReadError};
12pub use container::*;
13
14/// A representation of the different types of chunk palettes Minecraft uses.
15#[derive(Clone, Debug, PartialEq)]
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    #[inline]
28    pub fn value_for(&self, id: usize) -> S {
29        match self {
30            Palette::SingleValue(v) => *v,
31            Palette::Linear(v) => v.get(id).copied().unwrap_or_default(),
32            Palette::Hashmap(v) => v.get(id).copied().unwrap_or_default(),
33            Palette::Global => S::try_from(id as u32).unwrap_or_default(),
34        }
35    }
36}
37
38impl<S: PalletedContainerKind> Palette<S> {
39    pub fn write(&self, buf: &mut impl Write) -> io::Result<()> {
40        match self {
41            Palette::SingleValue(value) => {
42                (*value).into().azalea_write_var(buf)?;
43            }
44            Palette::Linear(values) => {
45                (values.len() as u32).azalea_write_var(buf)?;
46                for value in values {
47                    (*value).into().azalea_write_var(buf)?;
48                }
49            }
50            Palette::Hashmap(values) => {
51                (values.len() as u32).azalea_write_var(buf)?;
52                for value in values {
53                    (*value).into().azalea_write_var(buf)?;
54                }
55            }
56            Palette::Global => {}
57        }
58        Ok(())
59    }
60}
61
62impl PaletteKind {
63    pub fn read<S: PalletedContainerKind>(
64        &self,
65        buf: &mut Cursor<&[u8]>,
66    ) -> Result<Palette<S>, BufReadError> {
67        Ok(match self {
68            // since they're read as varints it's actually fine to just use BlockStateIntegerRepr
69            // instead of the correct type (u32)
70            PaletteKind::SingleValue => {
71                Palette::SingleValue(S::try_from(u32::azalea_read_var(buf)?).unwrap_or_default())
72            }
73            PaletteKind::Linear => Palette::Linear(
74                Vec::<u32>::azalea_read_var(buf)?
75                    .into_iter()
76                    .map(|v| S::try_from(v).unwrap_or_default())
77                    .collect(),
78            ),
79            PaletteKind::Hashmap => Palette::Hashmap(
80                Vec::<u32>::azalea_read_var(buf)?
81                    .into_iter()
82                    .map(|v| S::try_from(v).unwrap_or_default())
83                    .collect(),
84            ),
85            PaletteKind::Global => Palette::Global,
86        })
87    }
88
89    pub fn as_empty_palette<S: PalletedContainerKind>(&self) -> Palette<S> {
90        match self {
91            PaletteKind::SingleValue => Palette::SingleValue(S::default()),
92            PaletteKind::Linear => Palette::Linear(Vec::new()),
93            PaletteKind::Hashmap => Palette::Hashmap(Vec::new()),
94            PaletteKind::Global => Palette::Global,
95        }
96    }
97}
98
99impl<S: PalletedContainerKind> From<&Palette<S>> for PaletteKind {
100    fn from(palette: &Palette<S>) -> Self {
101        match palette {
102            Palette::SingleValue(_) => PaletteKind::SingleValue,
103            Palette::Linear(_) => PaletteKind::Linear,
104            Palette::Hashmap(_) => PaletteKind::Hashmap,
105            Palette::Global => PaletteKind::Global,
106        }
107    }
108}
109
110#[derive(Clone, Debug, Eq, PartialEq)]
111pub enum PaletteKind {
112    SingleValue,
113    Linear,
114    Hashmap,
115    Global,
116}