1use crate::comp::{Pos, Presence, Vel};
2use common_base::span;
3use hashbrown::{DefaultHashBuilder, HashSet};
4use indexmap::IndexMap;
5use specs::{BitSet, Entities, Join, LendJoin, ReadStorage, hibitset::BitSetLike};
6use vek::*;
7
8pub enum Event {
9 Left(u32, Option<Vec2<i32>>),
14 Entered(u32, Option<Vec2<i32>>),
16}
17
18#[derive(Default)]
20pub struct Region {
21 bitset: BitSet,
23 neighbors: [Option<usize>; 8],
25 events: Vec<Event>,
28}
29impl Region {
30 fn removable(&self) -> bool { self.bitset.is_empty() && self.events.is_empty() }
32
33 fn add(&mut self, id: u32, from: Option<Vec2<i32>>) {
34 self.bitset.add(id);
35 self.events.push(Event::Entered(id, from));
36 }
37
38 fn remove(&mut self, id: u32, to: Option<Vec2<i32>>) {
39 self.bitset.remove(id);
40 self.events.push(Event::Left(id, to));
41 }
42
43 pub fn events(&self) -> &[Event] { &self.events }
44
45 pub fn entities(&self) -> &BitSet { &self.bitset }
46}
47
48pub const TETHER_LENGTH: u32 = 16;
52const REGION_LOG2: u8 = 9;
54pub const REGION_SIZE: u32 = 1 << REGION_LOG2;
56const NEIGHBOR_OFFSETS: [Vec2<i32>; 8] = [
59 Vec2::new(0, 1),
60 Vec2::new(-1, 1),
61 Vec2::new(-1, 0),
62 Vec2::new(-1, -1),
63 Vec2::new(0, -1),
64 Vec2::new(1, -1),
65 Vec2::new(1, 0),
66 Vec2::new(1, 1),
67];
68
69#[derive(Default)]
70pub struct RegionMap {
79 regions: IndexMap<Vec2<i32>, Region, DefaultHashBuilder>,
84 tracked_entities: BitSet,
86 entities_to_move: Vec<(usize, u32, Vec3<i32>)>,
89 entities_to_remove: Vec<(usize, u32)>,
91 tick: u64,
94}
95impl RegionMap {
96 pub fn new() -> Self { Self::default() }
97
98 pub fn tick(
101 &mut self,
102 pos: ReadStorage<Pos>,
103 vel: ReadStorage<Vel>,
104 presence: ReadStorage<Presence>,
105 entities: Entities,
106 ) {
107 span!(_guard, "tick", "Region::tick");
108 self.tick += 1;
109 self.regions.values_mut().for_each(|region| {
111 region.events.clear();
112 });
113
114 for (pos, id) in (&pos, &entities, presence.maybe(), !&self.tracked_entities)
116 .join()
117 .filter(|(_, _, presence, _)| presence.is_none_or(|p| p.kind.sync_me()))
118 .map(|(pos, e, _, _)| (pos, e.id()))
119 .collect::<Vec<_>>()
120 {
121 self.tracked_entities.add(id);
123 self.add_entity(id, pos.0.map(|e| e as i32), None);
124 }
125
126 let mut regions_to_remove = Vec::new();
127
128 let RegionMap {
129 entities_to_move,
130 entities_to_remove,
131 regions,
132 ..
133 } = self;
134 regions
135 .iter()
136 .enumerate()
137 .for_each(|(i, (¤t_region, region_data))| {
138 for (maybe_pos, _maybe_vel, maybe_presence, id) in (
139 pos.maybe(),
140 vel.maybe(),
141 presence.maybe(),
142 ®ion_data.bitset,
143 )
144 .join()
145 {
146 let should_sync = maybe_presence.is_none_or(|p| p.kind.sync_me());
147 match maybe_pos {
148 Some(pos) if should_sync => {
153 let pos = pos.0.map(|e| e as i32);
154 let key = Self::pos_key(pos);
155 if key != current_region
158 && (Vec2::<i32>::from(pos) - Self::key_pos(current_region))
159 .map(|e| e.unsigned_abs())
160 .reduce_max()
161 > TETHER_LENGTH
162 {
163 entities_to_move.push((i, id, pos));
165 }
166 },
167 None | Some(_) => {
170 entities_to_remove.push((i, id));
174 },
175 }
176 }
177
178 if region_data.removable() {
181 regions_to_remove.push(current_region);
182 }
183 });
184
185 while let Some((i, id, pos)) = self.entities_to_move.pop() {
189 let (prev_key, region) = self.regions.get_index_mut(i).map(|(k, v)| (*k, v)).unwrap();
190 region.remove(id, Some(Self::pos_key(pos)));
191
192 self.add_entity(id, pos, Some(prev_key));
193 }
194 for (i, id) in self.entities_to_remove.drain(..) {
195 self.regions
196 .get_index_mut(i)
197 .map(|(_, v)| v)
198 .unwrap()
199 .remove(id, None);
200 self.tracked_entities.remove(id);
201 }
202 for key in regions_to_remove.into_iter() {
203 if self.regions.get(&key).unwrap().removable() {
205 self.remove(key);
208 }
209 }
210 }
211
212 pub fn entity_deleted(&mut self, entity: specs::Entity) {
216 self.tracked_entities.remove(entity.id());
217 }
218
219 fn add_entity(&mut self, id: u32, pos: Vec3<i32>, from: Option<Vec2<i32>>) {
220 let key = Self::pos_key(pos);
221 if let Some(region) = self.regions.get_mut(&key) {
222 region.add(id, from);
223 return;
224 }
225
226 let index = self.insert(key);
227 self.regions
228 .get_index_mut(index)
229 .map(|(_, v)| v)
230 .unwrap()
231 .add(id, None);
232 }
233
234 fn pos_key<P: Into<Vec2<i32>>>(pos: P) -> Vec2<i32> { pos.into().map(|e| e >> REGION_LOG2) }
235
236 pub fn key_pos(key: Vec2<i32>) -> Vec2<i32> { key.map(|e| e << REGION_LOG2) }
237
238 pub fn find_region(&self, entity: specs::Entity, pos: Vec3<f32>) -> Option<Vec2<i32>> {
241 let id = entity.id();
242 let key = Self::pos_key(pos.map(|e| e as i32));
244 if let Some(region) = self.regions.get(&key) {
246 if region.entities().contains(id) {
247 return Some(key);
248 } else {
249 for idx in region.neighbors.iter().flatten() {
251 let (key, region) = self.regions.get_index(*idx).unwrap();
252 if region.entities().contains(id) {
253 return Some(*key);
254 }
255 }
256 }
257 } else if !self.tracked_entities.contains(id) {
258 return None;
259 } else {
260 for o in &NEIGHBOR_OFFSETS {
262 let key = key + o;
263 if let Some(region) = self.regions.get(&key) {
264 if region.entities().contains(id) {
265 return Some(key);
266 }
267 }
268 }
269 }
270
271 for (key, region) in self.iter() {
273 if region.entities().contains(id) {
274 return Some(key);
275 }
276 }
277
278 None
279 }
280
281 pub fn in_region_map(&self, entity: specs::Entity) -> bool {
283 self.tracked_entities.contains(entity.id())
284 }
285
286 fn key_index(&self, key: Vec2<i32>) -> Option<usize> {
287 self.regions.get_full(&key).map(|(i, _, _)| i)
288 }
289
290 fn insert(&mut self, key: Vec2<i32>) -> usize {
293 let (index, old_region) = self.regions.insert_full(key, Region::default());
294 if old_region.is_some() {
295 panic!("Inserted a region that already exists!!!(this should never need to occur");
296 }
297 let mut neighbors = [None; 8];
299 for i in 0..8 {
300 if let Some((idx, _, region)) = self.regions.get_full_mut(&(key + NEIGHBOR_OFFSETS[i]))
301 {
302 neighbors[i] = Some(idx);
304 region.neighbors[(i + 4) % 8] = Some(index);
306 }
307 }
308 self.regions
309 .get_index_mut(index)
310 .map(|(_, v)| v)
311 .unwrap()
312 .neighbors = neighbors;
313
314 index
315 }
316
317 fn remove(&mut self, key: Vec2<i32>) {
319 if let Some(index) = self.key_index(key) {
320 self.remove_index(index);
321 }
322 }
323
324 fn remove_index(&mut self, index: usize) {
326 if index != self.regions.len() - 1 {
329 let moved_neighbors = self
330 .regions
331 .get_index(self.regions.len() - 1)
332 .map(|(_, v)| v)
333 .unwrap()
334 .neighbors;
335 for (i, possible_idx) in moved_neighbors.iter().enumerate() {
336 if let Some(idx) = possible_idx {
337 self.regions
338 .get_index_mut(*idx)
339 .map(|(_, v)| v)
340 .unwrap()
341 .neighbors[(i + 4) % 8] = Some(index);
342 }
343 }
344 }
345 if let Some(region) = self
346 .regions
347 .swap_remove_index(index)
348 .map(|(_, region)| region)
349 {
350 if !region.bitset.is_empty() {
351 panic!("Removed region containing entities");
352 }
353 for i in 0..8 {
355 if let Some(idx) = region.neighbors[i] {
356 self.regions
357 .get_index_mut(idx)
358 .map(|(_, v)| v)
359 .unwrap()
360 .neighbors[(i + 4) % 8] = None;
361 }
362 }
363 }
364 }
365
366 pub fn get(&self, key: Vec2<i32>) -> Option<&Region> { self.regions.get(&key) }
368
369 pub fn iter(&self) -> impl Iterator<Item = (Vec2<i32>, &Region)> {
371 self.regions.iter().map(|(key, r)| (*key, r))
372 }
373}
374
375pub fn region_in_vd(key: Vec2<i32>, pos: Vec3<f32>, vd: f32) -> bool {
377 let vd_extended = vd + TETHER_LENGTH as f32 * 2.0f32.sqrt();
378
379 let min_region_pos = RegionMap::key_pos(key).map(|e| e as f32);
380 let diff = (min_region_pos - Vec2::from(pos)).map(|e| {
383 if e < 0.0 {
384 (e + REGION_SIZE as f32).min(0.0)
385 } else {
386 e
387 }
388 });
389
390 diff.magnitude_squared() < vd_extended.powi(2)
391}
392
393pub fn regions_in_vd(pos: Vec3<f32>, vd: f32) -> HashSet<Vec2<i32>> {
395 let mut set = HashSet::new();
396
397 let pos_xy = Vec2::<f32>::from(pos);
398 let vd_extended = vd + TETHER_LENGTH as f32 * 2.0f32.sqrt();
399
400 let max = RegionMap::pos_key(pos_xy.map(|e| (e + vd_extended) as i32));
401 let min = RegionMap::pos_key(pos_xy.map(|e| (e - vd_extended) as i32));
402
403 for x in min.x..max.x + 1 {
404 for y in min.y..max.y + 1 {
405 let key = Vec2::new(x, y);
406
407 if region_in_vd(key, pos, vd) {
408 set.insert(key);
409 }
410 }
411 }
412
413 set
414}
415