use specs::prelude::*; use specs::saveload::{SimpleMarker, SimpleMarkerAllocator, SerializeComponents, DeserializeComponents, MarkedBuilder}; use std::convert::Infallible; use super::components::*; use std::fs::File; use std::path::Path; use std::fs; macro_rules! serialize_individually { ($ecs:expr, $ser:expr, $data:expr, $( $type:ty),*) => { $( SerializeComponents::>::serialize( &( $ecs.read_storage::<$type>(), ), &$data.0, &$data.1, &mut $ser, ) .unwrap(); )* }; } macro_rules! deserialize_individually { ($ecs:expr, $de:expr, $data:expr, $( $type:ty),*) => { $( DeserializeComponents::::deserialize( &mut ( &mut $ecs.write_storage::<$type>(), ), &mut $data.0, // entities &mut $data.1, // marker &mut $data.2, // allocater &mut $de, ) .unwrap(); )* }; } pub fn does_save_exist() -> bool { Path::new("./savegame.json").exists() } #[cfg(not(target_arch = "wasm32"))] pub fn save_game(ecs : &mut World) { // Create helper let mapcopy = ecs.get_mut::().unwrap().clone(); let savehelper = ecs .create_entity() .with(SerializationHelper{ map : mapcopy }) .marked::>() .build(); // Actually serialize { let data = ( ecs.entities(), ecs.read_storage::>() ); let writer = File::create("./savegame.json").unwrap(); let mut serializer = serde_json::Serializer::new(writer); serialize_individually!(ecs, serializer, data, Position, Renderable, Player, Viewshed, Monster, Name, BlocksTile, CombatStats, SufferDamage, WantsToMelee, Item, Consumable, Ranged, InflictsDamage, AreaOfEffect, ProvidesHealing, InBackpack, WantsToPickupItem, WantsToUseItem, WantsToDropItem, SerializationHelper, Equippable, Equipped, MeleePowerBonus, DefenseBonus, WantsToRemoveItem, ParticleLifetime ); } // Clean up ecs.delete_entity(savehelper).expect("Crash on cleanup"); } #[cfg(target_arch = "wasm32")] pub fn save_game(_ecs : &mut World) { } pub fn delete_save() { if Path::new("./savegame.json").exists() { std::fs::remove_file("./savegame.json").expect("Unable to delete file"); } } pub fn load_game(ecs: &mut World) { { // Delete everything let mut to_delete = Vec::new(); for e in ecs.entities().join() { to_delete.push(e); } for del in to_delete.iter() { ecs.delete_entity(*del).expect("Deletion failed"); } } let data = fs::read_to_string("./savegame.json").unwrap(); let mut de = serde_json::Deserializer::from_str(&data); { let mut d = (&mut ecs.entities(), &mut ecs.write_storage::>(), &mut ecs.write_resource::>()); deserialize_individually!(ecs, de, d, Position, Renderable, Player, Viewshed, Monster, Name, BlocksTile, CombatStats, SufferDamage, WantsToMelee, Item, Consumable, Ranged, InflictsDamage, AreaOfEffect, ProvidesHealing, InBackpack, WantsToPickupItem, WantsToUseItem, WantsToDropItem, SerializationHelper, Equippable, Equipped, MeleePowerBonus, DefenseBonus, WantsToRemoveItem, ParticleLifetime ); } let mut deleteme : Option = None; { let entities = ecs.entities(); let helper = ecs.read_storage::(); let player = ecs.read_storage::(); let position = ecs.read_storage::(); for (e,h) in (&entities, &helper).join() { let mut worldmap = ecs.write_resource::(); *worldmap = h.map.clone(); worldmap.tile_content = vec![Vec::new(); super::map::MAPCOUNT]; deleteme = Some(e); } for (e,_p,pos) in (&entities, &player, &position).join() { let mut ppos = ecs.write_resource::(); *ppos = rltk::Point::new(pos.x, pos.y); let mut player_resource = ecs.write_resource::(); *player_resource = e; } } ecs.delete_entity(deleteme.unwrap()).expect("Unable to delete helper"); }