mc_core/heightmap/
mod.rs

1use crate::block::{BlockState, GlobalBlocks};
2use crate::util::OpaquePtr;
3
4use std::collections::HashMap;
5
6
7/// A structure used to statically define an heightmap type.
8///
9/// The heightmap's predicate must not return true upon "null block", this restriction is needed
10/// at the current state of the crate because the "null block" is currently used to optimize
11/// storage.
12pub struct HeightmapType {
13    pub name: &'static str,
14    pub predicate: fn(&'static BlockState, &GlobalBlocks) -> bool
15}
16
17impl HeightmapType {
18
19    #[inline]
20    pub fn get_name(&self) -> &'static str {
21        self.name
22    }
23
24    #[inline]
25    pub fn get_key(&'static self) -> HeightmapTypeKey {
26        OpaquePtr::new(self)
27    }
28
29    #[inline]
30    pub fn check_block(&self, state: &'static BlockState, blocks: &GlobalBlocks) -> bool {
31        (self.predicate)(state, blocks)
32    }
33
34}
35
36pub type HeightmapTypeKey = OpaquePtr<HeightmapType>;
37
38impl PartialEq for &'static HeightmapType {
39    fn eq(&self, other: &Self) -> bool {
40        std::ptr::eq(*self, *other)
41    }
42}
43
44impl Eq for &'static HeightmapType { }
45
46
47/// A global heightmaps palette used by level, each chunk created into it will include all
48/// these heightmaps and automatically computed and updated when modifying the chunk.
49pub struct GlobalHeightmaps {
50    heightmap_types: Vec<&'static HeightmapType>,
51    heightmap_types_to_index: HashMap<HeightmapTypeKey, usize>,
52}
53
54impl GlobalHeightmaps {
55
56    pub fn new() -> Self {
57        Self {
58            heightmap_types: Vec::new(),
59            heightmap_types_to_index: HashMap::new()
60        }
61    }
62
63    pub fn with_all(slice: &[&'static HeightmapType]) -> Self {
64        let mut heightmaps = Self::new();
65        heightmaps.register_all(slice);
66        heightmaps
67    }
68
69    pub fn register(&mut self, heightmap_type: &'static HeightmapType) {
70        self.heightmap_types_to_index.insert(heightmap_type.get_key(), self.heightmap_types.len());
71        self.heightmap_types.push(heightmap_type);
72    }
73
74    pub fn register_all(&mut self, slice: &[&'static HeightmapType]) {
75        self.heightmap_types.reserve(slice.len());
76        self.heightmap_types_to_index.reserve(slice.len());
77        for &heightmap_type in slice {
78            self.register(heightmap_type);
79        }
80    }
81
82    pub fn get_heightmap_index(&self, heightmap_type: &'static HeightmapType) -> Option<usize> {
83        self.heightmap_types_to_index.get(&heightmap_type.get_key()).copied()
84    }
85
86    pub fn get_heightmap_from(&self, index: usize) -> Option<&'static HeightmapType> {
87        self.heightmap_types.get(index).copied()
88    }
89
90    pub fn has_heightmap_type(&self, heightmap_type: &'static HeightmapType) -> bool {
91        self.heightmap_types.iter().any(move |&t| t == heightmap_type)
92    }
93
94    pub fn iter_heightmap_types(&self) -> impl Iterator<Item = &'static HeightmapType> + '_ {
95        self.heightmap_types.iter().copied()
96    }
97
98    pub fn heightmaps_count(&self) -> usize {
99        self.heightmap_types.len()
100    }
101
102}
103
104
105#[macro_export]
106macro_rules! heightmaps {
107    ($global_vis:vis $static_id:ident [
108        $($heightmap_id:ident $heightmap_name:literal $heightmap_predicate:ident),*
109        $(,)?
110    ]) => {
111
112        $($global_vis static $heightmap_id: $crate::heightmap::HeightmapType = $crate::heightmap::HeightmapType {
113            name: $heightmap_name,
114            predicate: $heightmap_predicate
115        };)*
116
117        $global_vis static $static_id: [&'static $crate::heightmap::HeightmapType; $crate::count!($($heightmap_id)*)] = [
118            $(&$heightmap_id),*
119        ];
120
121    };
122}