Skip to main content

veloren_common_state/
special_areas.rs

1use common::depot::{Depot, Id};
2use hashbrown::{HashMap, hash_map};
3use std::{
4    marker::PhantomData,
5    ops::{Deref, DerefMut},
6};
7use vek::*;
8
9#[derive(Default)]
10pub struct AreasContainer<Kind>(Areas, PhantomData<Kind>);
11
12#[derive(Default)]
13pub struct BuildArea;
14
15#[derive(Default)]
16pub struct NoDurabilityArea;
17
18/// An area where one can change battle mode.
19#[derive(Default)]
20pub struct BattleModeChangeArea;
21
22/// NOTE: Please don't add `Deserialize` without checking to make sure we
23/// can guarantee the invariant that every entry in `area_names` points to a
24/// valid id in `areas`.
25#[derive(Default)]
26pub struct Areas {
27    areas: Depot<Aabb<i32>>,
28    area_names: HashMap<String, Id<Aabb<i32>>>,
29}
30
31pub enum SpecialAreaError {
32    /// This build area name is reserved by the system.
33    Reserved,
34    /// The build area name was not found.
35    NotFound,
36}
37
38/// Build area names that can only be inserted, not removed.
39const RESERVED_BUILD_AREA_NAMES: &[&str] = &["world"];
40
41impl Areas {
42    pub fn areas(&self) -> &Depot<Aabb<i32>> { &self.areas }
43
44    pub fn area_metas(&self) -> &HashMap<String, Id<Aabb<i32>>> { &self.area_names }
45
46    /// If the area_name is already in the map, returns Err(area_name).
47    pub fn insert(&mut self, area_name: String, area: Aabb<i32>) -> Result<Id<Aabb<i32>>, String> {
48        let area_name_entry = match self.area_names.entry(area_name) {
49            hash_map::Entry::Occupied(o) => return Err(o.key().to_string()),
50            hash_map::Entry::Vacant(v) => v,
51        };
52        let bb_id = self.areas.insert(area.made_valid());
53        area_name_entry.insert(bb_id);
54        Ok(bb_id)
55    }
56
57    pub fn remove(&mut self, area_name: &str) -> Result<Aabb<i32>, SpecialAreaError> {
58        if RESERVED_BUILD_AREA_NAMES.contains(&area_name) {
59            return Err(SpecialAreaError::Reserved);
60        }
61        let bb_id = self
62            .area_names
63            .remove(area_name)
64            .ok_or(SpecialAreaError::NotFound)?;
65        let area = self.areas.remove(bb_id).expect(
66            "Entries in `areas` are added before entries in `area_names` in `insert`, and that is \
67             the only exposed way to add elements to `area_names`.",
68        );
69        Ok(area)
70    }
71}
72
73impl<Kind> Deref for AreasContainer<Kind>
74where
75    Kind: AreaKind,
76{
77    type Target = Areas;
78
79    fn deref(&self) -> &Self::Target { &self.0 }
80}
81
82impl<Kind> DerefMut for AreasContainer<Kind>
83where
84    Kind: AreaKind,
85{
86    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
87}
88
89pub trait AreaKind {
90    fn display() -> &'static str;
91}
92
93impl AreaKind for BuildArea {
94    fn display() -> &'static str { "build" }
95}
96
97impl AreaKind for NoDurabilityArea {
98    fn display() -> &'static str { "durability free" }
99}
100
101impl AreaKind for BattleModeChangeArea {
102    fn display() -> &'static str { "battlemode change" }
103}