diff --git a/src/newtypes.rs b/src/newtypes.rs index 8b12c6b..19e2e59 100644 --- a/src/newtypes.rs +++ b/src/newtypes.rs @@ -1,3 +1,4 @@ +mod common; pub mod aabb; pub mod model; pub mod integer; diff --git a/src/newtypes/common.rs b/src/newtypes/common.rs new file mode 100644 index 0000000..0136b54 --- /dev/null +++ b/src/newtypes/common.rs @@ -0,0 +1,26 @@ +pub const fn flag(b:bool,mask:u8)->u8{ + (-(b as i8) as u8)&mask +} + +#[binrw::binrw] +#[brw(little,repr=u8)] +pub enum Boolio{ + True, + False +} +impl Into for Boolio{ + fn into(self)->bool{ + match self{ + Boolio::True=>true, + Boolio::False=>false, + } + } +} +impl From for Boolio{ + fn from(value:bool)->Self{ + match value{ + true=>Boolio::True, + false=>Boolio::False, + } + } +} diff --git a/src/newtypes/gameplay_attributes.rs b/src/newtypes/gameplay_attributes.rs index c8039d7..0dd3501 100644 --- a/src/newtypes/gameplay_attributes.rs +++ b/src/newtypes/gameplay_attributes.rs @@ -1,24 +1,22 @@ +use super::common::{flag,Boolio}; use super::integer::{Time,Planar64,Planar64Vec3}; #[binrw::binrw] #[brw(little)] pub struct ContactingLadder{ - pub sticky:Option<()>, + pub sticky:Boolio, } impl Into for ContactingLadder{ fn into(self)->strafesnet_common::gameplay_attributes::ContactingLadder{ strafesnet_common::gameplay_attributes::ContactingLadder{ - sticky:self.sticky.is_some(), + sticky:self.sticky.into(), } } } impl From for ContactingLadder{ fn from(value:strafesnet_common::gameplay_attributes::ContactingLadder)->Self{ Self{ - sticky:match value.sticky{ - true=>Some(()), - false=>None, - } + sticky:value.sticky.into(), } } } @@ -26,10 +24,15 @@ impl From for Contacti #[binrw::binrw] #[brw(little)] pub enum ContactingBehaviour{ + #[brw(magic=0u8)] Surf, + #[brw(magic=1u8)] Ladder(ContactingLadder), + #[brw(magic=2u8)] NoJump, + #[brw(magic=3u8)] Cling, + #[brw(magic=4u8)] Elastic(u32), } impl Into for ContactingBehaviour{ @@ -118,7 +121,9 @@ impl From for Accelerator{ #[binrw::binrw] #[brw(little)] pub enum Booster{ + #[brw(magic=0u8)] Velocity(Planar64Vec3), + #[brw(magic=1u8)] Energy{direction:Planar64Vec3,energy:Planar64}, } impl Into for Booster{ @@ -180,18 +185,24 @@ impl From for Trajecto #[binrw::binrw] #[brw(little)] pub enum SetTrajectory{ + #[brw(magic=0u8)] AirTime(Time), + #[brw(magic=1u8)] Height(Planar64), + #[brw(magic=2u8)] DotVelocity{direction:Planar64Vec3,dot:Planar64}, + #[brw(magic=3u8)] TargetPointTime{ target_point:Planar64Vec3, time:Time, }, + #[brw(magic=4u8)] TargetPointSpeed{ target_point:Planar64Vec3, speed:Planar64, trajectory_choice:TrajectoryChoice, }, + #[brw(magic=5u8)] Velocity(Planar64Vec3), } impl Into for SetTrajectory{ @@ -286,11 +297,22 @@ impl From for Wormhole{ #[binrw::binrw] #[brw(little)] pub struct GeneralAttributes{ + pub header:u8, + #[br(if(header&Self::BOOSTER!=0))] pub booster:Option, + #[br(if(header&Self::TRAJECTORY!=0))] pub trajectory:Option, + #[br(if(header&Self::WORMHOLE!=0))] pub wormhole:Option, + #[br(if(header&Self::ACCELERATOR!=0))] pub accelerator:Option, } +impl GeneralAttributes{ + const BOOSTER:u8=1<<0; + const TRAJECTORY:u8=1<<1; + const WORMHOLE:u8=1<<2; + const ACCELERATOR:u8=1<<3; +} impl Into for GeneralAttributes{ fn into(self)->strafesnet_common::gameplay_attributes::GeneralAttributes{ strafesnet_common::gameplay_attributes::GeneralAttributes{ @@ -303,7 +325,13 @@ impl Into for General } impl From for GeneralAttributes{ fn from(value:strafesnet_common::gameplay_attributes::GeneralAttributes)->Self{ + let header= + flag(value.booster.is_some(),GeneralAttributes::BOOSTER) + |flag(value.trajectory.is_some(),GeneralAttributes::TRAJECTORY) + |flag(value.wormhole.is_some(),GeneralAttributes::WORMHOLE) + |flag(value.accelerator.is_some(),GeneralAttributes::ACCELERATOR); Self{ + header, booster:value.booster.map(Into::into), trajectory:value.trajectory.map(Into::into), wormhole:value.wormhole.map(Into::into), @@ -315,8 +343,13 @@ impl From for General #[binrw::binrw] #[brw(little)] pub struct ContactingAttributes{ + pub header:u8, + #[br(if(header&Self::CONTACTING_BEHAVIOUR!=0))] pub contact_behaviour:Option, } +impl ContactingAttributes{ + const CONTACTING_BEHAVIOUR:u8=1<<0; +} impl Into for ContactingAttributes{ fn into(self)->strafesnet_common::gameplay_attributes::ContactingAttributes{ strafesnet_common::gameplay_attributes::ContactingAttributes{ @@ -327,6 +360,7 @@ impl Into for Cont impl From for ContactingAttributes{ fn from(value:strafesnet_common::gameplay_attributes::ContactingAttributes)->Self{ Self{ + header:flag(value.contact_behaviour.is_some(),ContactingAttributes::CONTACTING_BEHAVIOUR), contact_behaviour:value.contact_behaviour.map(Into::into), } } @@ -335,8 +369,13 @@ impl From for Cont #[binrw::binrw] #[brw(little)] pub struct IntersectingAttributes{ + pub header:u8, + #[br(if(header&Self::INTERSECTING_WATER!=0))] pub water:Option, } +impl IntersectingAttributes{ + const INTERSECTING_WATER:u8=1<<0; +} impl Into for IntersectingAttributes{ fn into(self)->strafesnet_common::gameplay_attributes::IntersectingAttributes{ strafesnet_common::gameplay_attributes::IntersectingAttributes{ @@ -347,6 +386,7 @@ impl Into for In impl From for IntersectingAttributes{ fn from(value:strafesnet_common::gameplay_attributes::IntersectingAttributes)->Self{ Self{ + header:flag(value.water.is_some(),IntersectingAttributes::INTERSECTING_WATER), water:value.water.map(Into::into), } } @@ -355,11 +395,14 @@ impl From for In #[binrw::binrw] #[brw(little)] pub enum CollisionAttributes{ + #[brw(magic=0u8)] Decoration, + #[brw(magic=1u8)] Contact{ contacting:ContactingAttributes, general:GeneralAttributes, }, + #[brw(magic=2u8)] Intersect{ intersecting:IntersectingAttributes, general:GeneralAttributes, diff --git a/src/newtypes/gameplay_modes.rs b/src/newtypes/gameplay_modes.rs index aa7848e..b789427 100644 --- a/src/newtypes/gameplay_modes.rs +++ b/src/newtypes/gameplay_modes.rs @@ -1,65 +1,60 @@ -#[binrw::binrw] -#[brw(little,repr=u8)] -pub enum StageElementBehaviour{ - SpawnAt,//must be standing on top to get effect. except cancollide false - Trigger, - Teleport, - Platform, - //Check(point) acts like a trigger if you haven't hit all the checkpoints on previous stages yet. - //Note that all stage elements act like this, this is just the isolated behaviour. - Check, - Checkpoint,//this is a combined behaviour for Ordered & Unordered in case a model is used multiple times or for both. -} -impl Into for StageElementBehaviour{ - fn into(self)->strafesnet_common::gameplay_modes::StageElementBehaviour{ - match self{ - StageElementBehaviour::SpawnAt=>strafesnet_common::gameplay_modes::StageElementBehaviour::SpawnAt, - StageElementBehaviour::Trigger=>strafesnet_common::gameplay_modes::StageElementBehaviour::Trigger, - StageElementBehaviour::Teleport=>strafesnet_common::gameplay_modes::StageElementBehaviour::Teleport, - StageElementBehaviour::Platform=>strafesnet_common::gameplay_modes::StageElementBehaviour::Platform, - StageElementBehaviour::Check=>strafesnet_common::gameplay_modes::StageElementBehaviour::Check, - StageElementBehaviour::Checkpoint=>strafesnet_common::gameplay_modes::StageElementBehaviour::Checkpoint, - } - } -} -impl From for StageElementBehaviour{ - fn from(value:strafesnet_common::gameplay_modes::StageElementBehaviour)->Self{ - match value{ - strafesnet_common::gameplay_modes::StageElementBehaviour::SpawnAt=>StageElementBehaviour::SpawnAt, - strafesnet_common::gameplay_modes::StageElementBehaviour::Trigger=>StageElementBehaviour::Trigger, - strafesnet_common::gameplay_modes::StageElementBehaviour::Teleport=>StageElementBehaviour::Teleport, - strafesnet_common::gameplay_modes::StageElementBehaviour::Platform=>StageElementBehaviour::Platform, - strafesnet_common::gameplay_modes::StageElementBehaviour::Check=>StageElementBehaviour::Check, - strafesnet_common::gameplay_modes::StageElementBehaviour::Checkpoint=>StageElementBehaviour::Checkpoint, - } - } -} +use super::common::flag; #[binrw::binrw] #[brw(little)] pub struct StageElement{ - pub stage_id:u32,//which stage spawn to send to - pub behaviour:StageElementBehaviour, + pub header:u8, + pub stage_id:u32, + #[br(if(header&Self::JUMP_LIMIT!=0))] pub jump_limit:Option, - pub force:Option<()>,//allow setting to lower spawn id i.e. 7->3 +} +impl StageElement{ + const BEHAVIOUR:u8=0b00111; + const JUMP_LIMIT:u8=1<<3; + const FORCE:u8=1<<4; + const fn behaviour(&self)->Option{ + match self.header&Self::BEHAVIOUR{ + 0=>Some(strafesnet_common::gameplay_modes::StageElementBehaviour::SpawnAt), + 1=>Some(strafesnet_common::gameplay_modes::StageElementBehaviour::Trigger), + 2=>Some(strafesnet_common::gameplay_modes::StageElementBehaviour::Teleport), + 3=>Some(strafesnet_common::gameplay_modes::StageElementBehaviour::Platform), + 4=>Some(strafesnet_common::gameplay_modes::StageElementBehaviour::Check), + 5=>Some(strafesnet_common::gameplay_modes::StageElementBehaviour::Checkpoint), + _=>None, + } + } + const fn force(&self)->bool{ + self.header&Self::FORCE!=0 + } } impl Into for StageElement{ fn into(self)->strafesnet_common::gameplay_modes::StageElement{ strafesnet_common::gameplay_modes::StageElement::new( strafesnet_common::gameplay_modes::StageId::new(self.stage_id), - self.force.is_some(), - self.behaviour.into(), + self.force(), + self.behaviour().unwrap(), self.jump_limit, ) } } impl From for StageElement{ fn from(value:strafesnet_common::gameplay_modes::StageElement)->Self{ + let behaviour=match value.behaviour(){ + strafesnet_common::gameplay_modes::StageElementBehaviour::SpawnAt=>0, + strafesnet_common::gameplay_modes::StageElementBehaviour::Trigger=>1, + strafesnet_common::gameplay_modes::StageElementBehaviour::Teleport=>2, + strafesnet_common::gameplay_modes::StageElementBehaviour::Platform=>3, + strafesnet_common::gameplay_modes::StageElementBehaviour::Check=>4, + strafesnet_common::gameplay_modes::StageElementBehaviour::Checkpoint=>5, + }; + let header= + behaviour + |flag(value.jump_limit().is_some(),StageElement::JUMP_LIMIT) + |flag(value.force(),StageElement::FORCE); Self{ + header, stage_id:value.stage_id().get(), - behaviour:value.behaviour().into(), jump_limit:value.jump_limit(), - force:match value.force(){true=>Some(()),false=>None}, } } } diff --git a/src/newtypes/gameplay_style.rs b/src/newtypes/gameplay_style.rs index 1983a22..f7049da 100644 --- a/src/newtypes/gameplay_style.rs +++ b/src/newtypes/gameplay_style.rs @@ -1,3 +1,4 @@ +use super::common::flag; use super::integer::{Time,Ratio64,Planar64,Planar64Vec3}; pub type Controls=u32; @@ -5,19 +6,34 @@ pub type Controls=u32; #[binrw::binrw] #[brw(little)] pub struct StyleModifiers{ + pub header:u8, pub controls_mask:Controls, pub controls_mask_state:Controls, + #[br(if(header&Self::STRAFE!=0))] pub strafe:Option, + #[br(if(header&Self::ROCKET!=0))] pub rocket:Option, + #[br(if(header&Self::JUMP!=0))] pub jump:Option, + #[br(if(header&Self::WALK!=0))] pub walk:Option, + #[br(if(header&Self::LADDER!=0))] pub ladder:Option, + #[br(if(header&Self::SWIM!=0))] pub swim:Option, pub gravity:Planar64Vec3, pub hitbox:Hitbox, pub camera_offset:Planar64Vec3, pub mass:Planar64, } +impl StyleModifiers{ + const STRAFE:u8=1<<0; + const ROCKET:u8=1<<1; + const JUMP:u8=1<<2; + const WALK:u8=1<<3; + 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{ @@ -39,7 +55,15 @@ impl Into for StyleModifiers{ } impl From for StyleModifiers{ fn from(value:strafesnet_common::gameplay_style::StyleModifiers)->Self{ + let header= + flag(value.strafe.is_some(),StyleModifiers::STRAFE) + |flag(value.rocket.is_some(),StyleModifiers::ROCKET) + |flag(value.jump.is_some(),StyleModifiers::JUMP) + |flag(value.walk.is_some(),StyleModifiers::WALK) + |flag(value.ladder.is_some(),StyleModifiers::LADDER) + |flag(value.swim.is_some(),StyleModifiers::SWIM); Self{ + header, controls_mask:value.controls_mask.bits(), controls_mask_state:value.controls_mask_state.bits(), strafe:value.strafe.map(Into::into), @@ -82,8 +106,6 @@ impl From for JumpCalculatio } } -#[binrw::binrw] -#[brw(little)] pub enum JumpImpulse{ FromTime(Time), FromHeight(Planar64), @@ -140,11 +162,16 @@ impl From for ControlsAct #[binrw::binrw] #[brw(little)] pub struct StrafeSettings{ + header:u8, enable:ControlsActivation, mv:Planar64, + #[br(if(header&Self::AIR_ACCEL_LIMIT!=0))] air_accel_limit:Option, tick_rate:Ratio64, } +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( @@ -158,7 +185,9 @@ impl Into for StrafeSettings{ impl From for StrafeSettings{ fn from(value:strafesnet_common::gameplay_style::StrafeSettings)->Self{ let (enable,mv,air_accel_limit,tick_rate)=value.into_inner(); + let header=flag(air_accel_limit.is_some(),StrafeSettings::AIR_ACCEL_LIMIT); Self{ + header, enable:enable.into(), mv:mv.get(), air_accel_limit:air_accel_limit.map(|a|a.get()), @@ -190,23 +219,58 @@ impl From for PropulsionS #[binrw::binrw] #[brw(little)] pub struct JumpSettings{ - impulse:JumpImpulse, - calculation:JumpCalculation, + header:u8, + impulse:i64, +} +impl JumpSettings{ + const IMPULSE:u8=0b0011; + const CALCULATION:u8=0b1100; + const fn impulse(&self)->Option{ + match self.header&Self::IMPULSE{ + 0=>Some(strafesnet_common::gameplay_style::JumpImpulse::FromTime(strafesnet_common::integer::Time::raw(self.impulse))), + 1=>Some(strafesnet_common::gameplay_style::JumpImpulse::FromHeight(strafesnet_common::integer::Planar64::raw(self.impulse))), + 2=>Some(strafesnet_common::gameplay_style::JumpImpulse::FromDeltaV(strafesnet_common::integer::Planar64::raw(self.impulse))), + 3=>Some(strafesnet_common::gameplay_style::JumpImpulse::FromEnergy(strafesnet_common::integer::Planar64::raw(self.impulse))), + _=>None, + } + } + const fn calculation(&self)->Option{ + match (self.header&Self::CALCULATION)>>2{ + 0=>Some(strafesnet_common::gameplay_style::JumpCalculation::Capped), + 1=>Some(strafesnet_common::gameplay_style::JumpCalculation::Energy), + 2=>Some(strafesnet_common::gameplay_style::JumpCalculation::Linear), + _=>None, + } + } } impl Into for JumpSettings{ fn into(self)->strafesnet_common::gameplay_style::JumpSettings{ strafesnet_common::gameplay_style::JumpSettings::new( - self.impulse.into(), - self.calculation.into(), + self.impulse().unwrap(), + self.calculation().unwrap(), ) } } impl From for JumpSettings{ fn from(value:strafesnet_common::gameplay_style::JumpSettings)->Self{ - let (impulse,calculation)=value.into_inner(); + let (impulse_enum,calculation)=value.into_inner(); + let (impulse,impulse_header)=match impulse_enum{ + strafesnet_common::gameplay_style::JumpImpulse::FromTime(impulse)=>(impulse.get(),0), + strafesnet_common::gameplay_style::JumpImpulse::FromHeight(impulse)=>(impulse.get(),1), + strafesnet_common::gameplay_style::JumpImpulse::FromDeltaV(impulse)=>(impulse.get(),2), + strafesnet_common::gameplay_style::JumpImpulse::FromEnergy(impulse)=>(impulse.get(),3), + }; + let calculation_header=match calculation{ + strafesnet_common::gameplay_style::JumpCalculation::Capped=>0, + strafesnet_common::gameplay_style::JumpCalculation::Energy=>1, + strafesnet_common::gameplay_style::JumpCalculation::Linear=>2, + }; + let header= + impulse_header + |(calculation_header<<2); Self{ - impulse:impulse.into(), - calculation:calculation.into(), + header, + impulse, } } } diff --git a/src/newtypes/model.rs b/src/newtypes/model.rs index 4d42aa9..6b874d0 100644 --- a/src/newtypes/model.rs +++ b/src/newtypes/model.rs @@ -1,3 +1,4 @@ +use super::common::flag; use strafesnet_common::model::PolygonIter; use super::integer::{Planar64Vec3,Planar64Affine3}; @@ -60,8 +61,13 @@ impl From for PolygonGroup{ #[binrw::binrw] #[brw(little)] pub struct RenderConfig{ + pub header:u8, + #[br(if(header&Self::TEXTURE!=0))] pub texture:Option, } +impl RenderConfig{ + const TEXTURE:u8=1<<0; +} impl Into for RenderConfig{ fn into(self)->strafesnet_common::model::RenderConfig{ strafesnet_common::model::RenderConfig{ @@ -71,7 +77,9 @@ impl Into for RenderConfig{ } impl From for RenderConfig{ fn from(value:strafesnet_common::model::RenderConfig)->Self{ + let header=flag(value.texture.is_some(),RenderConfig::TEXTURE); Self{ + header, texture:value.texture.map(|texture_id|texture_id.get()), } }