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
32pub const CURRENT_VERSION: u32 = 10;
38
39#[derive(Clone, Serialize, Deserialize)]
40pub struct Data {
41 #[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 #[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 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 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}