veloren_rtsim/data/
mod.rs

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