veloren_rtsim/data/
mod.rs

1pub mod airship;
2pub mod faction;
3pub mod nature;
4pub mod npc;
5pub mod report;
6pub mod sentiment;
7pub mod site;
8
9pub use self::{
10    faction::{Faction, FactionId, Factions},
11    nature::Nature,
12    npc::{Npc, NpcId, Npcs},
13    report::{Report, ReportId, ReportKind, Reports},
14    sentiment::{Sentiment, Sentiments},
15    site::{Site, SiteId, Sites},
16};
17use airship::AirshipSim;
18use common::resources::TimeOfDay;
19use enum_map::{EnumArray, EnumMap, enum_map};
20use serde::{Deserialize, Serialize, de, ser};
21use std::{
22    cmp::PartialEq,
23    fmt,
24    io::{Read, Write},
25    marker::PhantomData,
26};
27
28/// The current version of rtsim data.
29///
30/// Note that this number does *not* need incrementing on every change: most
31/// field removals/additions are fine. This number should only be incremented
32/// when we wish to perform a *hard purge* of rtsim data.
33pub const CURRENT_VERSION: u32 = 8;
34
35#[derive(Clone, Serialize, Deserialize)]
36pub struct Data {
37    // Absence of field just implied version = 0
38    #[serde(default)]
39    pub version: u32,
40
41    pub nature: Nature,
42    #[serde(default)]
43    pub npcs: Npcs,
44    #[serde(default)]
45    pub sites: Sites,
46    #[serde(default)]
47    pub factions: Factions,
48    #[serde(default)]
49    pub reports: Reports,
50
51    #[serde(default)]
52    pub tick: u64,
53    #[serde(default)]
54    pub time_of_day: TimeOfDay,
55
56    // If true, rtsim data will be ignored (and, hence, overwritten on next save) on load.
57    #[serde(default)]
58    pub should_purge: bool,
59
60    #[serde(skip)]
61    pub airship_sim: AirshipSim,
62}
63
64pub enum ReadError {
65    Load(rmp_serde::decode::Error),
66    // Preserve old data
67    VersionMismatch(Box<Data>),
68}
69
70impl fmt::Debug for ReadError {
71    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72        match self {
73            Self::Load(err) => err.fmt(f),
74            Self::VersionMismatch(_) => write!(f, "VersionMismatch"),
75        }
76    }
77}
78
79pub type WriteError = rmp_serde::encode::Error;
80
81impl Data {
82    pub fn spawn_npc(&mut self, npc: Npc) -> NpcId {
83        let home = npc.home;
84        let id = self.npcs.create_npc(npc);
85        if let Some(home) = home.and_then(|home| self.sites.get_mut(home)) {
86            home.population.insert(id);
87        }
88        id
89    }
90
91    pub fn from_reader<R: Read>(reader: R) -> Result<Box<Self>, ReadError> {
92        rmp_serde::decode::from_read(reader)
93            .map_err(ReadError::Load)
94            .and_then(|data: Data| {
95                if data.version == CURRENT_VERSION {
96                    Ok(Box::new(data))
97                } else {
98                    Err(ReadError::VersionMismatch(Box::new(data)))
99                }
100            })
101    }
102
103    pub fn write_to<W: Write>(&self, mut writer: W) -> Result<(), WriteError> {
104        rmp_serde::encode::write_named(&mut writer, self)
105    }
106}
107
108fn rugged_ser_enum_map<
109    K: EnumArray<V> + Serialize,
110    V: From<i16> + PartialEq + Serialize,
111    S: ser::Serializer,
112    const DEFAULT: i16,
113>(
114    map: &EnumMap<K, V>,
115    ser: S,
116) -> Result<S::Ok, S::Error> {
117    ser.collect_map(map.iter().filter(|(_, v)| v != &&V::from(DEFAULT)))
118}
119
120fn rugged_de_enum_map<
121    'a,
122    K: EnumArray<V> + EnumArray<Option<V>> + Deserialize<'a>,
123    V: From<i16> + Deserialize<'a>,
124    D: de::Deserializer<'a>,
125    const DEFAULT: i16,
126>(
127    de: D,
128) -> Result<EnumMap<K, V>, D::Error> {
129    struct Visitor<K, V, const DEFAULT: i16>(PhantomData<(K, V)>);
130
131    impl<'de, K, V, const DEFAULT: i16> de::Visitor<'de> for Visitor<K, V, DEFAULT>
132    where
133        K: EnumArray<V> + EnumArray<Option<V>> + Deserialize<'de>,
134        V: From<i16> + Deserialize<'de>,
135    {
136        type Value = EnumMap<K, V>;
137
138        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
139            write!(formatter, "a map")
140        }
141
142        fn visit_map<M: de::MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
143            let mut entries = EnumMap::default();
144            while let Some((key, value)) = access.next_entry()? {
145                entries[key] = Some(value);
146            }
147            Ok(enum_map! { key => entries[key].take().unwrap_or_else(|| V::from(DEFAULT)) })
148        }
149    }
150
151    de.deserialize_map(Visitor::<_, _, DEFAULT>(PhantomData))
152}