From 05c8db47507d3a2840b76d88f650673c34eb1132 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 29 Jul 2024 18:20:44 -0700 Subject: [PATCH] don't panic --- src/map.rs | 3 +- src/newtypes/gameplay_modes.rs | 47 +++++++++++----- src/newtypes/gameplay_style.rs | 97 ++++++++++++++++++++++++---------- src/newtypes/integer.rs | 18 +++++-- 4 files changed, 121 insertions(+), 44 deletions(-) diff --git a/src/map.rs b/src/map.rs index 55313f9..1eed566 100644 --- a/src/map.rs +++ b/src/map.rs @@ -12,6 +12,7 @@ use strafesnet_common::gameplay_modes; #[derive(Debug)] pub enum Error{ InvalidHeader(binrw::Error), + InvalidMode(newtypes::gameplay_modes::ModeError), InvalidBlockId(BlockId), InvalidMeshId(model::MeshId), InvalidModelId(model::ModelId), @@ -214,7 +215,7 @@ impl StreamableMap{ pub(crate) fn new(mut file:crate::file::File)->Result{ //assume the file seek is in the right place to start reading a map header let header:MapHeader=file.as_mut().read_le().map_err(Error::InvalidHeader)?; - let modes=header.modes.into_iter().map(Into::into).collect(); + let modes=header.modes.into_iter().map(TryInto::try_into).collect::>().map_err(Error::InvalidMode)?; let attributes=header.attributes.into_iter().map(Into::into).collect(); let render_configs=header.render_configs.into_iter().map(Into::into).collect(); let bvh=header.spacial_blocks.into_iter().map(|spacial_block| diff --git a/src/newtypes/gameplay_modes.rs b/src/newtypes/gameplay_modes.rs index b789427..bda60af 100644 --- a/src/newtypes/gameplay_modes.rs +++ b/src/newtypes/gameplay_modes.rs @@ -27,14 +27,25 @@ impl StageElement{ self.header&Self::FORCE!=0 } } -impl Into for StageElement{ - fn into(self)->strafesnet_common::gameplay_modes::StageElement{ - strafesnet_common::gameplay_modes::StageElement::new( +#[derive(Debug)] +pub enum StageElementError{ + InvalidBehaviour, +} +impl std::fmt::Display for StageElementError{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for StageElementError{} +impl TryInto for StageElement{ + type Error=StageElementError; + fn try_into(self)->Result{ + Ok(strafesnet_common::gameplay_modes::StageElement::new( strafesnet_common::gameplay_modes::StageId::new(self.stage_id), self.force(), - self.behaviour().unwrap(), + self.behaviour().ok_or(StageElementError::InvalidBehaviour)?, self.jump_limit, - ) + )) } } impl From for StageElement{ @@ -154,19 +165,31 @@ pub struct Mode{ #[br(count=header.elements)] pub elements:Vec<(u32,StageElement)>, } -impl Into for Mode{ - fn into(self)->strafesnet_common::gameplay_modes::Mode{ - strafesnet_common::gameplay_modes::Mode::new( - self.style.into(), +#[derive(Debug)] +pub enum ModeError{ + StyleModifier(super::gameplay_style::StyleModifierError), + StageElement(StageElementError), +} +impl std::fmt::Display for ModeError{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for ModeError{} +impl TryInto for Mode{ + type Error=ModeError; + fn try_into(self)->Result{ + Ok(strafesnet_common::gameplay_modes::Mode::new( + self.style.try_into().map_err(ModeError::StyleModifier)?, strafesnet_common::model::ModelId::new(self.start), self.zones.into_iter().map(|(model_id,zone)| (strafesnet_common::model::ModelId::new(model_id),zone.into()) ).collect(), self.stages.into_iter().map(Into::into).collect(), self.elements.into_iter().map(|(model_id,stage_element)| - (strafesnet_common::model::ModelId::new(model_id),stage_element.into()) - ).collect(), - ) + Ok((strafesnet_common::model::ModelId::new(model_id),stage_element.try_into()?)) + ).collect::>().map_err(ModeError::StageElement)?, + )) } } impl From for Mode{ diff --git a/src/newtypes/gameplay_style.rs b/src/newtypes/gameplay_style.rs index f7049da..bb7cecb 100644 --- a/src/newtypes/gameplay_style.rs +++ b/src/newtypes/gameplay_style.rs @@ -2,6 +2,16 @@ use super::common::flag; use super::integer::{Time,Ratio64,Planar64,Planar64Vec3}; pub type Controls=u32; +#[derive(Debug)] +pub enum ControlsError{ + UnknownBits, +} +impl std::fmt::Display for ControlsError{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for ControlsError{} #[binrw::binrw] #[brw(little)] @@ -34,15 +44,27 @@ impl StyleModifiers{ const LADDER:u8=1<<4; const SWIM:u8=1<<5; } -impl Into for StyleModifiers{ - fn into(self)->strafesnet_common::gameplay_style::StyleModifiers{ - strafesnet_common::gameplay_style::StyleModifiers{ - //TODO: fail gracefully in binrw instead of panicing here - controls_mask:strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_mask).unwrap(), - controls_mask_state:strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_mask_state).unwrap(), - strafe:self.strafe.map(Into::into), +#[derive(Debug)] +pub enum StyleModifierError{ + Controls(ControlsError), + JumpSettings(JumpSettingsError), + StrafeSettings(StrafeSettingsError), +} +impl std::fmt::Display for StyleModifierError{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for StyleModifierError{} +impl TryInto for StyleModifiers{ + type Error=StyleModifierError; + fn try_into(self)->Result{ + Ok(strafesnet_common::gameplay_style::StyleModifiers{ + controls_mask:strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_mask).ok_or(StyleModifierError::Controls(ControlsError::UnknownBits))?, + controls_mask_state:strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_mask_state).ok_or(StyleModifierError::Controls(ControlsError::UnknownBits))?, + strafe:self.strafe.map(TryInto::try_into).transpose().map_err(StyleModifierError::StrafeSettings)?, rocket:self.rocket.map(Into::into), - jump:self.jump.map(Into::into), + jump:self.jump.map(TryInto::try_into).transpose().map_err(StyleModifierError::JumpSettings)?, walk:self.walk.map(Into::into), ladder:self.ladder.map(Into::into), swim:self.swim.map(Into::into), @@ -50,7 +72,7 @@ impl Into for StyleModifiers{ hitbox:self.hitbox.into(), camera_offset:strafesnet_common::integer::Planar64Vec3::raw_array(self.camera_offset), mass:strafesnet_common::integer::Planar64::raw(self.mass), - } + }) } } impl From for StyleModifiers{ @@ -140,13 +162,14 @@ pub struct ControlsActivation{ controls_intersects:Controls, controls_contains:Controls, } -impl Into for ControlsActivation{ - fn into(self)->strafesnet_common::gameplay_style::ControlsActivation{ - strafesnet_common::gameplay_style::ControlsActivation::new( - strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_mask).unwrap(), - strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_intersects).unwrap(), - strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_contains).unwrap(), - ) +impl TryInto for ControlsActivation{ + type Error=ControlsError; + fn try_into(self)->Result{ + Ok(strafesnet_common::gameplay_style::ControlsActivation::new( + strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_mask).ok_or(ControlsError::UnknownBits)?, + strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_intersects).ok_or(ControlsError::UnknownBits)?, + strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_contains).ok_or(ControlsError::UnknownBits)?, + )) } } impl From for ControlsActivation{ @@ -172,14 +195,26 @@ pub struct StrafeSettings{ impl StrafeSettings{ const AIR_ACCEL_LIMIT:u8=1<<0; } -impl Into for StrafeSettings{ - fn into(self)->strafesnet_common::gameplay_style::StrafeSettings{ - strafesnet_common::gameplay_style::StrafeSettings::new( - self.enable.into(), +#[derive(Debug)] +pub enum StrafeSettingsError{ + Ratio(super::integer::RatioError), + Controls(ControlsError), +} +impl std::fmt::Display for StrafeSettingsError{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for StrafeSettingsError{} +impl TryInto for StrafeSettings{ + type Error=StrafeSettingsError; + fn try_into(self)->Result{ + Ok(strafesnet_common::gameplay_style::StrafeSettings::new( + self.enable.try_into().map_err(StrafeSettingsError::Controls)?, strafesnet_common::integer::Planar64::raw(self.mv), self.air_accel_limit.map(strafesnet_common::integer::Planar64::raw), - self.tick_rate.into(), - ) + self.tick_rate.try_into().map_err(StrafeSettingsError::Ratio)?, + )) } } impl From for StrafeSettings{ @@ -243,12 +278,18 @@ impl JumpSettings{ } } } -impl Into for JumpSettings{ - fn into(self)->strafesnet_common::gameplay_style::JumpSettings{ - strafesnet_common::gameplay_style::JumpSettings::new( - self.impulse().unwrap(), - self.calculation().unwrap(), - ) +#[derive(Debug)] +pub enum JumpSettingsError{ + InvalidImpulseDiscriminant, + InvalidCalculationDiscriminant, +} +impl TryInto for JumpSettings{ + type Error=JumpSettingsError; + fn try_into(self)->Result{ + Ok(strafesnet_common::gameplay_style::JumpSettings::new( + self.impulse().ok_or(JumpSettingsError::InvalidImpulseDiscriminant)?, + self.calculation().ok_or(JumpSettingsError::InvalidCalculationDiscriminant)?, + )) } } impl From for JumpSettings{ diff --git a/src/newtypes/integer.rs b/src/newtypes/integer.rs index f75ba70..0eb7711 100644 --- a/src/newtypes/integer.rs +++ b/src/newtypes/integer.rs @@ -6,9 +6,21 @@ pub struct Ratio64{ num:i64, den:u64, } -impl Into for Ratio64{ - fn into(self)->strafesnet_common::integer::Ratio64{ - strafesnet_common::integer::Ratio64::new(self.num,self.den).unwrap() +#[derive(Debug)] +pub enum RatioError{ + ZeroDenominator, +} +impl std::fmt::Display for RatioError{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for RatioError{} +impl TryInto for Ratio64{ + type Error=RatioError; + fn try_into(self)->Result{ + strafesnet_common::integer::Ratio64::new(self.num,self.den) + .ok_or(RatioError::ZeroDenominator) } } impl From for Ratio64{