summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortroido <troido@protonmail.com>2020-04-08 18:03:44 +0200
committertroido <troido@protonmail.com>2020-04-08 18:03:44 +0200
commit15da8ce3af4e943939d6976ccfe5c46785638c7e (patch)
tree96d63166d3a0914cf84b635417049310b6741bfa /src
parent950e15f7f7bbf354399c0d710ff8fb195a941e92 (diff)
don't ignore loading errors anymore
Diffstat (limited to 'src')
-rw-r--r--src/persistence.rs82
-rw-r--r--src/world.rs33
2 files changed, 81 insertions, 34 deletions
diff --git a/src/persistence.rs b/src/persistence.rs
index b97f857..1174ceb 100644
--- a/src/persistence.rs
+++ b/src/persistence.rs
@@ -2,6 +2,7 @@
use std::path::{PathBuf, Path};
use std::fs;
use std::env;
+use std::io::ErrorKind;
use serde_json;
use serde_json::{Value, json};
use crate::{
@@ -10,19 +11,30 @@ use crate::{
savestate::SaveState,
playerstate::PlayerState,
Timestamp,
- Result,
- aerr
+ aerr,
+ errors::AnyError
};
+
+pub enum LoaderError {
+ MissingResource(AnyError),
+ InvalidResource(AnyError)
+}
+
+macro_rules! inv {
+ ($code:expr) => {($code).map_err(|err| LoaderError::InvalidResource(Box::new(err)))}
+}
+
+
pub trait PersistentStorage {
- fn load_room(&self, id: RoomId) -> Result<SaveState>;
- fn load_player(&self, id: PlayerId) -> Result<PlayerState>;
- fn load_world_meta(&self) -> Result<Timestamp>;
+ fn load_room(&self, id: RoomId) -> Result<SaveState, LoaderError>;
+ fn load_player(&self, id: PlayerId) -> Result<PlayerState, LoaderError>;
+ fn load_world_meta(&self) -> Result<Timestamp, LoaderError>;
- fn save_room(&self, id: RoomId, state: SaveState) -> Result<()>;
- fn save_player(&self, id: PlayerId, sate: PlayerState) -> Result<()>;
- fn save_world_meta(&self, time: Timestamp) -> Result<()>;
+ fn save_room(&self, id: RoomId, state: SaveState) -> Result<(), AnyError>;
+ fn save_player(&self, id: PlayerId, sate: PlayerState) -> Result<(), AnyError>;
+ fn save_world_meta(&self, time: Timestamp) -> Result<(), AnyError>;
}
@@ -56,43 +68,61 @@ impl FileStorage {
impl PersistentStorage for FileStorage {
- fn load_room(&self, id: RoomId) -> Result<SaveState> {
+ fn load_room(&self, id: RoomId) -> Result<SaveState, LoaderError> {
let mut path = self.directory.clone();
path.push("rooms");
let fname = id.to_string() + ".save.json";
path.push(fname);
- let text = fs::read_to_string(path)?;
- let json: Value = serde_json::from_str(&text)?;
- let state = SaveState::from_json(&json)?;
+ let text = fs::read_to_string(path).map_err(|err| {
+ if err.kind() == ErrorKind::NotFound {
+ LoaderError::MissingResource(Box::new(err))
+ } else {
+ LoaderError::InvalidResource(Box::new(err))
+ }
+ })?;
+ let json: Value = inv!(serde_json::from_str(&text))?;
+ let state = inv!(SaveState::from_json(&json))?;
Ok(state)
}
- fn load_player(&self, id: PlayerId) -> Result<PlayerState> {
+ fn load_player(&self, id: PlayerId) -> Result<PlayerState, LoaderError> {
let mut path = self.directory.clone();
path.push("players");
let fname = id.to_string() + ".save.json";
path.push(fname);
- let text = fs::read_to_string(path)?;
- let json: Value = serde_json::from_str(&text)?;
- let state = PlayerState::from_json(&json)?;
+ let text = fs::read_to_string(path).map_err(|err| {
+ if err.kind() == ErrorKind::NotFound {
+ LoaderError::MissingResource(Box::new(err))
+ } else {
+ LoaderError::InvalidResource(Box::new(err))
+ }
+ })?;
+ let json: Value = inv!(serde_json::from_str(&text))?;
+ let state = inv!(PlayerState::from_json(&json))?;
Ok(state)
}
- fn load_world_meta(&self) -> Result<Timestamp> {
+ fn load_world_meta(&self) -> Result<Timestamp, LoaderError> {
let mut path = self.directory.clone();
path.push("world.save.json");
- let text = fs::read_to_string(path)?;
- let json: Value = serde_json::from_str(&text)?;
+ let text = fs::read_to_string(path).map_err(|err| {
+ if err.kind() == ErrorKind::NotFound {
+ LoaderError::MissingResource(Box::new(err))
+ } else {
+ LoaderError::InvalidResource(Box::new(err))
+ }
+ })?;
+ let json: Value = inv!(serde_json::from_str(&text))?;
Ok(
Timestamp(
- json
- .get("steps").ok_or(aerr!("world data does not have steps"))?
- .as_i64().ok_or(aerr!("timestamp not an int"))?
+ inv!(inv!(json
+ .get("steps").ok_or(aerr!("world data does not have steps")))?
+ .as_i64().ok_or(aerr!("timestamp not an int")))?
)
)
}
- fn save_room(&self, id: RoomId, state: SaveState) -> Result<()> {
+ fn save_room(&self, id: RoomId, state: SaveState) -> Result<(), AnyError> {
let mut path = self.directory.clone();
path.push("rooms");
fs::create_dir_all(&path)?;
@@ -103,7 +133,7 @@ impl PersistentStorage for FileStorage {
Ok(())
}
- fn save_player(&self, id: PlayerId, state: PlayerState) -> Result<()> {
+ fn save_player(&self, id: PlayerId, state: PlayerState) -> Result<(), AnyError> {
let mut path = self.directory.clone();
path.push("players");
fs::create_dir_all(&path)?;
@@ -114,7 +144,7 @@ impl PersistentStorage for FileStorage {
Ok(())
}
- fn save_world_meta(&self, time: Timestamp) -> Result<()> {
+ fn save_world_meta(&self, time: Timestamp) -> Result<(), AnyError> {
let mut path = self.directory.clone();
fs::create_dir_all(&path)?;
path.push("world.save.json");
@@ -123,7 +153,7 @@ impl PersistentStorage for FileStorage {
}
}
-fn write_file_safe<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {
+fn write_file_safe<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<(), AnyError> {
let temppath = path
.as_ref()
.with_file_name(
diff --git a/src/world.rs b/src/world.rs
index d7b5555..9de51d7 100644
--- a/src/world.rs
+++ b/src/world.rs
@@ -9,7 +9,7 @@ use crate::{
room::Room,
room,
worldloader::WorldLoader,
- persistence::PersistentStorage,
+ persistence::{PersistentStorage, LoaderError},
playerstate::{PlayerState, RoomPos},
Encyclopedia,
controls::Control,
@@ -36,9 +36,18 @@ pub struct World<'a, 'b> {
impl <'a, 'b>World<'a, 'b> {
pub fn new(encyclopedia: Encyclopedia, template_loader: WorldLoader, persistence: Box<dyn PersistentStorage>, default_room: RoomId) -> Self {
+ let time = match persistence.load_world_meta() {
+ Ok(time) => {time}
+ Err(LoaderError::MissingResource(_)) => {
+ Timestamp(1000000)
+ }
+ Err(LoaderError::InvalidResource(err)) => {
+ panic!("Invalid world meta: {:?}", err)
+ }
+ };
World {
template_loader,
- time: persistence.load_world_meta().unwrap_or(Timestamp(1000000)),
+ time,
persistence,
default_room,
encyclopedia: encyclopedia,
@@ -69,8 +78,12 @@ impl <'a, 'b>World<'a, 'b> {
room.load_from_template(&template)?;
room
};
- if let Ok(state) = self.persistence.load_room(id.clone()){
- room.load_saved(&state);
+ match self.persistence.load_room(id.clone()){
+ Ok(state) => {
+ room.load_saved(&state);
+ }
+ Err(LoaderError::MissingResource(_)) => {}
+ Err(LoaderError::InvalidResource(err)) => {return Err(err);}
}
let last_time = self.time - 1;
if room.get_time() < last_time {
@@ -91,11 +104,15 @@ impl <'a, 'b>World<'a, 'b> {
}
pub fn add_player(&mut self, playerid: &PlayerId) -> Result<()> {
- let mut state = self.persistence
- .load_player(playerid.clone())
- .unwrap_or_else(|_err| // todo: what if player exists but can't be loaded for another reason?
+ let mut state = match self.persistence.load_player(playerid.clone()) {
+ Ok(state) => {state}
+ Err(LoaderError::MissingResource(_)) => {
PlayerState::new(playerid.clone())
- );
+ }
+ Err(LoaderError::InvalidResource(err)) => {
+ return Err(err)
+ }
+ };
state.id = playerid.clone();
if state.room == Some(purgatory::purgatory_id()){
state.respawn();