Skip to main content

nurtex_protocol/types/
palette.rs

1use nurtex_codec::Buffer;
2use nurtex_codec::types::variable::VarI32;
3
4/// Формат палитры
5#[derive(Clone, Debug, PartialEq)]
6pub enum PaletteFormat {
7  Single(u32),
8  Direct,
9  Indirect(Vec<u32>),
10}
11
12/// Название палитры
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub enum PaletteKind {
15  Blocks,
16  Biomes,
17}
18
19/// Палитра
20#[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  /// Метод получения элемента по индексу
30  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
72/// Функция чтения палитры из буффера
73pub 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}