1use std::collections::HashMap;
2
3use crate::util::OpaquePtr;
4
5
6#[derive(Debug)]
8pub struct Biome {
9 name: &'static str,
10 id: i32
11}
12
13
14pub type BiomeKey = OpaquePtr<Biome>;
17
18
19impl Biome {
20
21 pub const fn new(name: &'static str, id: i32) -> Self {
22 Self { name, id }
23 }
24
25 #[inline]
26 pub fn get_name(&self) -> &'static str {
27 self.name
28 }
29
30 #[inline]
31 pub fn get_key(&'static self) -> BiomeKey {
32 OpaquePtr::new(self)
33 }
34
35 #[inline]
36 pub fn get_id(&self) -> i32 {
37 self.id
38 }
39
40}
41
42impl PartialEq for &'static Biome {
43 fn eq(&self, other: &Self) -> bool {
44 std::ptr::eq(*self, *other)
45 }
46}
47
48impl Eq for &'static Biome {}
49
50
51pub struct GlobalBiomes {
55 next_sid: u16,
56 biome_to_sid: HashMap<BiomeKey, u16>,
57 sid_to_biome: Vec<&'static Biome>,
58 name_to_biome: HashMap<&'static str, &'static Biome>,
59 id_to_biome: HashMap<i32, &'static Biome>
60}
61
62impl GlobalBiomes {
63
64 pub fn new() -> Self {
65 Self {
66 next_sid: 0,
67 biome_to_sid: HashMap::new(),
68 sid_to_biome: Vec::new(),
69 name_to_biome: HashMap::new(),
70 id_to_biome: HashMap::new()
71 }
72 }
73
74 pub fn with_all(slice: &[&'static Biome]) -> Result<Self, ()> {
76 let mut biomes = Self::new();
77 biomes.register_all(slice)?;
78 Ok(biomes)
79 }
80
81 pub fn register(&mut self, biome: &'static Biome) -> Result<(), ()> {
85
86 let sid = self.next_sid;
87 let next_sid = sid.checked_add(1).ok_or(())?;
88
89 if let None = self.biome_to_sid.insert(biome.get_key(), sid) {
90 self.next_sid = next_sid;
91 self.sid_to_biome.push(biome);
92 self.name_to_biome.insert(biome.name, biome);
93 self.id_to_biome.insert(biome.id, biome);
94 }
95
96 Ok(())
97
98 }
99
100 pub fn register_all(&mut self, slice: &[&'static Biome]) -> Result<(), ()> {
104 let count = slice.len();
105 self.biome_to_sid.reserve(count);
106 self.sid_to_biome.reserve(count);
107 self.name_to_biome.reserve(count);
108 self.id_to_biome.reserve(count);
109 for &biome in slice {
110 self.register(biome)?;
111 }
112 Ok(())
113 }
114
115 pub fn get_sid_from(&self, biome: &'static Biome) -> Option<u16> {
116 Some(*self.biome_to_sid.get(&biome.get_key())?)
117 }
118
119 pub fn get_biome_from(&self, sid: u16) -> Option<&'static Biome> {
120 Some(*self.sid_to_biome.get(sid as usize)?)
121 }
122
123 pub fn get_biome_from_name(&self, name: &str) -> Option<&'static Biome> {
124 self.name_to_biome.get(name).cloned()
125 }
126
127 pub fn get_biome_from_id(&self, id: i32) -> Option<&'static Biome> {
128 self.id_to_biome.get(&id).cloned()
129 }
130
131 pub fn has_biome(&self, biome: &'static Biome) -> bool {
132 self.biome_to_sid.contains_key(&biome.get_key())
133 }
134
135 pub fn check_biome<E>(&self, biome: &'static Biome, err: impl FnOnce() -> E) -> Result<&'static Biome, E> {
136 if self.has_biome(biome) { Ok(biome) } else { Err(err()) }
137 }
138
139 pub fn biomes_count(&self) -> usize {
140 self.sid_to_biome.len()
141 }
142
143}
144
145
146#[macro_export]
147macro_rules! biomes {
148 ($global_vis:vis $static_id:ident $namespace:literal [
149 $($biome_id:ident $biome_name:literal $biome_numeric_id:literal),*
150 $(,)?
151 ]) => {
152
153 $($global_vis static $biome_id: $crate::biome::Biome = $crate::biome::Biome::new(
154 concat!($namespace, ':', $biome_name),
155 $biome_numeric_id
156 );)*
157
158 $global_vis static $static_id: [&'static $crate::biome::Biome; $crate::count!($($biome_id)*)] = [
159 $(&$biome_id),*
160 ];
161
162 };
163}