-
-
Save chamons/37e8c6f8753e63eaef08bef36686c2e2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use bevy_ecs::{ | |
archetype::{Archetype, ArchetypeId}, | |
prelude::*, | |
}; | |
use serde::{Deserialize, Serialize}; | |
use crate::core::{Age, Buildings, BuildingsTimer, Demand, Inventory, Passives, Player, Research, ResearchTimer, Skills, Stability, StoreOffer}; | |
use super::ChoosePlacementStoreItem; | |
#[derive(Debug, Serialize, Deserialize)] | |
struct SaveState { | |
stability: Stability, | |
demand: Demand, | |
age: Age, | |
buildings_timer: BuildingsTimer, | |
research_timer: ResearchTimer, | |
passives: Passives, | |
store_offer: StoreOffer, | |
placement_store_item: ChoosePlacementStoreItem, | |
entities: Vec<SaveEntity>, | |
} | |
#[derive(Debug, Serialize, Deserialize)] | |
struct SaveEntity { | |
entity: Entity, | |
inventory: Option<Inventory>, | |
player: bool, // Player has no state, so it serializes to null | |
skills: Option<Skills>, | |
buildings: Option<Buildings>, | |
research: Option<Research>, | |
} | |
impl SaveState { | |
pub fn create(world: &mut World) -> Self { | |
let stability = world.get_resource::<Stability>().unwrap().clone(); | |
let demand = world.get_resource::<Demand>().unwrap().clone(); | |
let age = world.get_resource::<Age>().unwrap().clone(); | |
let buildings_timer = world.get_resource::<BuildingsTimer>().unwrap().clone(); | |
let research_timer = world.get_resource::<ResearchTimer>().unwrap().clone(); | |
let passives = world.get_resource::<Passives>().unwrap().clone(); | |
let store_offer = world.get_resource::<StoreOffer>().unwrap().clone(); | |
let placement_store_item = world.get_resource::<ChoosePlacementStoreItem>().unwrap().clone(); | |
SaveState { | |
stability, | |
demand, | |
age, | |
buildings_timer, | |
research_timer, | |
passives, | |
store_offer, | |
placement_store_item, | |
entities: SaveState::snapshot_entities(world), | |
} | |
} | |
fn snapshot_entities(world: &World) -> Vec<SaveEntity> { | |
let archetypes = world.archetypes(); | |
let all_archetypes: Vec<&Archetype> = archetypes | |
.iter() | |
.filter(|archetype| match archetype.id() { | |
ArchetypeId::EMPTY | ArchetypeId::RESOURCE | ArchetypeId::INVALID => false, | |
_ => true, | |
}) | |
.collect(); | |
let mut entities = Vec::with_capacity(all_archetypes.len()); | |
for archetype in all_archetypes { | |
for entity in archetype.entities() { | |
entities.push(SaveEntity { | |
entity: *entity, | |
inventory: world.get::<Inventory>(*entity).cloned(), | |
player: world.get::<Player>(*entity).is_some(), | |
skills: world.get::<Skills>(*entity).cloned(), | |
buildings: world.get::<Buildings>(*entity).cloned(), | |
research: world.get::<Research>(*entity).cloned(), | |
}); | |
} | |
} | |
entities | |
} | |
} | |
pub fn save_game(world: &mut World) -> String { | |
let state = SaveState::create(world); | |
serde_json::to_string(&state).unwrap() | |
} | |
pub fn load_game(state: &str) -> World { | |
let state: SaveState = serde_json::from_str(state).unwrap(); | |
let mut world = World::new(); | |
world.insert_resource(state.age); | |
world.insert_resource(state.buildings_timer); | |
world.insert_resource(state.demand); | |
world.insert_resource(state.passives); | |
world.insert_resource(state.research_timer); | |
world.insert_resource(state.stability); | |
world.insert_resource(state.store_offer); | |
world.insert_resource(state.placement_store_item); | |
for entity in state.entities { | |
let mut e = world.spawn(); | |
if let Some(inventory) = entity.inventory { | |
e.insert(inventory); | |
} | |
if entity.player { | |
e.insert(Player {}); | |
} | |
if let Some(skills) = entity.skills { | |
e.insert(skills); | |
} | |
if let Some(buildings) = entity.buildings { | |
e.insert(buildings); | |
} | |
if let Some(research) = entity.research { | |
e.insert(research); | |
} | |
} | |
world | |
} | |
#[cfg(test)] | |
mod tests { | |
use crate::{ | |
core::{create_game_world, find_player, test_utils::test_root_dir, Data}, | |
ui::{GameState, ImageCache, ScreenCoordinates}, | |
}; | |
use super::*; | |
#[test] | |
fn save_load_smoke() { | |
let image_cache = ImageCache::empty(); | |
let data = Data::load_from_dir(&test_root_dir()).unwrap(); | |
let screen_coordinates = ScreenCoordinates::new(ggez::graphics::Rect::new(0.0, 0.0, 800.0, 600.0)); | |
let world = create_game_world(&data); | |
let mut world = GameState::instance_world(world, image_cache, data, screen_coordinates); | |
let save = save_game(&mut world); | |
let mut loaded_world = load_game(&save); | |
let _ = find_player(&mut loaded_world); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment