veloren_server/
location.rs

1use common::comp::Content;
2use hashbrown::HashMap;
3use std::fmt;
4use vek::*;
5
6#[derive(Debug)]
7pub enum LocationError<'a> {
8    InvalidName(String),
9    DuplicateName(String),
10    DoesNotExist(&'a str),
11}
12
13impl<'a> From<LocationError<'a>> for Content {
14    fn from(value: LocationError<'a>) -> Self {
15        match value {
16            LocationError::InvalidName(location) => {
17                Content::localized_with_args("command-location-invalid", [("location", location)])
18            },
19            LocationError::DuplicateName(location) => {
20                Content::localized_with_args("command-location-duplicate", [("location", location)])
21            },
22            LocationError::DoesNotExist(location) => {
23                Content::localized_with_args("command-location-not-found", [("location", location)])
24            },
25        }
26    }
27}
28
29impl fmt::Display for LocationError<'_> {
30    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31        match self {
32            Self::InvalidName(name) => write!(
33                f,
34                "Location name '{}' is invalid. Names may only contain lowercase ASCII and \
35                 underscores",
36                name
37            ),
38            Self::DuplicateName(name) => write!(
39                f,
40                "Location '{}' already exists, consider deleting it first",
41                name
42            ),
43            Self::DoesNotExist(name) => write!(f, "Location '{}' does not exist", name),
44        }
45    }
46}
47
48/// Locations are moderator-defined positions that can be teleported between by
49/// players. They currently do not persist between server sessions.
50#[derive(Default)]
51pub struct Locations {
52    locations: HashMap<String, Vec3<f32>>,
53}
54
55impl Locations {
56    pub fn insert(&mut self, name: String, pos: Vec3<f32>) -> Result<(), LocationError<'static>> {
57        if name.chars().all(|c| c.is_ascii_lowercase() || c == '_') {
58            self.locations
59                .try_insert(name, pos)
60                .map(|_| ())
61                .map_err(|o| LocationError::DuplicateName(o.entry.key().clone()))
62        } else {
63            Err(LocationError::InvalidName(name))
64        }
65    }
66
67    pub fn get<'a>(&self, name: &'a str) -> Result<Vec3<f32>, LocationError<'a>> {
68        self.locations
69            .get(name)
70            .copied()
71            .ok_or(LocationError::DoesNotExist(name))
72    }
73
74    pub fn iter(&self) -> impl Iterator<Item = &String> { self.locations.keys() }
75
76    pub fn remove<'a>(&mut self, name: &'a str) -> Result<(), LocationError<'a>> {
77        self.locations
78            .remove(name)
79            .map(|_| ())
80            .ok_or(LocationError::DoesNotExist(name))
81    }
82}