From 09306cb76c6e1eabb4082a985a0a0fa335bda5c1 Mon Sep 17 00:00:00 2001 From: troido Date: Fri, 25 Sep 2020 08:54:20 +0200 Subject: proper serialisation for playerstate; strum for old-style enums --- src/playerstate.rs | 164 +++++++++++++++++++++++------------------------------ 1 file changed, 72 insertions(+), 92 deletions(-) (limited to 'src/playerstate.rs') diff --git a/src/playerstate.rs b/src/playerstate.rs index f159567..658aeb2 100644 --- a/src/playerstate.rs +++ b/src/playerstate.rs @@ -1,5 +1,6 @@ -use serde_json::{Value, json}; +use std::collections::HashMap; +use serde::{Serialize, Deserialize, Serializer, Deserializer}; use crate::{ componentwrapper::{ComponentWrapper, PreEntity}, PlayerId, @@ -26,10 +27,13 @@ use crate::{ Sprite, Encyclopedia, Pos, - PResult, - perr }; +#[allow(non_upper_case_globals)] +const maximum_health: i64 = 50; +#[allow(non_upper_case_globals)] +const inventory_capacity: usize = 20; + #[derive(Debug, Clone)] #[allow(dead_code)] pub enum RoomPos { @@ -43,10 +47,8 @@ pub struct PlayerState { pub id: PlayerId, pub room: Option, pub pos: RoomPos, - pub inventory_capacity: usize, pub inventory: Vec<(ItemId, bool)>, - pub health: i64, - pub maximum_health: i64 + pub health: i64 } impl PlayerState { @@ -57,105 +59,24 @@ impl PlayerState { room: None, pos: RoomPos::Unknown, inventory: Vec::new(), - inventory_capacity: 10, - health: 25, - maximum_health: 50 + health: maximum_health/2, } } - pub fn create(id: PlayerId, room: RoomId, inventory: Vec<(ItemId, bool)>, inventory_capacity: usize, health: i64, maximum_health: i64) -> Self { + pub fn create(id: PlayerId, room: RoomId, inventory: Vec<(ItemId, bool)>, health: i64) -> Self { Self { id, room: Some(room), pos: RoomPos::Unknown, inventory, health, - inventory_capacity, - maximum_health } } - - pub fn to_json(&self) -> Value { - json!({ - "name": self.id, - "roomname": match &self.room { - Some(id) => json!(id.to_string()), - None => json!(null) - }, - "inventory": { - "items": self.inventory.iter().map(|(item, e)| (json!(item.0), *e)).collect::>() - }, - "health": self.health - }) - } - - pub fn from_json(val: &Value) -> PResult { - let inventory = val.get("inventory").ok_or(perr!("player json does not have inventory"))?; - let mut items = - inventory - .get("items") - .ok_or(perr!("inventory does not have items"))? - .as_array() - .ok_or(perr!("inventory items not an array"))? - .iter() - .map(|entry| { - if entry.is_array() { - let itemid = ItemId( - entry - .get(0) - .ok_or(perr!("item does not have name"))? - .as_str() - .ok_or(perr!("item name not a string"))? - .to_string() - ); - let is_equipped = - entry - .get(1) - .ok_or(perr!("item does not have equipped flag"))? - .as_bool() - .ok_or(perr!("item is_equipped not a bool"))?; - Ok((itemid, is_equipped)) - } else if entry.is_string() { - Ok((ItemId(entry.as_str().unwrap().to_string()), false)) - } else { - Err(perr!("item entry must be a string or array, not {:?}", entry)) - } - }) - .collect::>>()?; - if let Some(equipment) = val.get("equipment") { - for (slot, item) in equipment.as_object().ok_or(perr!("equipment not a json object: {:?}", equipment))?.iter() { - if item.is_null(){ - continue - } - let itemid = ItemId( - item - .as_str() - .ok_or(perr!("equipment item not a string: {:?}", item))? - .to_string() - ); - // validate the slot, but don't do anything with it - Slot::from_str(slot).ok_or(perr!("invalid slot: {:?}", slot))?; - items.push((itemid, true)) - } - } - Ok(Self { - id: PlayerId(val.get("name").ok_or(perr!("player json does not have name"))?.as_str().ok_or(perr!("player name not a string"))?.to_string()), - room: match val.get("roomname").ok_or(perr!("player json does not have room name"))? { - Value::String(name) => Some(RoomId(name.clone())), - _ => None - }, - pos: RoomPos::Unknown, - inventory: items, - health: val.get("health").ok_or(perr!("player json does not have health"))?.as_i64().ok_or(perr!("player health not a number"))?, - inventory_capacity: 12, - maximum_health: 50, - }) - } pub fn respawn(&mut self) { self.room = None; self.pos = RoomPos::Unknown; - self.health = self.maximum_health / 2; + self.health = maximum_health / 2; } pub fn construct(&self, encyclopedia: &Encyclopedia) -> Result { @@ -167,9 +88,9 @@ impl PlayerState { let item = encyclopedia.get_item(&itemid).ok_or(aerr!("failed to load item '{:?} in inventory of player {:?}", itemid, self))?; Ok(InventoryEntry{itemid: itemid.clone(), item, is_equipped: *is_equipped}) }).collect::>>()?, - capacity: self.inventory_capacity + capacity: inventory_capacity }), - ComponentWrapper::Health(Health{health: self.health, maxhealth: self.maximum_health}), + ComponentWrapper::Health(Health{health: self.health, maxhealth: maximum_health}), ComponentWrapper::Fighter(Fighter{attack: AttackType::Attack(5), cooldown: 8, range: 1}), ComponentWrapper::Healing(Healing{delay: 50, health: 1, next_heal: None}), ComponentWrapper::Movable(Movable{cooldown: 2}), @@ -180,3 +101,62 @@ impl PlayerState { ]) } } + +impl Serialize for PlayerState { + fn serialize(&self, serializer: S) -> std::result::Result + where S: Serializer { + PlayerStateSave::New{name: self.id.clone(), roomname: self.room.clone(), inventory: NewInventorySave{items: self.inventory.clone()}, health: self.health}.serialize(serializer) + } +} +impl<'de> Deserialize<'de> for PlayerState { + fn deserialize(deserializer: D) -> std::result::Result + where D: Deserializer<'de> { + Ok(match PlayerStateSave::deserialize(deserializer)? { + PlayerStateSave::New{name, roomname, inventory, health} => PlayerState{id: name, room: roomname, inventory: inventory.items, health, pos: RoomPos::Unknown}, + PlayerStateSave::Old{name, roomname, inventory, equipment, health} => { + PlayerState{ + id: name, + room: roomname, + inventory: { + let mut inv = Vec::new(); + for item in inventory.items { + inv.push((item, false)); + } + for (_slot, item) in equipment.into_iter() { + inv.push((item, true)); + } + inv + }, + health, + pos: RoomPos::Unknown + } + } + }) + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +struct OldInventorySave { + pub items: Vec +} +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +struct NewInventorySave { + pub items: Vec<(ItemId, bool)> +} +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +enum PlayerStateSave { + New { + name: PlayerId, + roomname: Option, + inventory: NewInventorySave, + health: i64 + }, + Old { + name: PlayerId, + roomname: Option, + inventory: OldInventorySave, + equipment: HashMap, + health: i64 + } +} -- cgit