1use crate::block::{BlockState, GlobalBlocks};
2use crate::util::OpaquePtr;
3
4use std::collections::HashMap;
5
6
7pub 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
47pub 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}