src/saveload_system.rs
1	use specs::prelude::*;
2 use specs::saveload::{SimpleMarker, SimpleMarkerAllocator, SerializeComponents, DeserializeComponents, MarkedBuilder};
3 use std::convert::Infallible;
4 use super::components::*;
5 use std::fs::File;
6 use std::path::Path;
7 use std::fs;
8
9 macro_rules! serialize_individually {
10 ($ecs:expr, $ser:expr, $data:expr, $( $type:ty),*) => {
11 $(
12 SerializeComponents::<Infallible, SimpleMarker<SerializeMe>>::serialize(
13 &( $ecs.read_storage::<$type>(), ),
14 &$data.0,
15 &$data.1,
16 &mut $ser,
17 )
18 .unwrap();
19 )*
20 };
21 }
22
23 macro_rules! deserialize_individually {
24 ($ecs:expr, $de:expr, $data:expr, $( $type:ty),*) => {
25 $(
26 DeserializeComponents::<Infallible, _>::deserialize(
27 &mut ( &mut $ecs.write_storage::<$type>(), ),
28 &mut $data.0, // entities
29 &mut $data.1, // marker
30 &mut $data.2, // allocater
31 &mut $de,
32 )
33 .unwrap();
34 )*
35 };
36 }
37
38 pub fn does_save_exist() -> bool {
39 Path::new("./savegame.json").exists()
40 }
41
42 #[cfg(not(target_arch = "wasm32"))]
43 pub fn save_game(ecs : &mut World) {
44 // Create helper
45 let mapcopy = ecs.get_mut::<super::map::Map>().unwrap().clone();
46 let savehelper = ecs
47 .create_entity()
48 .with(SerializationHelper{ map : mapcopy })
49 .marked::<SimpleMarker<SerializeMe>>()
50 .build();
51
52 // Actually serialize
53 {
54 let data = ( ecs.entities(), ecs.read_storage::<SimpleMarker<SerializeMe>>() );
55
56 let writer = File::create("./savegame.json").unwrap();
57 let mut serializer = serde_json::Serializer::new(writer);
58 serialize_individually!(ecs, serializer, data, Position, Renderable, Player, Viewshed, Monster,
59 Name, BlocksTile, CombatStats, SufferDamage, WantsToMelee, Item, Consumable, Ranged, InflictsDamage,
60 AreaOfEffect, ProvidesHealing, InBackpack, WantsToPickupItem, WantsToUseItem,
61 WantsToDropItem, SerializationHelper, Equippable, Equipped, MeleePowerBonus, DefenseBonus, WantsToRemoveItem,
62 ParticleLifetime
63 );
64 }
65
66 // Clean up
67 ecs.delete_entity(savehelper).expect("Crash on cleanup");
68 }
69
70 #[cfg(target_arch = "wasm32")]
71 pub fn save_game(_ecs : &mut World) {
72 }
73
74 pub fn delete_save() {
75 if Path::new("./savegame.json").exists() {
76 std::fs::remove_file("./savegame.json").expect("Unable to delete file");
77 }
78 }
79
80 pub fn load_game(ecs: &mut World) {
81 {
82 // Delete everything
83 let mut to_delete = Vec::new();
84 for e in ecs.entities().join() {
85 to_delete.push(e);
86 }
87 for del in to_delete.iter() {
88 ecs.delete_entity(*del).expect("Deletion failed");
89 }
90 }
91
92 let data = fs::read_to_string("./savegame.json").unwrap();
93 let mut de = serde_json::Deserializer::from_str(&data);
94
95 {
96 let mut d = (&mut ecs.entities(), &mut ecs.write_storage::<SimpleMarker<SerializeMe>>(), &mut ecs.write_resource::<SimpleMarkerAllocator<SerializeMe>>());
97
98 deserialize_individually!(ecs, de, d, Position, Renderable, Player, Viewshed, Monster,
99 Name, BlocksTile, CombatStats, SufferDamage, WantsToMelee, Item, Consumable, Ranged, InflictsDamage,
100 AreaOfEffect, ProvidesHealing, InBackpack, WantsToPickupItem, WantsToUseItem,
101 WantsToDropItem, SerializationHelper, Equippable, Equipped, MeleePowerBonus, DefenseBonus, WantsToRemoveItem,
102 ParticleLifetime
103 );
104 }
105
106 let mut deleteme : Option<Entity> = None;
107 {
108 let entities = ecs.entities();
109 let helper = ecs.read_storage::<SerializationHelper>();
110 let player = ecs.read_storage::<Player>();
111 let position = ecs.read_storage::<Position>();
112 for (e,h) in (&entities, &helper).join() {
113 let mut worldmap = ecs.write_resource::<super::map::Map>();
114 *worldmap = h.map.clone();
115 worldmap.tile_content = vec![Vec::new(); super::map::MAPCOUNT];
116 deleteme = Some(e);
117 }
118 for (e,_p,pos) in (&entities, &player, &position).join() {
119 let mut ppos = ecs.write_resource::<rltk::Point>();
120 *ppos = rltk::Point::new(pos.x, pos.y);
121 let mut player_resource = ecs.write_resource::<Entity>();
122 *player_resource = e;
123 }
124 }
125 ecs.delete_entity(deleteme.unwrap()).expect("Unable to delete helper");
126 }