1use crate::{
2 vol::{
3 BaseVol, IntoPosIterator, IntoVolIterator, ReadVol, RectRasterableVol, RectVolSize,
4 VolSize, WriteVol,
5 },
6 volumes::chunk::{Chunk, ChunkError, ChunkPosIter, ChunkVolIter},
7};
8use core::{hash::Hash, marker::PhantomData};
9use serde::{Deserialize, Serialize};
10use vek::*;
11
12#[derive(Debug)]
13pub enum ChonkError {
14 SubChunkError(ChunkError),
15 OutOfBounds,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct SubChunkSize<ChonkSize: RectVolSize> {
20 phantom: PhantomData<ChonkSize>,
21}
22
23impl<ChonkSize: RectVolSize> VolSize for SubChunkSize<ChonkSize> {
26 const SIZE: Vec3<u32> = Vec3 {
27 x: ChonkSize::RECT_SIZE.x,
28 y: ChonkSize::RECT_SIZE.x,
29 z: ChonkSize::RECT_SIZE.x / 2,
31 };
32}
33
34type SubChunk<V, S, M> = Chunk<V, SubChunkSize<S>, M>;
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct Chonk<V, S: RectVolSize, M: Clone> {
38 z_offset: i32,
39 sub_chunks: Vec<SubChunk<V, S, M>>,
40 below: V,
41 above: V,
42 meta: M,
43 phantom: PhantomData<S>,
44}
45
46impl<V, S: RectVolSize, M: Clone> Chonk<V, S, M> {
47 pub fn new(z_offset: i32, below: V, above: V, meta: M) -> Self {
48 Self {
49 z_offset,
50 sub_chunks: Vec::new(),
51 below,
52 above,
53 meta,
54 phantom: PhantomData,
55 }
56 }
57
58 pub fn meta(&self) -> &M { &self.meta }
59
60 pub fn meta_mut(&mut self) -> &mut M { &mut self.meta }
61
62 #[inline]
63 pub fn get_min_z(&self) -> i32 { self.z_offset }
64
65 #[inline]
66 pub fn get_max_z(&self) -> i32 {
67 self.z_offset + (self.sub_chunks.len() as u32 * SubChunkSize::<S>::SIZE.z) as i32
68 }
69
70 pub fn sub_chunks_len(&self) -> usize { self.sub_chunks.len() }
71
72 pub fn sub_chunk_groups(&self) -> usize {
73 self.sub_chunks.iter().map(SubChunk::num_groups).sum()
74 }
75
76 pub fn iter_changed(&self) -> impl Iterator<Item = (Vec3<i32>, &V)> + '_ {
80 self.sub_chunks
81 .iter()
82 .enumerate()
83 .filter(|(_, sc)| sc.num_groups() > 0)
84 .flat_map(move |(i, sc)| {
85 let z_offset = self.z_offset + i as i32 * SubChunkSize::<S>::SIZE.z as i32;
86 sc.vol_iter(Vec3::zero(), SubChunkSize::<S>::SIZE.map(|e| e as i32))
87 .map(move |(pos, vox)| (pos + Vec3::unit_z() * z_offset, vox))
88 })
89 }
90
91 #[inline]
94 fn sub_chunk_idx(&self, z: i32) -> i32 {
95 let diff = z - self.z_offset;
96 diff >> (SubChunkSize::<S>::SIZE.z - 1).count_ones()
97 }
98
99 fn sub_chunk_z(&self, z: i32) -> i32 {
101 let diff = z - self.z_offset;
102 diff & (SubChunkSize::<S>::SIZE.z - 1) as i32
103 }
104
105 fn sub_chunk_min_z(&self, z: i32) -> i32 { z - self.sub_chunk_z(z) }
107
108 pub fn defragment(&mut self)
110 where
111 V: Clone + Eq + Hash,
112 {
113 self.sub_chunks.iter_mut().for_each(SubChunk::defragment);
115 let above_count = self
123 .sub_chunks
124 .iter()
125 .rev()
126 .take_while(|subchunk| subchunk.homogeneous() == Some(&self.above))
127 .count();
128 let mut subchunks = self.sub_chunks.iter();
133 if above_count > 0 {
134 subchunks.nth_back(above_count - 1);
135 }
136 let above_index = subchunks.len();
139 let below_len = subchunks.position(|subchunk| subchunk.homogeneous() != Some(&self.below));
143 let below_len = below_len
144 .unwrap_or(above_index);
147 self.sub_chunks.truncate(above_index);
149 self.sub_chunks.drain(..below_len);
150 self.z_offset += below_len as i32 * SubChunkSize::<S>::SIZE.z as i32;
154 }
155}
156
157impl<V, S: RectVolSize, M: Clone> BaseVol for Chonk<V, S, M> {
158 type Error = ChonkError;
159 type Vox = V;
160}
161
162impl<V, S: RectVolSize, M: Clone> RectRasterableVol for Chonk<V, S, M> {
163 const RECT_SIZE: Vec2<u32> = S::RECT_SIZE;
164}
165
166impl<V, S: RectVolSize, M: Clone> ReadVol for Chonk<V, S, M> {
167 #[inline(always)]
168 fn get(&self, pos: Vec3<i32>) -> Result<&V, Self::Error> {
169 if pos.z < self.get_min_z() {
170 Ok(&self.below)
172 } else if pos.z >= self.get_max_z() {
173 Ok(&self.above)
175 } else {
176 let sub_chunk_idx = self.sub_chunk_idx(pos.z);
178 let rpos = pos
179 - Vec3::unit_z()
180 * (self.z_offset + sub_chunk_idx * SubChunkSize::<S>::SIZE.z as i32);
181 self.sub_chunks[sub_chunk_idx as usize]
182 .get(rpos)
183 .map_err(Self::Error::SubChunkError)
184 }
185 }
186
187 #[inline(always)]
188 fn get_unchecked(&self, pos: Vec3<i32>) -> &V {
189 if pos.z < self.get_min_z() {
190 &self.below
192 } else if pos.z >= self.get_max_z() {
193 &self.above
195 } else {
196 let sub_chunk_idx = self.sub_chunk_idx(pos.z);
198 let rpos = pos
199 - Vec3::unit_z()
200 * (self.z_offset + sub_chunk_idx * SubChunkSize::<S>::SIZE.z as i32);
201 self.sub_chunks[sub_chunk_idx as usize].get_unchecked(rpos)
202 }
203 }
204
205 fn for_each_in(&self, aabb: Aabb<i32>, mut f: impl FnMut(Vec3<i32>, Self::Vox))
206 where
207 Self::Vox: Copy,
208 {
209 let idx = self.sub_chunk_idx(aabb.min.z);
210 if idx == self.sub_chunk_idx(aabb.max.z) && idx >= 0 && idx < self.sub_chunks.len() as i32 {
213 let sub_chunk = &self.sub_chunks[idx as usize];
214 let z_off = self.z_offset + idx * SubChunkSize::<S>::SIZE.z as i32;
215 sub_chunk.for_each_in(
216 Aabb {
217 min: aabb.min.with_z(aabb.min.z - z_off),
218 max: aabb.max.with_z(aabb.max.z - z_off),
219 },
220 |pos, vox| f(pos.with_z(pos.z + z_off), vox),
221 );
222 } else {
223 for z in aabb.min.z..aabb.max.z + 1 {
224 for y in aabb.min.y..aabb.max.y + 1 {
225 for x in aabb.min.x..aabb.max.x + 1 {
226 f(Vec3::new(x, y, z), *self.get_unchecked(Vec3::new(x, y, z)));
227 }
228 }
229 }
230 }
231 }
232}
233
234impl<V: Clone + PartialEq, S: RectVolSize, M: Clone> WriteVol for Chonk<V, S, M> {
235 #[inline(always)]
236 fn set(&mut self, pos: Vec3<i32>, block: Self::Vox) -> Result<V, Self::Error> {
237 let mut sub_chunk_idx = self.sub_chunk_idx(pos.z);
238
239 if pos.z < self.get_min_z() {
240 if block == self.below {
242 return Ok(self.below.clone());
243 }
244 let c = Chunk::<V, SubChunkSize<S>, M>::filled(self.below.clone(), self.meta.clone());
246 let n = (-sub_chunk_idx) as usize;
247 self.sub_chunks.splice(0..0, std::iter::repeat_n(c, n));
248 self.z_offset += sub_chunk_idx * SubChunkSize::<S>::SIZE.z as i32;
249 sub_chunk_idx = 0;
250 } else if pos.z >= self.get_max_z() {
251 if block == self.above {
253 return Ok(self.above.clone());
254 }
255 let c = Chunk::<V, SubChunkSize<S>, M>::filled(self.above.clone(), self.meta.clone());
257 let n = 1 + sub_chunk_idx as usize - self.sub_chunks.len();
258 self.sub_chunks.extend(std::iter::repeat_n(c, n));
259 }
260
261 let rpos = pos
262 - Vec3::unit_z() * (self.z_offset + sub_chunk_idx * SubChunkSize::<S>::SIZE.z as i32);
263 self.sub_chunks[sub_chunk_idx as usize] .set(rpos, block)
265 .map_err(Self::Error::SubChunkError)
266 }
267}
268
269struct ChonkIterHelper<V, S: RectVolSize, M: Clone> {
270 sub_chunk_min_z: i32,
271 lower_bound: Vec3<i32>,
272 upper_bound: Vec3<i32>,
273 phantom: PhantomData<Chonk<V, S, M>>,
274}
275
276impl<V, S: RectVolSize, M: Clone> Iterator for ChonkIterHelper<V, S, M> {
277 type Item = (i32, Vec3<i32>, Vec3<i32>);
278
279 #[inline(always)]
280 fn next(&mut self) -> Option<Self::Item> {
281 if self.lower_bound.z >= self.upper_bound.z {
282 return None;
283 }
284 let mut lb = self.lower_bound;
285 let mut ub = self.upper_bound;
286 let current_min_z = self.sub_chunk_min_z;
287 lb.z -= current_min_z;
288 ub.z -= current_min_z;
289 ub.z = std::cmp::min(ub.z, SubChunkSize::<S>::SIZE.z as i32);
290 self.sub_chunk_min_z += SubChunkSize::<S>::SIZE.z as i32;
291 self.lower_bound.z = self.sub_chunk_min_z;
292 Some((current_min_z, lb, ub))
293 }
294}
295
296pub struct ChonkPosIter<V, S: RectVolSize, M: Clone> {
297 outer: ChonkIterHelper<V, S, M>,
298 opt_inner: Option<(i32, ChunkPosIter<V, SubChunkSize<S>, M>)>,
299}
300
301impl<V, S: RectVolSize, M: Clone> Iterator for ChonkPosIter<V, S, M> {
302 type Item = Vec3<i32>;
303
304 #[inline(always)]
305 fn next(&mut self) -> Option<Self::Item> {
306 loop {
307 if let Some((sub_chunk_min_z, ref mut inner)) = self.opt_inner {
308 if let Some(mut pos) = inner.next() {
309 pos.z += sub_chunk_min_z;
310 return Some(pos);
311 }
312 }
313 match self.outer.next() {
314 None => return None,
315 Some((sub_chunk_min_z, lb, ub)) => {
316 self.opt_inner = Some((sub_chunk_min_z, SubChunk::<V, S, M>::pos_iter(lb, ub)))
317 },
318 }
319 }
320 }
321}
322
323enum InnerChonkVolIter<'a, V, S: RectVolSize, M: Clone> {
324 Vol(ChunkVolIter<'a, V, SubChunkSize<S>, M>),
325 Pos(ChunkPosIter<V, SubChunkSize<S>, M>),
326}
327
328pub struct ChonkVolIter<'a, V, S: RectVolSize, M: Clone> {
329 chonk: &'a Chonk<V, S, M>,
330 outer: ChonkIterHelper<V, S, M>,
331 opt_inner: Option<(i32, InnerChonkVolIter<'a, V, S, M>)>,
332}
333
334impl<'a, V, S: RectVolSize, M: Clone> Iterator for ChonkVolIter<'a, V, S, M> {
335 type Item = (Vec3<i32>, &'a V);
336
337 #[inline(always)]
338 fn next(&mut self) -> Option<Self::Item> {
339 loop {
340 if let Some((sub_chunk_min_z, ref mut inner)) = self.opt_inner {
341 let got = match inner {
342 InnerChonkVolIter::<'a, V, S, M>::Vol(iter) => iter.next(),
343 InnerChonkVolIter::<'a, V, S, M>::Pos(iter) => iter.next().map(|pos| {
344 if sub_chunk_min_z < self.chonk.get_min_z() {
345 (pos, &self.chonk.below)
346 } else {
347 (pos, &self.chonk.above)
348 }
349 }),
350 };
351 if let Some((mut pos, vox)) = got {
352 pos.z += sub_chunk_min_z;
353 return Some((pos, vox));
354 }
355 }
356 match self.outer.next() {
357 None => return None,
358 Some((sub_chunk_min_z, lb, ub)) => {
359 let inner = if sub_chunk_min_z < self.chonk.get_min_z()
360 || sub_chunk_min_z >= self.chonk.get_max_z()
361 {
362 InnerChonkVolIter::<'a, V, S, M>::Pos(SubChunk::<V, S, M>::pos_iter(lb, ub))
363 } else {
364 InnerChonkVolIter::<'a, V, S, M>::Vol(
365 self.chonk.sub_chunks
366 [self.chonk.sub_chunk_idx(sub_chunk_min_z) as usize]
367 .vol_iter(lb, ub),
368 )
369 };
370 self.opt_inner = Some((sub_chunk_min_z, inner));
371 },
372 }
373 }
374 }
375}
376
377impl<V, S: RectVolSize, M: Clone> IntoPosIterator for &Chonk<V, S, M> {
378 type IntoIter = ChonkPosIter<V, S, M>;
379
380 fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter {
381 Self::IntoIter {
382 outer: ChonkIterHelper::<V, S, M> {
383 sub_chunk_min_z: self.sub_chunk_min_z(lower_bound.z),
384 lower_bound,
385 upper_bound,
386 phantom: PhantomData,
387 },
388 opt_inner: None,
389 }
390 }
391}
392
393impl<'a, V, S: RectVolSize, M: Clone> IntoVolIterator<'a> for &'a Chonk<V, S, M> {
394 type IntoIter = ChonkVolIter<'a, V, S, M>;
395
396 fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter {
397 Self::IntoIter {
398 chonk: self,
399 outer: ChonkIterHelper::<V, S, M> {
400 sub_chunk_min_z: self.sub_chunk_min_z(lower_bound.z),
401 lower_bound,
402 upper_bound,
403 phantom: PhantomData,
404 },
405 opt_inner: None,
406 }
407 }
408}