diff --git a/src/load_roblox.rs b/src/load_roblox.rs index 3fd1c68..751e42d 100644 --- a/src/load_roblox.rs +++ b/src/load_roblox.rs @@ -50,8 +50,17 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,force_interse let mut contacting=crate::model::ContactingAttributes::default(); let mut force_can_collide=can_collide; match name{ - "Water"=>intersecting.water=Some(crate::model::IntersectingWater{density:Planar64::ONE,viscosity:Planar64::ONE/10,current:velocity}), - "Accelerator"=>{force_can_collide=false;intersecting.accelerator=Some(crate::model::IntersectingAccelerator{acceleration:velocity})}, + "Water"=>{ + force_can_collide=false; + //TODO: read stupid CustomPhysicalProperties + intersecting.water=Some(crate::model::IntersectingWater{density:Planar64::ONE,viscosity:Planar64::ONE/10,current:velocity}); + }, + "Accelerator"=>{ + //although the new game supports collidable accelerators, this is a roblox compatability map loader + force_can_collide=false; + general.accelerator=Some(crate::model::GameMechanicAccelerator{acceleration:velocity}); + }, + "SetVelocity"=>general.trajectory=Some(crate::model::GameMechanicSetTrajectory::Velocity(velocity)), "MapFinish"=>{force_can_collide=false;general.zone=Some(crate::model::GameMechanicZone{mode_id:0,behaviour:crate::model::ZoneBehaviour::Finish})}, "MapAnticheat"=>{force_can_collide=false;general.zone=Some(crate::model::GameMechanicZone{mode_id:0,behaviour:crate::model::ZoneBehaviour::Anitcheat})}, "Platform"=>general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(crate::model::GameMechanicStageElement{ @@ -72,12 +81,28 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,force_interse }, behaviour:match &captures[2]{ "Spawn"|"SpawnAt"=>crate::model::StageElementBehaviour::SpawnAt, + //cancollide false so you don't hit the side + //NOT a decoration "Trigger"=>{force_can_collide=false;crate::model::StageElementBehaviour::Trigger}, "Teleport"=>{force_can_collide=false;crate::model::StageElementBehaviour::Teleport}, "Platform"=>crate::model::StageElementBehaviour::Platform, _=>panic!("regex1[2] messed up bad"), } })); + }else if let Some(captures)=lazy_regex::regex!(r"^(Force)?(Jump)(\d+)$") + .captures(other){ + general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(crate::model::GameMechanicStageElement{ + mode_id:0, + stage_id:0, + force:match captures.get(1){ + Some(m)=>m.as_str()=="Force", + None=>false, + }, + behaviour:match &captures[2]{ + "Jump"=>crate::model::StageElementBehaviour::JumpLimit(captures[3].parse::().unwrap()), + _=>panic!("regex4[1] messed up bad"), + } + })); }else if let Some(captures)=lazy_regex::regex!(r"^Bonus(Finish|Anticheat)(\d+)$") .captures(other){ force_can_collide=false; @@ -86,39 +111,33 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,force_interse "Anticheat"=>general.zone=Some(crate::model::GameMechanicZone{mode_id:captures[2].parse::().unwrap(),behaviour:crate::model::ZoneBehaviour::Anitcheat}), _=>panic!("regex2[1] messed up bad"), } + }else if let Some(captures)=lazy_regex::regex!(r"^(WormholeIn)(\d+)$") + .captures(other){ + force_can_collide=false; + match &captures[1]{ + "WormholeIn"=>general.teleport_behaviour=Some(crate::model::TeleportBehaviour::Wormhole(crate::model::GameMechanicWormhole{destination_model_id:captures[2].parse::().unwrap()})), + _=>panic!("regex3[1] messed up bad"), + } } } } //need some way to skip this if velocity!=Planar64Vec3::ZERO{ - general.booster=Some(crate::model::GameMechanicBooster{velocity}); + general.booster=Some(crate::model::GameMechanicBooster::Velocity(velocity)); } match force_can_collide{ true=>{ match name{ - "Bounce"=>contacting.elasticity=Some(u32::MAX), + "Bounce"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Elastic(u32::MAX)), "Surf"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Surf), "Ladder"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Ladder(crate::model::ContactingLadder{sticky:true})), - other=>{ - if let Some(captures)=lazy_regex::regex!(r"^(Jump|WormholeIn)(\d+)$") - .captures(other){ - match &captures[1]{ - "Jump"=>general.jump_limit=Some(crate::model::GameMechanicJumpLimit{count:captures[2].parse::().unwrap()}), - "WormholeIn"=>general.teleport_behaviour=Some(crate::model::TeleportBehaviour::Wormhole(crate::model::GameMechanicWormhole{destination_model_id:captures[2].parse::().unwrap()})), - _=>panic!("regex3[1] messed up bad"), - } - } - } + _=>(), } crate::model::CollisionAttributes::Contact{contacting,general} }, false=>if force_intersecting - ||general.jump_limit.is_some() - ||general.booster.is_some() - ||general.zone.is_some() - ||general.teleport_behaviour.is_some() - ||intersecting.water.is_some() - ||intersecting.accelerator.is_some() + ||general.any() + ||intersecting.any() { crate::model::CollisionAttributes::Intersect{intersecting,general} }else{ diff --git a/src/model.rs b/src/model.rs index edde0b3..76024c7 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,4 +1,4 @@ -use crate::integer::{Planar64,Planar64Vec3,Planar64Affine3}; +use crate::integer::{Time,Planar64,Planar64Vec3,Planar64Affine3}; pub type TextureCoordinate=glam::Vec2; pub type Color4=glam::Vec4; #[derive(Clone,Hash,PartialEq,Eq)] @@ -99,6 +99,7 @@ pub struct ContactingLadder{ pub enum ContactingBehaviour{ Surf, Ladder(ContactingLadder), + Elastic(u32),//[1/2^32,1] 0=None (elasticity+1)/2^32 } //you have this effect while intersecting #[derive(Clone)] @@ -107,18 +108,37 @@ pub struct IntersectingWater{ pub density:Planar64, pub current:Planar64Vec3, } -#[derive(Clone)] -pub struct IntersectingAccelerator{ - pub acceleration:Planar64Vec3 -} //All models can be given these attributes #[derive(Clone)] -pub struct GameMechanicJumpLimit{ - pub count:u32, +pub struct GameMechanicAccelerator{ + pub acceleration:Planar64Vec3 } #[derive(Clone)] -pub struct GameMechanicBooster{ - pub velocity:Planar64Vec3, +pub enum GameMechanicBooster{ + Affine(Planar64Affine3),//capable of SetVelocity,DotVelocity,normal booster,bouncy part,redirect velocity, and much more + Velocity(Planar64Vec3),//straight up boost velocity adds to your current velocity + Energy{direction:Planar64Vec3,energy:Planar64},//increase energy in direction +} +#[derive(Clone)] +pub enum TrajectoryChoice{ + HighArcLongDuration,//underhand lob at target: less horizontal speed and more air time + LowArcShortDuration,//overhand throw at target: more horizontal speed and less air time +} +#[derive(Clone)] +pub enum GameMechanicSetTrajectory{ + AirTime(Time),//air time (relative to gravity direction) is invariant across mass and gravity changes + Height(Planar64),//boost height (relative to gravity direction) is invariant across mass and gravity changes + TargetPointTime{//launch on a trajectory that will land at a target point in a set amount of time + target_point:Planar64Vec3, + time:Time,//short time = fast and direct, long time = launch high in the air, negative time = wrong way + }, + TrajectoryTargetPoint{//launch at a fixed speed and land at a target point + target_point:Planar64Vec3, + speed:Planar64,//if speed is too low this will fail to reach the target. The closest-passing trajectory will be chosen instead + trajectory_choice:TrajectoryChoice, + }, + Velocity(Planar64Vec3),//SetVelocity + DotVelocity{direction:Planar64Vec3,dot:Planar64},//set your velocity in a specific direction without touching other directions } #[derive(Clone)] pub enum ZoneBehaviour{ @@ -133,10 +153,10 @@ pub struct GameMechanicZone{ pub behaviour:ZoneBehaviour, } // enum TrapCondition{ -// FasterThan(i64), -// SlowerThan(i64), -// InRange(i64,i64), -// OutsideRange(i64,i64), +// FasterThan(Planar64), +// SlowerThan(Planar64), +// InRange(Planar64,Planar64), +// OutsideRange(Planar64,Planar64), // } #[derive(Clone)] pub enum StageElementBehaviour{ @@ -145,6 +165,7 @@ pub enum StageElementBehaviour{ Trigger, Teleport, Platform, + JumpLimit(u32), //Speedtrap(TrapCondition),//Acts as a trigger with a speed condition } #[derive(Clone)] @@ -167,23 +188,42 @@ pub enum TeleportBehaviour{ StageElement(GameMechanicStageElement), Wormhole(GameMechanicWormhole), } +//attributes listed in order of handling #[derive(Default,Clone)] pub struct GameMechanicAttributes{ - pub jump_limit:Option, - pub booster:Option, pub zone:Option, + pub booster:Option, + pub trajectory:Option, pub teleport_behaviour:Option, + pub accelerator:Option, +} +impl GameMechanicAttributes{ + pub fn any(&self)->bool{ + self.booster.is_some() + ||self.trajectory.is_some() + ||self.zone.is_some() + ||self.teleport_behaviour.is_some() + ||self.accelerator.is_some() + } } #[derive(Default,Clone)] pub struct ContactingAttributes{ - pub elasticity:Option,//[1/2^32,1] 0=None (elasticity+1)/2^32 //friction? pub contact_behaviour:Option, } +impl ContactingAttributes{ + pub fn any(&self)->bool{ + self.contact_behaviour.is_some() + } +} #[derive(Default,Clone)] pub struct IntersectingAttributes{ pub water:Option, - pub accelerator:Option, +} +impl IntersectingAttributes{ + pub fn any(&self)->bool{ + self.water.is_some() + } } //Spawn(u32) NO! spawns are indexed in the map header instead of marked with attibutes pub enum CollisionAttributes{ diff --git a/src/physics.rs b/src/physics.rs index 6ac9866..2afce4a 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -1313,12 +1313,18 @@ impl crate::instruction::InstructionConsumer for PhysicsStat let model=c.model(&self.models).unwrap(); match &model.attributes{ PhysicsCollisionAttributes::Contact{contacting,general}=>{ + let mut v=self.body.velocity; match &contacting.contact_behaviour{ Some(crate::model::ContactingBehaviour::Surf)=>println!("I'm surfing!"), + &Some(crate::model::ContactingBehaviour::Elastic(elasticity))=>{ + let n=c.normal(&self.models); + let d=n.dot(v)*Planar64::raw(-1-elasticity as i64); + v-=n*(d/n.dot(n)); + }, Some(crate::model::ContactingBehaviour::Ladder(contacting_ladder))=>{ if contacting_ladder.sticky{ //kill v - self.body.velocity=Planar64Vec3::ZERO;//model.velocity + v=Planar64Vec3::ZERO;//model.velocity } //ladder walkstate let (walk_state,a)=WalkState::ladder(&self.touching,&self.body,&self.style,&self.models,self.style.get_ladder_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time),&c.normal(&self.models)); @@ -1342,7 +1348,7 @@ impl crate::instruction::InstructionConsumer for PhysicsStat if stage_element.force||self.game.stage_id(), crate::model::StageElementBehaviour::Trigger |crate::model::StageElementBehaviour::Teleport=>{ @@ -1360,6 +1366,7 @@ impl crate::instruction::InstructionConsumer for PhysicsStat }else{println!("bad3");} }, crate::model::StageElementBehaviour::Platform=>(), + crate::model::StageElementBehaviour::JumpLimit(_)=>(),//TODO } }, Some(crate::model::TeleportBehaviour::Wormhole(wormhole))=>{ @@ -1368,11 +1375,28 @@ impl crate::instruction::InstructionConsumer for PhysicsStat None=>(), } //flatten v - let mut v=self.body.velocity; self.touching.constrain_velocity(&self.models,&mut v); match &general.booster{ Some(booster)=>{ - v+=booster.velocity; + match booster{ + &crate::model::GameMechanicBooster::Affine(transform)=>v=transform.transform_point3(v), + &crate::model::GameMechanicBooster::Velocity(velocity)=>v+=velocity, + &crate::model::GameMechanicBooster::Energy{direction,energy}=>todo!(), + } + self.touching.constrain_velocity(&self.models,&mut v); + }, + None=>(), + } + match &general.trajectory{ + Some(trajectory)=>{ + match trajectory{ + crate::model::GameMechanicSetTrajectory::AirTime(_) => todo!(), + crate::model::GameMechanicSetTrajectory::Height(_) => todo!(), + crate::model::GameMechanicSetTrajectory::TargetPointTime { target_point, time } => todo!(), + crate::model::GameMechanicSetTrajectory::TrajectoryTargetPoint { target_point, speed, trajectory_choice } => todo!(), + &crate::model::GameMechanicSetTrajectory::Velocity(velocity)=>v=velocity, + crate::model::GameMechanicSetTrajectory::DotVelocity { direction, dot } => todo!(), + } self.touching.constrain_velocity(&self.models,&mut v); }, None=>(), @@ -1391,7 +1415,7 @@ impl crate::instruction::InstructionConsumer for PhysicsStat if stage_element.force||self.game.stage_id(), crate::model::StageElementBehaviour::Trigger |crate::model::StageElementBehaviour::Teleport=>{ @@ -1409,6 +1433,7 @@ impl crate::instruction::InstructionConsumer for PhysicsStat }else{println!("bad3");} }, crate::model::StageElementBehaviour::Platform=>(), + crate::model::StageElementBehaviour::JumpLimit(_)=>(),//TODO } }, Some(crate::model::TeleportBehaviour::Wormhole(wormhole))=>{