nurtex_protocol/types/
palette.rs1use nurtex_codec::Buffer;
2use nurtex_codec::types::variable::VarI32;
3
4#[derive(Clone, Debug, PartialEq)]
6pub enum PaletteFormat {
7 Single(u32),
8 Direct,
9 Indirect(Vec<u32>),
10}
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub enum PaletteKind {
15 Blocks,
16 Biomes,
17}
18
19#[derive(Clone, Debug, PartialEq)]
21pub struct Palette {
22 pub bits_per_entry: u8,
23 pub format: PaletteFormat,
24 pub data: Vec<u64>,
25 pub value_count: usize,
26}
27
28impl Palette {
29 pub fn get_by_index(&self, index: usize) -> Option<u32> {
31 if index >= self.value_count {
32 return None;
33 }
34
35 match &self.format {
36 PaletteFormat::Single(id) => Some(*id),
37 PaletteFormat::Direct => Some(self.storage_get(index)? as u32),
38 PaletteFormat::Indirect(palette) => {
39 let pal_index = self.storage_get(index)? as usize;
40 palette.get(pal_index).copied()
41 }
42 }
43 }
44
45 fn storage_get(&self, index: usize) -> Option<u64> {
46 let bits = self.bits_per_entry as usize;
47
48 if bits == 0 {
49 return Some(0);
50 }
51
52 if !(1..=32).contains(&bits) {
53 return None;
54 }
55
56 let values_per_word = 64 / bits;
57
58 if values_per_word == 0 {
59 return None;
60 }
61
62 let word_index = index / values_per_word;
63 let idx_in_word = index - word_index * values_per_word;
64 let shift = idx_in_word * bits;
65 let mask = (1u64 << bits) - 1;
66 let word = *self.data.get(word_index)?;
67
68 Some((word >> shift) & mask)
69 }
70}
71
72pub fn read_palette(buffer: &mut std::io::Cursor<&[u8]>, value_count: usize, kind: PaletteKind) -> Option<Palette> {
74 let bits_per_entry = u8::read_buf(buffer)?;
75
76 let format = match (kind, bits_per_entry) {
77 (_, 0) => PaletteFormat::Single(i32::read_var(buffer)? as u32),
78 (PaletteKind::Blocks, 1..=8) => {
79 let len = i32::read_var(buffer)? as usize;
80 let mut entries = Vec::with_capacity(len);
81 for _ in 0..len {
82 entries.push(i32::read_var(buffer)? as u32);
83 }
84 PaletteFormat::Indirect(entries)
85 }
86 (PaletteKind::Biomes, 1..=3) => {
87 let len = i32::read_var(buffer)? as usize;
88 let mut entries = Vec::with_capacity(len);
89 for _ in 0..len {
90 entries.push(i32::read_var(buffer)? as u32);
91 }
92 PaletteFormat::Indirect(entries)
93 }
94 _ => PaletteFormat::Direct,
95 };
96
97 let bits = bits_per_entry as usize;
98 let values_per_word = if bits == 0 { 0 } else { 64 / bits };
99 let word_count = if bits == 0 || values_per_word == 0 { 0 } else { value_count.div_ceil(values_per_word) };
100
101 let mut data = Vec::with_capacity(word_count);
102
103 for _ in 0..word_count {
104 data.push(u64::read_buf(buffer)?);
105 }
106
107 Some(Palette {
108 bits_per_entry,
109 format,
110 data,
111 value_count,
112 })
113}