nurtex_protocol/types/
chunk.rs1use std::hash::{Hash, Hasher};
2
3use nurtex_codec::Buffer;
4
5use crate::types::BlockPos;
6
7use super::{ChunkData, Palette, PaletteKind, read_palette};
8
9#[derive(Clone, Debug, PartialEq)]
11pub struct Chunk {
12 pub position: ChunkPos,
14
15 pub min_y: i32,
17
18 pub sections: Vec<ChunkSection>,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct ChunkPos {
25 pub x: i32,
26 pub z: i32,
27}
28
29impl ChunkPos {
30 pub fn new(x: i32, z: i32) -> Self {
32 Self { x, z }
33 }
34}
35
36impl Hash for ChunkPos {
37 fn hash<H: Hasher>(&self, state: &mut H) {
38 self.x.hash(state);
39 self.z.hash(state);
40 }
41}
42
43impl ChunkPos {
44 pub fn from_block(pos: BlockPos) -> Self {
45 Self {
46 x: pos.x.div_euclid(16),
47 z: pos.z.div_euclid(16),
48 }
49 }
50}
51
52#[derive(Clone, Debug, PartialEq)]
54pub struct ChunkSection {
55 pub non_air_block_count: u16,
57
58 pub blocks: Palette,
60
61 pub biomes: Palette,
63}
64
65impl Chunk {
66 pub fn decode(chunk_x: i32, chunk_z: i32, chunk_data: &ChunkData, section_count: usize, min_y: i32) -> Option<Self> {
68 let mut cur = std::io::Cursor::new(&chunk_data.sections[..]);
69 let mut sections = Vec::with_capacity(section_count);
70
71 for _ in 0..section_count {
72 let non_air_block_count = u16::read_buf(&mut cur)?;
73 let blocks = read_palette(&mut cur, 16 * 16 * 16, PaletteKind::Blocks)?;
74 let biomes = read_palette(&mut cur, 4 * 4 * 4, PaletteKind::Biomes)?;
75
76 sections.push(ChunkSection {
77 non_air_block_count,
78 blocks,
79 biomes,
80 });
81 }
82
83 Some(Self {
84 position: ChunkPos::new(chunk_x, chunk_z),
85 min_y: min_y,
86 sections: sections,
87 })
88 }
89
90 pub fn decode_to_end(chunk_x: i32, chunk_z: i32, chunk_data: &ChunkData, min_y: i32) -> Option<Self> {
92 let mut cur = std::io::Cursor::new(&chunk_data.sections[..]);
93 let mut sections = Vec::new();
94
95 while (cur.position() as usize) < cur.get_ref().len() {
96 let before = cur.position();
97
98 let non_air_block_count = u16::read_buf(&mut cur)?;
99 let blocks = read_palette(&mut cur, 16 * 16 * 16, PaletteKind::Blocks)?;
100 let biomes = read_palette(&mut cur, 4 * 4 * 4, PaletteKind::Biomes)?;
101
102 sections.push(ChunkSection {
103 non_air_block_count,
104 blocks,
105 biomes,
106 });
107
108 if cur.position() == before {
109 return None;
110 }
111 }
112
113 Some(Self {
114 position: ChunkPos::new(chunk_x, chunk_z),
115 min_y: min_y,
116 sections: sections,
117 })
118 }
119
120 pub fn get_block(&self, pos: BlockPos) -> Option<u32> {
122 if pos.y < self.min_y {
123 return None;
124 }
125
126 let rel_y = (pos.y - self.min_y) as usize;
127 let section_index = rel_y / 16;
128 let local_y = rel_y % 16;
129 let local_x = pos.x.rem_euclid(16) as usize;
130 let local_z = pos.z.rem_euclid(16) as usize;
131
132 let section = self.sections.get(section_index)?;
133
134 section.blocks.get_by_index((local_y * 16 * 16) + (local_z * 16) + local_x)
135 }
136
137 pub fn get_block_relative(&self, x: usize, y: usize, z: usize) -> Option<u32> {
139 if x >= 16 || z >= 16 {
140 return None;
141 }
142
143 let section_index = y / 16;
144 let local_y = y % 16;
145 let section = self.sections.get(section_index)?;
146 let index = (local_y * 16 * 16) + (z * 16) + x;
147
148 section.blocks.get_by_index(index)
149 }
150}