1use serde::ser::{Serialize, SerializeMap, Serializer};
15use serde_json::{json, Map, Value};
16
17use crate::events::{EventSystem, PendingChoice};
18use crate::ledger::{totals_json, Ledger};
19use crate::sim::{LogEntry, Simulation, LOG_SAVE_CAP, SAVE_VERSION};
20use crate::tower::{Transport, Unit};
21
22enum Field<'a> {
25 Owned(Value),
26 Borrowed(&'a Value),
27 Text(&'a str),
28 Units(&'a [Unit]),
29 Transports(&'a [Transport]),
30 Strings(&'a [String]),
31 Ids(&'a [i64]),
32 Floats(&'a [f64]),
33 Ledger(&'a Ledger),
34 Events(&'a EventSystem),
35 Log(&'a [LogEntry]),
36}
37
38fn log_entry(e: &LogEntry) -> Value {
39 json!({ "minute": e.minute, "text": e.text, "kind": e.kind.as_str() })
40}
41
42struct Each<'a, T, F>(&'a [T], F);
45
46impl<T, F: Fn(&T) -> Value> Serialize for Each<'_, T, F> {
47 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
48 s.collect_seq(self.0.iter().map(&self.1))
49 }
50}
51
52impl Field<'_> {
53 fn into_value(self) -> Value {
54 match self {
55 Field::Owned(v) => v,
56 Field::Borrowed(v) => v.clone(),
57 Field::Text(t) => json!(t),
58 Field::Units(us) => Value::Array(us.iter().map(Unit::serialize).collect()),
59 Field::Transports(ts) => Value::Array(ts.iter().map(Transport::serialize).collect()),
60 Field::Strings(ss) => json!(ss),
61 Field::Ids(ids) => json!(ids),
62 Field::Floats(fs) => json!(fs),
63 Field::Ledger(l) => l.serialize(),
64 Field::Events(e) => e.save_state(),
65 Field::Log(es) => Value::Array(es.iter().map(log_entry).collect()),
66 }
67 }
68}
69
70impl Serialize for Field<'_> {
71 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
72 match self {
73 Field::Owned(v) => v.serialize(s),
74 Field::Borrowed(v) => v.serialize(s),
75 Field::Units(us) => Each(us, Unit::serialize).serialize(s),
76 Field::Transports(ts) => Each(ts, Transport::serialize).serialize(s),
77 Field::Text(t) => t.serialize(s),
82 Field::Strings(ss) => ss.serialize(s),
83 Field::Ids(ids) => ids.serialize(s),
84 Field::Floats(fs) => fs.serialize(s),
85 Field::Ledger(l) => {
87 let mut m = s.serialize_map(Some(2))?;
88 m.serialize_entry("today", &totals_json(&l.today))?;
89 m.serialize_entry("history", &Each(&l.history, totals_json))?;
90 m.end()
91 }
92 Field::Events(e) => {
95 let mut m = s.serialize_map(Some(3 + usize::from(e.bomb.is_some())))?;
96 m.serialize_entry("lastSantaYear", &json!(e.last_santa_year))?;
97 m.serialize_entry("rngState", &json!(e.extra.seed()))?;
98 match &e.pending {
99 Some(p) => m.serialize_entry("pending", &Pending(p))?,
100 None => m.serialize_entry("pending", &Value::Null)?,
101 }
102 if let Some(b) = &e.bomb {
105 m.serialize_entry("bomb", &b.save_state())?;
106 }
107 m.end()
108 }
109 Field::Log(es) => Each(es, log_entry).serialize(s),
110 }
111 }
112}
113
114struct Pending<'a>(&'a PendingChoice);
117
118impl Serialize for Pending<'_> {
119 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
120 let mut m = s.serialize_map(Some(3))?;
121 m.serialize_entry("kind", self.0.kind)?;
122 m.serialize_entry("cost", &json!(self.0.cost))?;
123 m.serialize_entry("message", self.0.message.as_str())?;
124 m.end()
125 }
126}
127
128struct Fields<'a>(Vec<(&'static str, Field<'a>)>);
130
131impl Serialize for Fields<'_> {
132 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
133 let mut m = s.serialize_map(Some(self.0.len()))?;
134 for (k, v) in &self.0 {
135 m.serialize_entry(k, v)?;
136 }
137 m.end()
138 }
139}
140
141fn own(k: &'static str, v: Value) -> (&'static str, Field<'static>) {
143 (k, Field::Owned(v))
144}
145
146impl Simulation {
147 fn save_fields(&self) -> Vec<(&'static str, Field<'_>)> {
151 let mut m: Vec<(&'static str, Field<'_>)> = Vec::with_capacity(31);
152 m.push(own("version", json!(SAVE_VERSION)));
153 m.push(own("seed", json!(self.rng.seed())));
154 m.push(own("initialSeed", json!(self.rng.initial_seed)));
155 m.push(own("money", json!(self.money)));
156 m.push(own("star", json!(self.star)));
157 m.push(own("minutes", json!(self.clock.minutes)));
158 m.push(own("mode", json!(self.mode.as_str())));
159 m.push(own("modernCalendar", json!(self.modern_calendar.as_str())));
160 if !self.auto_bridge {
161 m.push(own("autoBridge", json!(false)));
162 }
163 if self.founder {
164 m.push(own("founder", json!(true)));
165 }
166 m.push(own("lastQuarterMoney", json!(self.last_quarter_money)));
167 m.push(("units", Field::Units(&self.tower.units)));
168 m.push(("transports", Field::Transports(&self.tower.transports)));
169 m.push(own("nextId", json!(self.tower.next_id)));
170 if let Some(n) = &self.tower.tower_name {
171 m.push(("towerName", Field::Text(n)));
172 }
173 if let Some(b) = self.tower.built_wedding_hall {
174 m.push(own("builtWeddingHall", json!(b)));
175 }
176 if let Some(b) = self.evaluated_tower {
177 m.push(own("evaluatedTower", json!(b)));
178 }
179 m.push(own("vipVisitDay", json!(self.vip_visit_day)));
180 m.push(own("vipFavorable", json!(self.vip_favorable)));
181 m.push(own("vipVisits", json!(self.vip_visits)));
182 m.push(own("lastVipNagDay", json!(self.last_vip_nag_day)));
183 m.push(own("treasuresFound", json!(self.treasures_found)));
184 if let Some(d) = self.extermination_due_day {
185 m.push(own("exterminationDueDay", json!(d)));
186 if let Some(ids) = &self.extermination_room_ids {
187 m.push(("exterminationRoomIds", Field::Ids(ids)));
188 }
189 }
190 m.push(("events", Field::Events(&self.events)));
191 m.push(("excavated", Field::Strings(&self.excavated)));
192 m.push(("blockbusters", Field::Floats(&self.blockbusters)));
193 m.push(("milestones", Field::Strings(&self.milestones)));
194 m.push(("ledger", Field::Ledger(&self.ledger)));
195 if let Some(v) = &self.view {
196 m.push(("view", Field::Borrowed(v)));
197 }
198 if !self.log.is_empty() {
199 let start = self.log.len().saturating_sub(LOG_SAVE_CAP);
200 m.push(("log", Field::Log(&self.log[start..])));
201 }
202 m
203 }
204
205 pub fn serialize(&self) -> Value {
221 let mut m = Map::new();
222 for (k, f) in self.save_fields() {
223 m.insert(k.into(), f.into_value());
224 }
225 Value::Object(m)
226 }
227
228 #[cfg_attr(not(feature = "wasm"), allow(dead_code))]
234 pub(crate) fn save_without_units(&self) -> (Value, impl Iterator<Item = Value> + '_) {
235 let mut m = Map::new();
236 for (k, f) in self.save_fields() {
237 if k != "units" {
238 m.insert(k.into(), f.into_value());
239 }
240 }
241 (
242 Value::Object(m),
243 self.tower.units.iter().map(Unit::serialize),
244 )
245 }
246
247 #[doc(hidden)]
248 pub fn save_text(&self) -> String {
253 serde_json::to_string(&Fields(self.save_fields())).expect("a save writes as JSON")
258 }
259
260 #[cfg(test)]
263 pub(crate) fn write_save(&self, buf: &mut Vec<u8>) {
264 serde_json::to_writer(buf, &Fields(self.save_fields())).expect("a save writes as JSON");
265 }
266}
267
268#[cfg(test)]
269#[path = "sim_save_tests.rs"]
270mod tests;