1
0
Fork 0
roguelike-game/src/saveload_system.rs

332 lines
9.0 KiB
Rust
Raw Permalink Normal View History

2022-02-01 15:41:08 -05:00
//! Serializes / Deserializes game data for saving and loading
use std::fs::{self, File};
2021-12-10 20:16:48 -05:00
use std::path::Path;
use ::bracket_lib::prelude::*;
2021-12-24 10:38:44 -05:00
use ::specs::error::NoError;
use ::specs::prelude::*;
use ::specs::saveload::{
2021-11-08 13:58:40 -05:00
DeserializeComponents, MarkedBuilder, SerializeComponents, SimpleMarker, SimpleMarkerAllocator,
};
2021-12-10 20:16:48 -05:00
use crate::components::*;
use crate::map::{Map, MasterDungeonMap};
use crate::spatial;
2021-11-08 13:58:40 -05:00
macro_rules! serialize_individually {
($ecs:expr, $ser:expr, $data:expr, $( $type:ty),*,) => {
2021-11-08 13:58:40 -05:00
$(
SerializeComponents::<NoError, SimpleMarker<SerializeMe>>::serialize(
&( $ecs.read_storage::<$type>(), ),
&$data.0,
&$data.1,
&mut $ser,
)
.unwrap();
2021-11-08 13:58:40 -05:00
)*
};
}
2021-11-09 10:49:39 -05:00
#[cfg(target_arch = "wasm32")]
pub fn save_game(_ecs: &mut World) {}
2022-02-01 15:41:08 -05:00
/// Saves the game data to a file
2021-11-09 10:49:39 -05:00
#[cfg(not(target_arch = "wasm32"))]
2021-11-08 13:58:40 -05:00
pub fn save_game(ecs: &mut World) {
// Create helper
2021-12-24 10:38:44 -05:00
let mapcopy = ecs.get_mut::<Map>().unwrap().clone();
let dungeon_master = ecs.get_mut::<MasterDungeonMap>().unwrap().clone();
2021-11-08 13:58:40 -05:00
let savehelper = ecs
.create_entity()
.with(SerializationHelper { map: mapcopy })
.marked::<SimpleMarker<SerializeMe>>()
.build();
let savehelper2 = ecs
.create_entity()
.with(DMSerializationHelper {
map: dungeon_master,
log: crate::gamelog::clone_log(),
events: crate::gamelog::clone_events(),
})
.marked::<SimpleMarker<SerializeMe>>()
.build();
2021-11-08 13:58:40 -05:00
// Actually serialize
{
let data = (
ecs.entities(),
ecs.read_storage::<SimpleMarker<SerializeMe>>(),
);
let writer = File::create("./savegame.json").unwrap();
2021-12-24 10:38:44 -05:00
let mut serializer = ::serde_json::Serializer::new(writer);
2021-11-08 13:58:40 -05:00
serialize_individually!(
ecs,
serializer,
data,
2022-01-28 13:47:16 -05:00
AlwaysTargetsSelf,
ApplyMove,
ApplyTeleport,
2021-11-08 13:58:40 -05:00
AreaOfEffect,
AttributeBonus,
Attributes,
BlocksTile,
BlocksVisibility,
Chasing,
2021-11-08 13:58:40 -05:00
Confusion,
Consumable,
2022-01-21 11:18:53 -05:00
CursedItem,
2022-01-25 13:45:44 -05:00
DamageOverTime,
DMSerializationHelper,
Door,
Duration,
EntityMoved,
EntryTrigger,
EquipmentChanged,
2021-11-15 11:32:09 -05:00
Equippable,
Equipped,
2022-01-11 14:16:23 -05:00
Faction,
Hidden,
HungerClock,
IdentifiedItem,
InBackpack,
InflictsDamage,
2022-01-11 09:28:45 -05:00
Initiative,
Item,
2022-01-25 09:58:30 -05:00
KnownSpells,
2022-01-10 10:21:19 -05:00
LightSource,
LootTable,
2022-01-19 09:38:41 -05:00
MagicItem,
MagicMapper,
2022-01-11 14:16:23 -05:00
MoveMode,
2022-01-11 09:33:21 -05:00
MyTurn,
Name,
NaturalAttackDefense,
ObfuscatedName,
2022-01-28 13:47:16 -05:00
OnDeath,
OtherLevelPosition,
2021-11-17 16:23:01 -05:00
ParticleLifetime,
Player,
Pools,
Position,
ProvidesFood,
ProvidesHealing,
ProvidesIdentification,
2022-01-25 11:42:02 -05:00
ProvidesMana,
ProvidesRemoveCurse,
2022-01-03 10:49:12 -05:00
Quips,
Ranged,
Renderable,
SerializationHelper,
SingleActivation,
2022-01-03 15:24:38 -05:00
Skills,
2022-01-25 13:45:44 -05:00
Slow,
SpawnParticleBurst,
SpawnParticleLine,
2022-01-25 15:04:00 -05:00
SpecialAbilities,
2022-01-25 09:58:30 -05:00
SpellTemplate,
StatusEffect,
Target,
2022-01-25 13:39:43 -05:00
TeachesSpell,
TeleportTo,
2022-01-28 11:48:25 -05:00
TileSize,
TownPortal,
2022-01-13 11:29:20 -05:00
Vendor,
Viewshed,
2022-01-11 14:16:23 -05:00
WantsToApproach,
2022-01-25 09:58:30 -05:00
WantsToCastSpell,
WantsToDropItem,
2022-01-11 14:16:23 -05:00
WantsToFlee,
WantsToMelee,
WantsToPickupItem,
WantsToRemoveItem,
2022-01-31 11:25:36 -05:00
WantsToShoot,
WantsToUseItem,
Weapon,
Wearable,
2021-11-08 13:58:40 -05:00
);
}
// Clean up
ecs.delete_entity(savehelper)
.expect("Failed to clean up savehelper component");
ecs.delete_entity(savehelper2)
.expect("Failed to clean up savehelper2 component");
2021-11-08 13:58:40 -05:00
}
2022-02-01 15:41:08 -05:00
/// Does the save game exist?
2021-11-08 13:58:40 -05:00
pub fn does_save_exist() -> bool {
Path::new("./savegame.json").exists()
}
2021-11-09 10:29:23 -05:00
macro_rules! deserialize_individually {
($ecs:expr, $de:expr, $data:expr, $( $type:ty),*,) => {
$(
DeserializeComponents::<NoError, _>::deserialize(
&mut ( &mut $ecs.write_storage::<$type>(), ),
&$data.0, // entities
&mut $data.1, // marker
&mut $data.2, // allocater
&mut $de,
)
.unwrap();
)*
};
}
2022-02-01 15:41:08 -05:00
/// Loads the game data from a file
2021-11-09 10:29:23 -05:00
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("Failed to delete entity");
}
}
let data = fs::read_to_string("./savegame.json").unwrap();
2021-12-24 10:38:44 -05:00
let mut de = ::serde_json::Deserializer::from_str(&data);
2021-11-09 10:29:23 -05:00
{
let mut d = (
&mut ecs.entities(),
&mut ecs.write_storage::<SimpleMarker<SerializeMe>>(),
&mut ecs.write_resource::<SimpleMarkerAllocator<SerializeMe>>(),
);
deserialize_individually!(
ecs,
de,
d,
2022-01-28 13:47:16 -05:00
AlwaysTargetsSelf,
ApplyMove,
ApplyTeleport,
2021-11-09 10:29:23 -05:00
AreaOfEffect,
AttributeBonus,
Attributes,
BlocksTile,
BlocksVisibility,
Chasing,
2021-11-09 10:29:23 -05:00
Confusion,
Consumable,
2022-01-21 11:18:53 -05:00
CursedItem,
2022-01-25 13:45:44 -05:00
DamageOverTime,
DMSerializationHelper,
Door,
Duration,
EntityMoved,
EntryTrigger,
EquipmentChanged,
2021-11-15 11:32:09 -05:00
Equippable,
Equipped,
2022-01-11 14:16:23 -05:00
Faction,
Hidden,
HungerClock,
IdentifiedItem,
InBackpack,
InflictsDamage,
2022-01-11 09:28:45 -05:00
Initiative,
Item,
2022-01-25 09:58:30 -05:00
KnownSpells,
2022-01-10 10:21:19 -05:00
LightSource,
LootTable,
2022-01-19 09:38:41 -05:00
MagicItem,
MagicMapper,
2022-01-11 14:16:23 -05:00
MoveMode,
2022-01-11 09:33:21 -05:00
MyTurn,
Name,
NaturalAttackDefense,
ObfuscatedName,
2022-01-28 13:47:16 -05:00
OnDeath,
OtherLevelPosition,
2021-11-17 16:23:01 -05:00
ParticleLifetime,
Player,
Pools,
Position,
ProvidesFood,
ProvidesHealing,
ProvidesIdentification,
2022-01-25 11:42:02 -05:00
ProvidesMana,
ProvidesRemoveCurse,
2022-01-03 10:49:12 -05:00
Quips,
Ranged,
Renderable,
SerializationHelper,
SingleActivation,
2022-01-03 15:24:38 -05:00
Skills,
Slow,
SpawnParticleBurst,
SpawnParticleLine,
2022-01-25 15:04:00 -05:00
SpecialAbilities,
2022-01-25 09:58:30 -05:00
SpellTemplate,
StatusEffect,
Target,
2022-01-25 13:39:43 -05:00
TeachesSpell,
TeleportTo,
2022-01-28 11:48:25 -05:00
TileSize,
TownPortal,
2022-01-13 11:29:20 -05:00
Vendor,
Viewshed,
2022-01-11 14:16:23 -05:00
WantsToApproach,
2022-01-25 09:58:30 -05:00
WantsToCastSpell,
WantsToDropItem,
2022-01-11 14:16:23 -05:00
WantsToFlee,
WantsToMelee,
WantsToPickupItem,
WantsToRemoveItem,
2022-01-31 11:25:36 -05:00
WantsToShoot,
WantsToUseItem,
Weapon,
Wearable,
2021-11-09 10:29:23 -05:00
);
}
let mut deleteme: Option<Entity> = None;
let mut deleteme2: Option<Entity> = None;
2021-11-09 10:29:23 -05:00
{
let entities = ecs.entities();
let helper = ecs.read_storage::<SerializationHelper>();
let helper2 = ecs.read_storage::<DMSerializationHelper>();
2021-11-09 10:29:23 -05:00
let player = ecs.read_storage::<Player>();
let position = ecs.read_storage::<Position>();
for (e, h) in (&entities, &helper).join() {
2021-12-24 10:38:44 -05:00
let mut worldmap = ecs.write_resource::<Map>();
2021-11-09 10:29:23 -05:00
*worldmap = h.map.clone();
spatial::set_size((worldmap.height * worldmap.width) as usize);
2021-11-09 10:29:23 -05:00
deleteme = Some(e);
}
for (e, h) in (&entities, &helper2).join() {
let mut dungeon_master = ecs.write_resource::<MasterDungeonMap>();
*dungeon_master = h.map.clone();
deleteme2 = Some(e);
crate::gamelog::restore_log(&mut h.log.clone());
crate::gamelog::load_events(h.events.clone());
}
2021-11-09 10:29:23 -05:00
for (e, _p, pos) in (&entities, &player, &position).join() {
2021-12-24 10:38:44 -05:00
let mut ppos = ecs.write_resource::<Point>();
*ppos = Point::from(*pos);
2021-11-09 10:29:23 -05:00
let mut player_resource = ecs.write_resource::<Entity>();
*player_resource = e;
}
}
ecs.delete_entity(deleteme.unwrap())
.expect("Unable to delete helper entity");
ecs.delete_entity(deleteme2.unwrap())
.expect("Unable to delete helper2 entity");
2021-11-09 10:29:23 -05:00
}
2022-02-01 15:41:08 -05:00
/// Deletes the save file, if it exists
2021-11-09 10:29:23 -05:00
pub fn delete_save() {
if Path::new("./savegame.json").exists() {
std::fs::remove_file("./savegame.json").expect("Failed to delete save file.");
}
}