From 07cc6d8919193c38cc13b2567ede5a510938db18 Mon Sep 17 00:00:00 2001 From: troido Date: Fri, 21 Feb 2020 17:49:50 +0100 Subject: players can now go to different rooms --- content/maps/broom.json | 28 +++++++++++++++------------- content/maps/room.json | 6 ++++-- src/components.rs | 6 +++++- src/componentwrapper.rs | 9 +++++---- src/defaultencyclopedia.rs | 7 +++++++ src/main.rs | 15 ++++++++------- src/parameter.rs | 2 +- src/persistence.rs | 7 +++---- src/playerstate.rs | 22 ++++++++++++---------- src/resources.rs | 2 +- src/room.rs | 16 ++++++++++------ src/roomtemplate.rs | 10 ++++++---- src/savestate.rs | 11 ++++++----- src/systems/migrate.rs | 37 +++++++++++++++++++++++++++++++++++++ src/systems/mod.rs | 1 + src/template.rs | 17 +++++++++-------- src/world.rs | 22 ++++++++++++++-------- 17 files changed, 144 insertions(+), 74 deletions(-) create mode 100644 src/systems/migrate.rs diff --git a/content/maps/broom.json b/content/maps/broom.json index c72496d..f6044a6 100644 --- a/content/maps/broom.json +++ b/content/maps/broom.json @@ -1,24 +1,25 @@ { "width": 42, - "height": 22, - "spawn": [5, 15], + "height": 23, + "spawn": [5, 5], "field": [ + " %%% ", "XXXXX,.,XXXXXXXXXX~~~XXXXXXXXXXXXXXXXXXXXX", - "XT,,,,,,,,,,T,,,,,~~~,,,,,,,,,,,,,,,,,,,,X", - "X,,T,,,,,,,,,,T,,,~~~,,,,,,,,,,,,,,,,,,,,X", - "X,,,,,,,,,T,,,,,,,~~~,,,,,,,,,,,,,,,,,,,,X", - "X,,,,,,T,,,,T,,T,,~~~,,,,,,,,,,,,,,,,,,,,X", + "XT,,,,.,,,,,T,,,,,~~~,,,,,,,,,,,,,,,,,,,,X", + "X,,T,,.,,,,,,,T,,,~~~,,,,,,,,,,,,,,,,,,,,X", + "X,,,,,.,,,T,,,,,,,~~~,,,,,,,,,,,,,,,,,,,,X", + "X,,,,,,,,,,,T,,T,,~~~,,,,,,,,,,,,,,,,,,,,X", "X,,,,,.,,,,,,,,,,,~~~~,,,,,,,,,,,,,,,,,,,X", "X,,,T,.,T,,T,,,,,,~~~~~~~~~~~~~~~~~~~~~~~~", "X,,,,,.,,,,,T,,,,,~~~~~~~~~~~~~~~~~~~~~~~~", "X,,,T,.,,T,,,,,,,,~~~~~~~~~~~~~~~~~~~~~~~~", - "X,,,,,.,,,,,,T,,,,,,,,,,,,,,,,,,,,,,,,,,,X", - "X,,,T,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,X", - "X,T,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,X", - "X,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,X", - "X,T,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,X", - "X,,,T,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,X", - "X,,T,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,X", + "X,,,,,.,,,,,,T,,,,,,,,T,,,,T,,,,TT,,,,,,,X", + "X,,,T,.,,,T,,,,,,,T,,,,,,,,,,,,,,,,,,,T,,X", + "X,T,,,.,,,,,,,T,,,,,,,T,,,,,,T,,,,T,,,,,,X", + "X,,,,,,,,,,,T,,,,,,,T,,,,,,,,,,,,,,,,,T,,X", + "X,T,,,,,,T,,,,T,,T,,,,,,,,T,,,,,T,,,,,,,,X", + "X,,,T,,,,,,,,,,,,,,,,,,T,,,,,,T,,,,,,T,,,X", + "X,,T,,,,,,,,T,,,T,,,,,,,,,,,,,,,,,T,,,,,,X", "X,,,,,,T,,,,,,,,,,,,,,,T,T,,,,,,,,,,,,,,TX", "X,,,T,,,,,,,,,,T,,,,,,,,,,,,,,,,T,,,,,,,,X", "X,T,,,,T,,,T,,,,,,,T,,,,,,,T,,,,,,,,,,,T,X", @@ -38,6 +39,7 @@ "f": ["grass", "fence"], "X": "rock", "*": ["grass", "pebble"], + "%": {"type": "portal", "kwargs": {"destination": "room"}}, " ": [] } } diff --git a/content/maps/room.json b/content/maps/room.json index 4025639..94afbb8 100644 --- a/content/maps/room.json +++ b/content/maps/room.json @@ -1,6 +1,6 @@ { "width": 42, - "height": 22, + "height": 23, "spawn": [5, 15], "field": [ " XXXXXXXXXXXX~~~XXXXXXXXXXXXXXXXXXXXXX", @@ -24,7 +24,8 @@ "X*,,,,.,,,,,,,,,,,~~~'''''''''''f''''f'''X", "X,,,,,.,,,,,,,,,,,~~~'''''''''''ffffff'''X", "X,,,,,.,,,,,,,,,,,~~~''''''''''''''''''''X", - "XXXXX,.,XXXXXXXXXX~~~XXXXXXXXXXXXXXXXXXXXX" + "XXXXX,.,XXXXXXXXXX~~~XXXXXXXXXXXXXXXXXXXXX", + " %%% " ], "mapping": { "#": "wall", @@ -38,6 +39,7 @@ "f": ["grass", "fence"], "X": "rock", "*": ["grass", "pebble"], + "%": {"type": "portal", "kwargs": {"destination": "broom"}}, " ": [] } } diff --git a/src/components.rs b/src/components.rs index 126f20e..60b32d6 100644 --- a/src/components.rs +++ b/src/components.rs @@ -7,7 +7,7 @@ use specs::{ Component }; -use crate::{Pos, PlayerId}; +use crate::{Pos, PlayerId, RoomId}; use crate::controls::Control; use crate::template::Template; @@ -93,3 +93,7 @@ pub struct Serialise { pub template: Template } +#[derive(Component, Debug, Clone)] +pub struct RoomExit { + pub destination: RoomId +} diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index e5f9b9f..9e98332 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -2,14 +2,14 @@ use std::collections::HashMap; use specs::Builder; -use crate::PlayerId; -use crate::components::{Visible, Blocking, Player, Floor, Item, Inventory, Health, Serialise}; +use crate::{PlayerId, RoomId}; +use crate::components::{Visible, Blocking, Player, Floor, Item, Inventory, Health, Serialise, RoomExit}; use crate::parameter::{Parameter, ParameterType}; macro_rules! components { - ($($comp: ident ($($paramname: ident : $paramtype: ident),*) {$creation: expr});*) => { + ($($comp: ident ($($paramname: ident : $paramtype: ident),*) {$creation: expr});*;) => { #[derive(Clone)] pub enum ComponentWrapper{ @@ -96,7 +96,8 @@ components!( Item (ent: Template, name: String) {Item{ent, name}}; Inventory (capacity: Int) {Inventory{items: Vec::new(), capacity: capacity as usize}}; Health (health: Int, maxhealth: Int) {Health{health, maxhealth}}; - Serialise (template: Template) {Serialise{template}} + Serialise (template: Template) {Serialise{template}}; + RoomExit (destination: String) {RoomExit{destination: RoomId::from_str(&destination)}}; ); diff --git a/src/defaultencyclopedia.rs b/src/defaultencyclopedia.rs index bbc9d21..853fbfb 100644 --- a/src/defaultencyclopedia.rs +++ b/src/defaultencyclopedia.rs @@ -96,6 +96,13 @@ pub fn default_encyclopedia() -> Encyclopedia { ["Inventory", {"capacity": ["int", 3]}], ["Health", {"health": ["int", 9], "maxhealth": ["int", 10]}] ] + }, + "portal": { + "arguments": [["destination", "string", null]], + "components": [ + ["RoomExit", {"destination": ["arg", "destination"]}], + "Floor" + ] } })).unwrap() } diff --git a/src/main.rs b/src/main.rs index 310fd0e..a0afece 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,7 @@ mod world; pub use self::pos::Pos; pub use self::playerid::PlayerId; pub use self::roomid::RoomId; +pub use self::util::Result; use self::gameserver::GameServer; use self::server::unixserver::UnixServer; @@ -48,21 +49,21 @@ use crate::world::World; -fn main() { +fn main() -> Result<()>{ let mut servers: Vec> = Vec::new(); let addr = Path::new("\0rustifarm"); - let unixserver = UnixServer::new(&addr).expect("binding unix server failed"); + let unixserver = UnixServer::new(&addr)?; servers.push(Box::new(unixserver)); - let addr = "127.0.0.1:1234".parse().unwrap(); - let inetserver = TcpServer::new(&addr).expect("binding inet server failed"); + let addr = "127.0.0.1:1234".parse()?; + let inetserver = TcpServer::new(&addr)?; servers.push(Box::new(inetserver)); let mut gameserver = GameServer::new(servers); - let loader = WorldLoader::new(PathBuf::from_str(&(env!("CARGO_MANIFEST_DIR").to_owned() + "/content/maps/")).unwrap()); + let loader = WorldLoader::new(PathBuf::from_str(&(env!("CARGO_MANIFEST_DIR").to_owned() + "/content/maps/"))?); let storage = FileStorage::new(FileStorage::savedir().expect("couldn't find any save directory")); @@ -80,10 +81,10 @@ fn main() { let _ = world.control_player(player, control); } Action::Join(player) => { - world.add_player(&player).unwrap(); + world.add_player(&player)?; } Action::Leave(player) => { - world.remove_player(&player).unwrap(); + world.remove_player(&player)?; } } } diff --git a/src/parameter.rs b/src/parameter.rs index cca0681..e82915b 100644 --- a/src/parameter.rs +++ b/src/parameter.rs @@ -23,7 +23,7 @@ impl Parameter { ParameterType::String => Some(Self::String(val.as_str()?.to_string())), ParameterType::Int => Some(Self::Int(val.as_i64()?)), ParameterType::Float => Some(Self::Float(val.as_f64()?)), - ParameterType::Template => Some(Self::Template(Template::from_json(val)?)) + ParameterType::Template => Some(Self::Template(Template::from_json(val).ok()?)) } } diff --git a/src/persistence.rs b/src/persistence.rs index 07ff89b..aab4088 100644 --- a/src/persistence.rs +++ b/src/persistence.rs @@ -9,8 +9,7 @@ use crate::{ RoomId, savestate::SaveState, playerstate::PlayerState, - util::Result, - aerr + util::Result }; pub trait PersistentStorage { @@ -65,7 +64,7 @@ impl PersistentStorage for FileStorage { path.push(fname); let text = fs::read_to_string(path)?; let json: Value = serde_json::from_str(&text)?; - SaveState::from_json(&json).ok_or(aerr!("not a valid save state")) + SaveState::from_json(&json) } fn load_player(&self, id: PlayerId) -> Result { @@ -75,7 +74,7 @@ impl PersistentStorage for FileStorage { path.push(fname); let text = fs::read_to_string(path)?; let json: Value = serde_json::from_str(&text)?; - PlayerState::from_json(&json).ok_or(aerr!("not a valid save state")) + PlayerState::from_json(&json) } fn save_room(&self, id: RoomId, state: SaveState) -> Result<()> { diff --git a/src/playerstate.rs b/src/playerstate.rs index f179fcc..f167d36 100644 --- a/src/playerstate.rs +++ b/src/playerstate.rs @@ -6,7 +6,9 @@ use crate::{ componentwrapper::{ComponentWrapper, PreEntity}, PlayerId, RoomId, - components::{Visible, Player, Inventory, Health, Item} + components::{Visible, Player, Inventory, Health, Item}, + Result, + aerr }; #[derive(Debug, Clone)] @@ -63,22 +65,22 @@ impl PlayerState { }) } - pub fn from_json(val: &Value) -> Option { - let inventory = val.get("inventory")?; + pub fn from_json(val: &Value) -> Result { + let inventory = val.get("inventory").ok_or(aerr!("player json does not have inventory"))?; let mut items = vec![]; - for item in inventory.get("items")?.as_array()? { + for item in inventory.get("items").ok_or(aerr!("inventory does not have items"))?.as_array().ok_or(aerr!("inventory items not an array"))? { items.push(Template::from_json(item)?); } - Some(Self { - id: PlayerId{name: val.get("name")?.as_str()?.to_string()}, - room: match val.get("roomname")? { + Ok(Self { + id: PlayerId{name: val.get("name").ok_or(aerr!("player json does not have name"))?.as_str().ok_or(aerr!("player name not a string"))?.to_string()}, + room: match val.get("roomname").ok_or(aerr!("player json does not have room name"))? { Value::String(name) => Some(RoomId::from_str(name)), _ => None }, inventory: items, - health: val.get("health")?.as_i64()?, - inventory_capacity: inventory.get("capacity")?.as_i64()? as usize, - maximum_health: val.get("maxhealth")?.as_i64()? + health: val.get("health").ok_or(aerr!("player json does not have health"))?.as_i64().ok_or(aerr!("player health not a number"))?, + inventory_capacity: inventory.get("capacity").ok_or(aerr!("inventory does no have capacity"))?.as_i64().ok_or(aerr!("inventory capacity not a number"))? as usize, + maximum_health: val.get("maxhealth").ok_or(aerr!("player json does not have maxhealth"))?.as_i64().ok_or(aerr!("maxhealh not a number"))? }) } diff --git a/src/resources.rs b/src/resources.rs index e0ac197..6e4bffb 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -66,7 +66,7 @@ pub struct Players { } #[derive(Default)] -pub struct Emigrating { +pub struct Emigration { pub emigrants: Vec<(PlayerId, RoomId)> } diff --git a/src/room.rs b/src/room.rs index 44608c8..b4ae5e5 100644 --- a/src/room.rs +++ b/src/room.rs @@ -20,7 +20,7 @@ use super::resources::{ NewEntities, Spawn, Players, - Emigrating + Emigration }; use super::systems::{ moving::Move, @@ -29,7 +29,8 @@ use super::systems::{ view::View, remove::Remove, create::Create, - take::Take + take::Take, + migrate::Migrate }; use crate::components::{ Position, @@ -63,7 +64,7 @@ impl <'a, 'b>Room<'a, 'b> { world.insert(NewEntities::new(encyclopedia)); world.insert(Players::default()); world.insert(Spawn::default()); - world.insert(Emigrating::default()); + world.insert(Emigration::default()); world.register::(); let mut dispatcher = DispatcherBuilder::new() @@ -72,6 +73,7 @@ impl <'a, 'b>Room<'a, 'b> { .with(Take, "take", &["controlinput"]) .with(Move, "move", &["registernew", "controlinput"]) .with(View::default(), "view", &["move"]) + .with(Migrate, "migrate", &["view"]) .with(Create, "create", &["view", "controlinput"]) .with(Remove, "remove", &["view", "move"]) .build(); @@ -139,8 +141,10 @@ impl <'a, 'b>Room<'a, 'b> { pub fn remove_player(&mut self, id: &PlayerId) -> Result{ let ent = self.world.fetch_mut::().entities.remove(id).ok_or(aerr!("failed to remove player"))?; + let state = self.save_player_ent(ent).ok_or(aerr!("failed to find player to remove"))?; self.world.write_component::().insert(ent, Removed)?; - self.save_player_ent(ent).ok_or(aerr!("failed to find player to remove")) + self.world.write_component::().remove(ent); + Ok(state) } pub fn save(&self) -> SaveState { @@ -202,8 +206,8 @@ impl <'a, 'b>Room<'a, 'b> { } pub fn emigrate(&mut self) -> Vec<(PlayerId, RoomId)> { - let emigrants = self.world.remove::().expect("World does not have Emigrating resource").emigrants; - self.world.insert(Emigrating::default()); + let emigrants = self.world.remove::().expect("World does not have Emigrating resource").emigrants; + self.world.insert(Emigration::default()); emigrants } } diff --git a/src/roomtemplate.rs b/src/roomtemplate.rs index cb8ae6a..49dd7af 100644 --- a/src/roomtemplate.rs +++ b/src/roomtemplate.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use serde_json::Value; use crate::Pos; use crate::template::Template; +use crate::{Result, aerr}; pub struct RoomTemplate { pub size: (i64, i64), @@ -12,7 +13,7 @@ pub struct RoomTemplate { impl RoomTemplate { - pub fn from_json(jsonroom: &Value) -> Result{ + pub fn from_json(jsonroom: &Value) -> Result{ let size = ( jsonroom.get("width").ok_or("no with")?.as_i64().ok_or("with not a number")?, jsonroom.get("height").ok_or("no height")?.as_i64().ok_or("height not a number")? @@ -24,10 +25,10 @@ impl RoomTemplate { let mut templates: Vec