diff --git a/src/lib.rs b/src/lib.rs index bac2c04..4f4f479 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,7 @@ use binrw::BinReaderExt; +mod newtypes; + pub mod file; pub mod map; pub mod bot; diff --git a/src/newtypes.rs b/src/newtypes.rs new file mode 100644 index 0000000..8b12c6b --- /dev/null +++ b/src/newtypes.rs @@ -0,0 +1,6 @@ +pub mod aabb; +pub mod model; +pub mod integer; +pub mod gameplay_modes; +pub mod gameplay_style; +pub mod gameplay_attributes; diff --git a/src/newtypes/aabb.rs b/src/newtypes/aabb.rs new file mode 100644 index 0000000..15d7954 --- /dev/null +++ b/src/newtypes/aabb.rs @@ -0,0 +1,15 @@ +use super::integer::Planar64Vec3; +#[binrw::binrw] +#[brw(little)] +pub struct Aabb{ + pub min:Planar64Vec3, + pub max:Planar64Vec3, +} +impl Into for Aabb{ + fn into(self)->strafesnet_common::aabb::Aabb{ + strafesnet_common::aabb::Aabb::new( + strafesnet_common::integer::Planar64Vec3::raw(self.min[0],self.min[1],self.min[2]), + strafesnet_common::integer::Planar64Vec3::raw(self.max[0],self.max[1],self.max[2]), + ) + } +} diff --git a/src/newtypes/gameplay_attributes.rs b/src/newtypes/gameplay_attributes.rs new file mode 100644 index 0000000..5102d41 --- /dev/null +++ b/src/newtypes/gameplay_attributes.rs @@ -0,0 +1,103 @@ +use super::integer::{Time,Planar64,Planar64Vec3}; + +#[binrw::binrw] +#[brw(little)] +pub struct ContactingLadder{ + pub sticky:Option<()>, +} + +#[binrw::binrw] +#[brw(little)] +pub enum ContactingBehaviour{ + Surf, + Ladder(ContactingLadder), + NoJump, + Cling, + Elastic(u32), +} + +#[binrw::binrw] +#[brw(little)] +pub struct IntersectingWater{ + pub viscosity:Planar64, + pub density:Planar64, + pub velocity:Planar64Vec3, +} + +#[binrw::binrw] +#[brw(little)] +pub struct Accelerator{ + pub acceleration:Planar64Vec3 +} + +#[binrw::binrw] +#[brw(little)] +pub enum Booster{ + Velocity(Planar64Vec3), + Energy{direction:Planar64Vec3,energy:Planar64}, +} + +#[binrw::binrw] +#[brw(little,repr=u8)] +pub enum TrajectoryChoice{ + HighArcLongDuration, + LowArcShortDuration, +} + +#[binrw::binrw] +#[brw(little)] +pub enum SetTrajectory{ + AirTime(Time), + Height(Planar64), + DotVelocity{direction:Planar64Vec3,dot:Planar64}, + TargetPointTime{ + target_point:Planar64Vec3, + time:Time, + }, + TargetPointSpeed{ + target_point:Planar64Vec3, + speed:Planar64, + trajectory_choice:TrajectoryChoice, + }, + Velocity(Planar64Vec3), +} + +#[binrw::binrw] +#[brw(little)] +pub struct Wormhole{ + pub destination_model:u32, +} + +#[binrw::binrw] +#[brw(little)] +pub struct GeneralAttributes{ + pub booster:Option, + pub trajectory:Option, + pub wormhole:Option, + pub accelerator:Option, +} + +#[binrw::binrw] +#[brw(little)] +pub struct ContactingAttributes{ + pub contact_behaviour:Option, +} + +#[binrw::binrw] +#[brw(little)] +pub struct IntersectingAttributes{ + pub water:Option, +} +#[binrw::binrw] +#[brw(little)] +pub enum CollisionAttributes{ + Decoration, + Contact{ + contacting:ContactingAttributes, + general:GeneralAttributes, + }, + Intersect{ + intersecting:IntersectingAttributes, + general:GeneralAttributes, + }, +} diff --git a/src/newtypes/gameplay_modes.rs b/src/newtypes/gameplay_modes.rs new file mode 100644 index 0000000..73c2eb4 --- /dev/null +++ b/src/newtypes/gameplay_modes.rs @@ -0,0 +1,126 @@ +#[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, + } + } +} + +#[binrw::binrw] +#[brw(little)] +pub struct StageElement{ + pub stage_id:u32,//which stage spawn to send to + pub behaviour:StageElementBehaviour, + pub jump_limit:Option, + pub force:Option<()>,//allow setting to lower spawn id i.e. 7->3 +} +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.jump_limit, + ) + } +} + +#[binrw::binrw] +#[brw(little)] +pub struct Stage{ + pub spawn:u32, + //open world support lol + pub ordered_checkpoints_count:u32, + pub unordered_checkpoints_count:u32, + //currently loaded checkpoint models + #[br(count=ordered_checkpoints_count)] + pub ordered_checkpoints:Vec<(u32,u32)>, + #[br(count=unordered_checkpoints_count)] + pub unordered_checkpoints:Vec, +} +impl Into for Stage{ + fn into(self)->strafesnet_common::gameplay_modes::Stage{ + strafesnet_common::gameplay_modes::Stage::new( + strafesnet_common::model::ModelId::new(self.spawn), + self.ordered_checkpoints_count, + self.unordered_checkpoints_count, + self.ordered_checkpoints.into_iter().map(|(checkpoint_id,model_id)|( + strafesnet_common::gameplay_modes::CheckpointId::new(checkpoint_id), + strafesnet_common::model::ModelId::new(model_id), + )).collect(), + self.unordered_checkpoints.into_iter() + .map(strafesnet_common::model::ModelId::new) + .collect(), + ) + } +} + +#[binrw::binrw] +#[brw(little,repr=u8)] +pub enum Zone{ + Start, + Finish, + Anticheat, +} +impl Into for Zone{ + fn into(self)->strafesnet_common::gameplay_modes::Zone{ + match self{ + Zone::Start=>strafesnet_common::gameplay_modes::Zone::Start, + Zone::Finish=>strafesnet_common::gameplay_modes::Zone::Finish, + Zone::Anticheat=>strafesnet_common::gameplay_modes::Zone::Anticheat, + } + } +} + +#[binrw::binrw] +#[brw(little)] +pub struct ModeHeader{ + pub zones:u32, + pub stages:u32, + pub elements:u32, +} +#[binrw::binrw] +#[brw(little)] +pub struct Mode{ + pub header:ModeHeader, + pub style:super::gameplay_style::StyleModifiers, + pub start:u32, + #[br(count=header.zones)] + pub zones:Vec<(u32,Zone)>, + #[br(count=header.stages)] + pub stages:Vec, + #[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(), + 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(), + ) + } +} diff --git a/src/newtypes/gameplay_style.rs b/src/newtypes/gameplay_style.rs new file mode 100644 index 0000000..fa211ae --- /dev/null +++ b/src/newtypes/gameplay_style.rs @@ -0,0 +1,218 @@ +use super::integer::{Time,Ratio64,Planar64,Planar64Vec3}; + +pub type Controls=u32; + +#[binrw::binrw] +#[brw(little)] +pub struct StyleModifiers{ + pub controls_mask:Controls, + pub controls_mask_state:Controls, + pub strafe:Option, + pub rocket:Option, + pub jump:Option, + pub walk:Option, + pub ladder:Option, + pub swim:Option, + pub gravity:Planar64Vec3, + pub hitbox:Hitbox, + pub camera_offset:Planar64Vec3, + pub mass:Planar64, +} +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), + rocket:self.rocket.map(Into::into), + jump:self.jump.map(Into::into), + walk:self.walk.map(Into::into), + ladder:self.ladder.map(Into::into), + swim:self.swim.map(Into::into), + gravity:strafesnet_common::integer::Planar64Vec3::raw(self.gravity[0],self.gravity[1],self.gravity[2]), + hitbox:self.hitbox.into(), + camera_offset:strafesnet_common::integer::Planar64Vec3::raw(self.camera_offset[0],self.camera_offset[1],self.camera_offset[2]), + mass:strafesnet_common::integer::Planar64::raw(self.mass), + } + } +} + +#[binrw::binrw] +#[brw(little,repr=u8)] +pub enum JumpCalculation{ + Capped, + Energy, + Linear, +} +impl Into for JumpCalculation{ + fn into(self)->strafesnet_common::gameplay_style::JumpCalculation{ + match self{ + JumpCalculation::Capped=>strafesnet_common::gameplay_style::JumpCalculation::Capped, + JumpCalculation::Energy=>strafesnet_common::gameplay_style::JumpCalculation::Energy, + JumpCalculation::Linear=>strafesnet_common::gameplay_style::JumpCalculation::Linear, + } + } +} + +#[binrw::binrw] +#[brw(little)] +pub enum JumpImpulse{ + FromTime(Time), + FromHeight(Planar64), + FromDeltaV(Planar64), + FromEnergy(Planar64), +} +impl Into for JumpImpulse{ + fn into(self)->strafesnet_common::gameplay_style::JumpImpulse{ + match self{ + JumpImpulse::FromTime(time)=>strafesnet_common::gameplay_style::JumpImpulse::FromTime(strafesnet_common::integer::Time::raw(time)), + JumpImpulse::FromHeight(height)=>strafesnet_common::gameplay_style::JumpImpulse::FromHeight(strafesnet_common::integer::Planar64::raw(height)), + JumpImpulse::FromDeltaV(deltav)=>strafesnet_common::gameplay_style::JumpImpulse::FromDeltaV(strafesnet_common::integer::Planar64::raw(deltav)), + JumpImpulse::FromEnergy(energy)=>strafesnet_common::gameplay_style::JumpImpulse::FromEnergy(strafesnet_common::integer::Planar64::raw(energy)), + } + } +} + +#[binrw::binrw] +#[brw(little)] +pub struct ControlsActivation{ + controls_mask:Controls, + 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(), + ) + } +} + +#[binrw::binrw] +#[brw(little)] +pub struct StrafeSettings{ + enable:ControlsActivation, + mv:Planar64, + air_accel_limit:Option, + tick_rate:Ratio64, +} +impl Into for StrafeSettings{ + fn into(self)->strafesnet_common::gameplay_style::StrafeSettings{ + strafesnet_common::gameplay_style::StrafeSettings::new( + self.enable.into(), + strafesnet_common::integer::Planar64::raw(self.mv), + self.air_accel_limit.map(strafesnet_common::integer::Planar64::raw), + self.tick_rate.into(), + ) + } +} + +#[binrw::binrw] +#[brw(little)] +pub struct PropulsionSettings{ + magnitude:Planar64, +} +impl Into for PropulsionSettings{ + fn into(self)->strafesnet_common::gameplay_style::PropulsionSettings{ + strafesnet_common::gameplay_style::PropulsionSettings::new( + strafesnet_common::integer::Planar64::raw(self.magnitude) + ) + } +} + +#[binrw::binrw] +#[brw(little)] +pub struct JumpSettings{ + impulse:JumpImpulse, + calculation:JumpCalculation, +} +impl Into for JumpSettings{ + fn into(self)->strafesnet_common::gameplay_style::JumpSettings{ + strafesnet_common::gameplay_style::JumpSettings::new( + self.impulse.into(), + self.calculation.into(), + ) + } +} + +#[binrw::binrw] +#[brw(little)] +pub struct AccelerateSettings{ + accel:Planar64, + topspeed:Planar64, +} +impl Into for AccelerateSettings{ + fn into(self)->strafesnet_common::gameplay_style::AccelerateSettings{ + strafesnet_common::gameplay_style::AccelerateSettings::new( + strafesnet_common::integer::Planar64::raw(self.accel), + strafesnet_common::integer::Planar64::raw(self.topspeed), + ) + } +} + +#[binrw::binrw] +#[brw(little)] +pub struct WalkSettings{ + accelerate:AccelerateSettings, + static_friction:Planar64, + kinetic_friction:Planar64, + surf_dot:Planar64, +} +impl Into for WalkSettings{ + fn into(self)->strafesnet_common::gameplay_style::WalkSettings{ + strafesnet_common::gameplay_style::WalkSettings::new( + self.accelerate.into(), + strafesnet_common::integer::Planar64::raw(self.static_friction), + strafesnet_common::integer::Planar64::raw(self.kinetic_friction), + strafesnet_common::integer::Planar64::raw(self.surf_dot), + ) + } +} + +#[binrw::binrw] +#[brw(little)] +pub struct LadderSettings{ + accelerate:AccelerateSettings, + dot:Planar64, +} +impl Into for LadderSettings{ + fn into(self)->strafesnet_common::gameplay_style::LadderSettings{ + strafesnet_common::gameplay_style::LadderSettings::new( + self.accelerate.into(), + strafesnet_common::integer::Planar64::raw(self.dot), + ) + } +} + +#[binrw::binrw] +#[brw(little,repr=u8)] +pub enum HitboxMesh{ + Box, + Cylinder, +} +impl Into for HitboxMesh{ + fn into(self)->strafesnet_common::gameplay_style::HitboxMesh{ + match self{ + HitboxMesh::Box=>strafesnet_common::gameplay_style::HitboxMesh::Box, + HitboxMesh::Cylinder=>strafesnet_common::gameplay_style::HitboxMesh::Cylinder, + } + } +} + +#[binrw::binrw] +#[brw(little)] +pub struct Hitbox{ + pub halfsize:Planar64Vec3, + pub mesh:HitboxMesh, +} +impl Into for Hitbox{ + fn into(self)->strafesnet_common::gameplay_style::Hitbox{ + strafesnet_common::gameplay_style::Hitbox{ + halfsize:strafesnet_common::integer::Planar64Vec3::raw(self.halfsize[0],self.halfsize[1],self.halfsize[2]), + mesh:self.mesh.into(), + } + } +} diff --git a/src/newtypes/integer.rs b/src/newtypes/integer.rs new file mode 100644 index 0000000..86a8b8c --- /dev/null +++ b/src/newtypes/integer.rs @@ -0,0 +1,26 @@ +pub type Time=i64; + +#[binrw::binrw] +#[brw(little)] +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() + } +} + +#[binrw::binrw] +#[brw(little)] +pub struct Ratio64Vec2{ + pub x:Ratio64, + pub y:Ratio64, +} + +pub type Angle32=i32; +pub type Planar64=i64; +pub type Planar64Vec3=[i64;3]; +pub type Planar64Mat3=[i64;9]; +pub type Planar64Affine3=[i64;12]; diff --git a/src/newtypes/model.rs b/src/newtypes/model.rs new file mode 100644 index 0000000..6b6ea19 --- /dev/null +++ b/src/newtypes/model.rs @@ -0,0 +1,104 @@ +use super::integer::{Planar64Vec3,Planar64Affine3}; + +pub type TextureCoordinate=[f32;2]; +pub type Color4=[f32;4]; + +#[binrw::binrw] +#[brw(little)] +pub struct IndexedVertex{ + pub pos:u32, + pub tex:u32, + pub normal:u32, + pub color:u32, +} + +#[binrw::binrw] +#[brw(little)] +pub struct Polygon{ + pub count:u32, + #[br(count=count)] + pub vertices:Vec, +} +#[binrw::binrw] +#[brw(little)] +pub struct PolygonGroup{ + pub count:u32, + #[br(count=count)] + pub vertices:Vec, +} +#[binrw::binrw] +#[brw(little)] +pub struct IndexedGraphicsGroup{ + pub count:u32, + pub render:u32, + #[br(count=count)] + pub groups:Vec, +} +#[binrw::binrw] +#[brw(little)] +pub struct IndexedPhysicsGroup{ + pub count:u32, + #[br(count=count)] + pub groups:Vec, +} + +#[binrw::binrw] +#[brw(little)] +pub struct MeshHeader{ + pub unique_pos:u32, + pub unique_normal:u32, + pub unique_tex:u32, + pub unique_color:u32, + pub unique_vertices:u32, + pub polygon_groups:u32, + pub graphics_groups:u32, + pub physics_groups:u32, +} +#[binrw::binrw] +#[brw(little)] +pub struct Mesh{ + pub header:MeshHeader, + #[br(count=header.unique_pos)] + pub unique_pos:Vec, + #[br(count=header.unique_normal)] + pub unique_normal:Vec, + #[br(count=header.unique_tex)] + pub unique_tex:Vec, + #[br(count=header.unique_color)] + pub unique_color:Vec, + #[br(count=header.unique_vertices)] + pub unique_vertices:Vec, + #[br(count=header.polygon_groups)] + pub polygon_groups:Vec, + #[br(count=header.graphics_groups)] + pub graphics_groups:Vec, + #[br(count=header.physics_groups)] + pub physics_groups:Vec, +} + +#[binrw::binrw] +#[brw(little)] +pub struct Model{ + pub mesh:u32, + pub attributes:u32, + pub color:Color4, + pub transform:Planar64Affine3, +} +impl Into for Model{ + fn into(self)->strafesnet_common::model::Model{ + let [_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_a,_b]=self.transform; + strafesnet_common::model::Model{ + mesh:strafesnet_common::model::MeshId::new(self.mesh), + attributes:strafesnet_common::gameplay_attributes::CollisionAttributesId::new(self.attributes), + color:strafesnet_common::model::Color4::from_array(self.color), + transform:strafesnet_common::integer::Planar64Affine3::new( + strafesnet_common::integer::Planar64Mat3::from_cols( + strafesnet_common::integer::Planar64Vec3::raw(_0,_1,_2), + strafesnet_common::integer::Planar64Vec3::raw(_3,_4,_5), + strafesnet_common::integer::Planar64Vec3::raw(_6,_7,_8) + ), + strafesnet_common::integer::Planar64Vec3::raw(_9,_a,_b) + ), + } + } +}