veloren_rtsim/data/
mod.rs

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