Skip to main content

fastanvil/java/
section_tower.rs

1use serde::Deserialize;
2
3use crate::SectionLike;
4
5/// SectionTower represents the set of sections that make up a Minecraft chunk.
6/// It has a custom deserialization in order to more efficiently lay out the
7/// sections for quick access.
8#[derive(Debug)]
9pub struct SectionTower<S> {
10    sections: Vec<S>,
11    map: Vec<Option<usize>>,
12    y_min: isize,
13    y_max: isize,
14}
15
16impl<S> SectionTower<S> {
17    pub fn sections(&self) -> &[S] {
18        &self.sections
19    }
20
21    pub(crate) fn take_sections(self) -> Vec<S> {
22        self.sections
23    }
24
25    pub fn get_section_for_y(&self, y: isize) -> Option<&S> {
26        if y >= self.y_max || y < self.y_min {
27            // TODO: This occurs a lot in hermitcraft season 7. Probably some
28            // form of bug?
29            return None;
30        }
31
32        let lookup_index = y_to_index(y, self.y_min);
33
34        let section_index = *self.map.get(lookup_index as usize)?;
35        self.sections.get(section_index?)
36    }
37
38    pub fn y_min(&self) -> isize {
39        self.y_min
40    }
41
42    pub fn y_max(&self) -> isize {
43        self.y_max
44    }
45}
46
47impl<'de, S: SectionLike + Deserialize<'de>> Deserialize<'de> for SectionTower<S> {
48    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
49        where
50            D: serde::Deserializer<'de>,
51    {
52        let sections: Vec<S> = Deserialize::deserialize(deserializer)?;
53        if sections.is_empty() {
54            return Ok(Self {
55                sections,
56                map: vec![],
57                y_min: 0,
58                y_max: 0,
59            });
60        }
61
62        // We need to figure out how deep the world goes. Since 1.17 the depth
63        // of worlds can be customized. Each section in the chunk will have a
64        // 'y' value. We need to find the minimum value here, and that will tell
65        // us the minimum world y.
66        let lowest_section = sections
67            .iter()
68            .min_by_key(|s| s.y())
69            .expect("checked no empty above");
70
71        // Sometimes the lowest section is a 'null' section. This isn't actually
72        // part of the world, it just indicates there no more sections below.
73        // You can tell if it's 'null terminated' by the palette and
74        // blockstates.
75        let null_term = lowest_section.is_terminator();
76
77        let min = if null_term {
78            lowest_section.y() as isize + 1
79        } else {
80            lowest_section.y() as isize
81        };
82        let max = sections
83            .iter()
84            .max_by_key(|s| s.y())
85            .map(|s| s.y())
86            .unwrap() as isize;
87
88        let mut sparse_sections = vec![None; (1 + max - min) as usize];
89
90        for (i, sec) in sections.iter().enumerate() {
91            // Don't bother adding the null section.
92            if sec.y() == lowest_section.y() && null_term {
93                continue;
94            }
95
96            let sec_index = (sec.y() as isize - min) as usize;
97
98            sparse_sections[sec_index] = Some(i);
99        }
100
101        Ok(Self {
102            sections,
103            map: sparse_sections,
104            y_min: 16 * min,
105            y_max: 16 * (max + 1),
106        })
107    }
108}
109
110const fn y_to_index(y: isize, y_min: isize) -> u8 {
111    ((y - y_min) >> 4) as u8
112}