Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::fs;
use std::io::Write;
use std::ops::Deref;
use std::path::Path;
use bevy::math::Vec3;
use bevy::prelude::*;
use bevy::utils::HashMap;
use serde::{Deserialize, Serialize};
use crate::states::Player;
use crate::world::{
CurrentResidence, EncounterState, HungerState, TradingState, TravelPath, TravelTarget,
};
#[derive(Serialize, Deserialize, Debug, Resource)]
pub struct PersistenceState {
pub player_location: Vec3,
pub player_inventory: TradingState,
pub player_hunger: HungerState,
pub travel_path: Option<TravelPath>,
pub travel_target: Option<TravelTarget>,
pub previous_location: CurrentResidence,
pub encounter_state: EncounterState,
pub town_states: HashMap<String, (TradingState, HungerState)>,
}
#[derive(Clone, Debug)]
pub struct SaveFileEvent {
pub filename: Option<String>,
}
#[derive(Clone, Debug)]
pub struct LoadFileEvent {
pub filename: Option<String>,
}
pub fn sync_state_to_persistence(
mut commands: Commands,
mut state: Option<ResMut<PersistenceState>>,
player_query: Query<
(
&Transform,
Option<&TravelPath>,
Option<&TravelTarget>,
&CurrentResidence,
),
With<Player>,
>,
encounters: Res<EncounterState>,
hunger: Option<Res<HungerState>>,
trading: Option<Res<TradingState>>,
) {
match state {
Some(mut state) => {
if let Some((transform, maybe_travel, maybe_target, residence)) =
player_query.iter().next()
{
*state = PersistenceState {
player_location: transform.translation,
player_inventory: trading.map(|r| r.clone()).unwrap_or_default(),
player_hunger: hunger.map(|r| r.clone()).unwrap_or_default(),
travel_path: maybe_travel.cloned(),
travel_target: maybe_target.cloned(),
previous_location: residence.clone(),
encounter_state: encounters.clone(),
town_states: Default::default(),
};
}
}
None => {
if let Some((transform, maybe_travel, maybe_target, residence)) =
player_query.iter().next()
{
commands.insert_resource(PersistenceState {
player_location: transform.translation,
player_inventory: trading.map(|r| r.clone()).unwrap_or_default(),
player_hunger: hunger.map(|r| r.clone()).unwrap_or_default(),
travel_path: maybe_travel.cloned(),
travel_target: maybe_target.cloned(),
previous_location: residence.clone(),
encounter_state: encounters.clone(),
town_states: Default::default(),
})
}
}
}
}
pub fn handle_save_event(
mut events: ResMut<Events<SaveFileEvent>>,
state: Option<Res<PersistenceState>>,
) {
let root_data_dir = directories::ProjectDirs::from("com", "microhacks", "TraderTales")
.expect("Failed to get project dir");
if let Some(state) = state {
for event in events.drain() {
std::fs::create_dir_all(root_data_dir.data_dir()).expect("Failed to create data dir");
match fs::File::create(match event.filename {
Some(name) => root_data_dir.data_dir().join(name),
None => root_data_dir.data_dir().join("autosave.json"),
}) {
Ok(file) => {
serde_json::to_writer_pretty(file, &*state)
.inspect_err(|err| {
log::error!("{}", err);
})
.expect("Failed to create save data");
}
Err(e) => {
log::error!("{}", e);
}
}
}
}
}