diff options
| author | troido <troido@protonmail.com> | 2020-09-25 08:54:20 +0200 |
|---|---|---|
| committer | troido <troido@protonmail.com> | 2020-09-25 08:54:20 +0200 |
| commit | 09306cb76c6e1eabb4082a985a0a0fa335bda5c1 (patch) | |
| tree | e43abd096374a8e79186b519d80372112ab0ca74 /src/playerstate.rs | |
| parent | 9eb3a9da97e53cee14e585e027badb3783b8e25e (diff) | |
proper serialisation for playerstate; strum for old-style enums
Diffstat (limited to 'src/playerstate.rs')
| -rw-r--r-- | src/playerstate.rs | 164 |
1 files changed, 72 insertions, 92 deletions
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<RoomId>, 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::<Vec<(Value, bool)>>() - }, - "health": self.health - }) - } - - pub fn from_json(val: &Value) -> PResult<Self> { - 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::<PResult<Vec<(ItemId, bool)>>>()?; - 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<PreEntity> { @@ -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::<Result<Vec<InventoryEntry>>>()?, - 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<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> + 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<D>(deserializer: D) -> std::result::Result<Self, D::Error> + 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<ItemId> +} +#[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<RoomId>, + inventory: NewInventorySave, + health: i64 + }, + Old { + name: PlayerId, + roomname: Option<RoomId>, + inventory: OldInventorySave, + equipment: HashMap<Slot, ItemId>, + health: i64 + } +} |
