diff --git a/strafe-client/src/body.rs b/strafe-client/src/body.rs new file mode 100644 index 0000000..6f7f769 --- /dev/null +++ b/strafe-client/src/body.rs @@ -0,0 +1,160 @@ +use strafesnet_common::aabb; +use strafesnet_common::integer::{self,vec3,Time,Planar64,Planar64Vec3}; +#[derive(Clone,Copy,Debug,Hash)] +pub struct Body{ + pub position:Planar64Vec3,//I64 where 2^32 = 1 u + pub velocity:Planar64Vec3,//I64 where 2^32 = 1 u/s + pub acceleration:Planar64Vec3,//I64 where 2^32 = 1 u/s/s + pub time:Time,//nanoseconds x xxxxD! +} +impl std::ops::Neg for Body{ + type Output=Self; + fn neg(self)->Self::Output{ + Self{ + position:self.position, + velocity:-self.velocity, + acceleration:self.acceleration, + time:-self.time, + } + } +} + +impl Body + where Time:Copy, +{ + pub const ZERO:Self=Self::new(vec3::ZERO,vec3::ZERO,vec3::ZERO,Time::ZERO); + pub const fn new(position:Planar64Vec3,velocity:Planar64Vec3,acceleration:Planar64Vec3,time:Time)->Self{ + Self{ + position, + velocity, + acceleration, + time, + } + } + pub fn extrapolated_position(&self,time:Time)->Planar64Vec3{ + let dt=time-self.time; + self.position + +(self.velocity*dt).map(|elem|elem.divide().fix_1()) + +self.acceleration.map(|elem|(dt*dt*elem/2).divide().fix_1()) + } + pub fn extrapolated_velocity(&self,time:Time)->Planar64Vec3{ + let dt=time-self.time; + self.velocity+(self.acceleration*dt).map(|elem|elem.divide().fix_1()) + } + pub fn advance_time(&mut self,time:Time){ + self.position=self.extrapolated_position(time); + self.velocity=self.extrapolated_velocity(time); + self.time=time; + } + pub fn extrapolated_position_ratio_dt(&self,dt:integer::Ratio)->Planar64Vec3 + where + // Why? + // All of this can be removed with const generics because the type can be specified as + // Ratio,Fixed> + // which is known to implement all the necessary traits + Num:Copy, + Den:Copy+core::ops::Mul, + D1:Copy, + Num:core::ops::Mul, + Planar64:core::ops::Mul, + N1:core::ops::Add, + Num:core::ops::Mul, + Den:core::ops::Mul, + D2:Copy, + Planar64:core::ops::Mul, + N4:integer::Divide, + T1:integer::Fix, + { + // a*dt^2/2 + v*dt + p + // (a*dt/2+v)*dt+p + (self.acceleration.map(|elem|dt*elem/2)+self.velocity).map(|elem|dt.mul_ratio(elem)) + .map(|elem|elem.divide().fix())+self.position + } + pub fn extrapolated_velocity_ratio_dt(&self,dt:integer::Ratio)->Planar64Vec3 + where + Num:Copy, + Den:Copy, + Num:core::ops::Mul, + Planar64:core::ops::Mul, + N1:integer::Divide, + T1:integer::Fix, + { + // a*dt + v + self.acceleration.map(|elem|(dt*elem).divide().fix())+self.velocity + } + pub fn advance_time_ratio_dt(&mut self,dt:crate::model_physics::GigaTime){ + self.position=self.extrapolated_position_ratio_dt(dt); + self.velocity=self.extrapolated_velocity_ratio_dt(dt); + self.time+=dt.into(); + } + pub fn infinity_dir(&self)->Option{ + if self.velocity==vec3::ZERO{ + if self.acceleration==vec3::ZERO{ + None + }else{ + Some(self.acceleration) + } + }else{ + Some(self.velocity) + } + } + pub fn grow_aabb(&self,aabb:&mut aabb::Aabb,t0:Time,t1:Time){ + aabb.grow(self.extrapolated_position(t0)); + aabb.grow(self.extrapolated_position(t1)); + //v+a*t==0 + //goober code + if !self.acceleration.x.is_zero(){ + let t=-self.velocity.x/self.acceleration.x; + if t0.to_ratio().lt_ratio(t)&&t.lt_ratio(t1.to_ratio()){ + aabb.grow(self.extrapolated_position_ratio_dt(t)); + } + } + if !self.acceleration.y.is_zero(){ + let t=-self.velocity.y/self.acceleration.y; + if t0.to_ratio().lt_ratio(t)&&t.lt_ratio(t1.to_ratio()){ + aabb.grow(self.extrapolated_position_ratio_dt(t)); + } + } + if !self.acceleration.z.is_zero(){ + let t=-self.velocity.z/self.acceleration.z; + if t0.to_ratio().lt_ratio(t)&&t.lt_ratio(t1.to_ratio()){ + aabb.grow(self.extrapolated_position_ratio_dt(t)); + } + } + } + +} +impl std::fmt::Display for Body{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"p({}) v({}) a({}) t({})",self.position,self.velocity,self.acceleration,self.time) + } +} + +pub struct VirtualBody<'a,T>{ + body0:&'a Body, + body1:&'a Body, +} +impl VirtualBody<'_,T> + where Time:Copy, +{ + pub const fn relative<'a>(body0:&'a Body,body1:&'a Body)->VirtualBody<'a,T>{ + //(p0,v0,a0,t0) + //(p1,v1,a1,t1) + VirtualBody{ + body0, + body1, + } + } + pub fn extrapolated_position(&self,time:Time)->Planar64Vec3{ + self.body1.extrapolated_position(time)-self.body0.extrapolated_position(time) + } + pub fn extrapolated_velocity(&self,time:Time)->Planar64Vec3{ + self.body1.extrapolated_velocity(time)-self.body0.extrapolated_velocity(time) + } + pub fn acceleration(&self)->Planar64Vec3{ + self.body1.acceleration-self.body0.acceleration + } + pub fn body(&self,time:Time)->Body{ + Body::new(self.extrapolated_position(time),self.extrapolated_velocity(time),self.acceleration(),time) + } +} diff --git a/strafe-client/src/face_crawler.rs b/strafe-client/src/face_crawler.rs index 4fc22d9..64b3631 100644 --- a/strafe-client/src/face_crawler.rs +++ b/strafe-client/src/face_crawler.rs @@ -1,6 +1,6 @@ -use crate::physics::Body; use crate::model_physics::{GigaTime,FEV,MeshQuery,DirectedEdge,MinkowskiMesh,MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert}; -use strafesnet_common::integer::{Time,Fixed,Ratio}; +use strafesnet_common::integer::{Fixed,Ratio}; +use crate::physics::{Time,Body}; #[derive(Debug)] enum Transition{ diff --git a/strafe-client/src/graphics.rs b/strafe-client/src/graphics.rs index 51d8eb4..b870ad2 100644 --- a/strafe-client/src/graphics.rs +++ b/strafe-client/src/graphics.rs @@ -98,12 +98,6 @@ impl std::default::Default for GraphicsCamera{ } } -pub struct FrameState{ - pub body:crate::physics::Body, - pub camera:crate::physics::PhysicsCamera, - pub time:integer::Time, -} - pub struct GraphicsState{ pipelines:GraphicsPipelines, bind_groups:GraphicsBindGroups, @@ -882,7 +876,7 @@ impl GraphicsState{ view:&wgpu::TextureView, device:&wgpu::Device, queue:&wgpu::Queue, - frame_state:FrameState, + frame_state:crate::physics_worker::FrameState, ){ //TODO:use scheduled frame times to create beautiful smoothing simulation physics extrapolation assuming no input diff --git a/strafe-client/src/graphics_worker.rs b/strafe-client/src/graphics_worker.rs index 9950785..67c89be 100644 --- a/strafe-client/src/graphics_worker.rs +++ b/strafe-client/src/graphics_worker.rs @@ -1,5 +1,5 @@ pub enum Instruction{ - Render(crate::graphics::FrameState), + Render(crate::physics_worker::FrameState), //UpdateModel(crate::graphics::GraphicsModelUpdate), Resize(winit::dpi::PhysicalSize,crate::settings::UserSettings), ChangeMap(strafesnet_common::map::CompleteMap), diff --git a/strafe-client/src/main.rs b/strafe-client/src/main.rs index d580614..312cd33 100644 --- a/strafe-client/src/main.rs +++ b/strafe-client/src/main.rs @@ -1,3 +1,4 @@ +mod body; mod file; mod setup; mod window; diff --git a/strafe-client/src/model_physics.rs b/strafe-client/src/model_physics.rs index ae60240..a429e77 100644 --- a/strafe-client/src/model_physics.rs +++ b/strafe-client/src/model_physics.rs @@ -3,6 +3,9 @@ use std::collections::{HashSet,HashMap}; use strafesnet_common::integer::vec3::Vector3; use strafesnet_common::model::{self,MeshId,PolygonIter}; use strafesnet_common::integer::{self,vec3,Fixed,Planar64,Planar64Vec3,Ratio}; +use strafesnet_common::physics::Time; + +type Body=crate::body::Body; pub trait UndirectedEdge{ type DirectedEdge:Copy+DirectedEdge; @@ -700,7 +703,7 @@ impl MinkowskiMesh<'_>{ }, } } - fn closest_fev_not_inside(&self,mut infinity_body:crate::physics::Body)->Option>{ + fn closest_fev_not_inside(&self,mut infinity_body:Body)->Option>{ infinity_body.infinity_dir().map_or(None,|dir|{ let infinity_fev=self.infinity_fev(-dir,infinity_body.position); //a line is simpler to solve than a parabola @@ -708,13 +711,13 @@ impl MinkowskiMesh<'_>{ infinity_body.acceleration=vec3::ZERO; //crawl in from negative infinity along a tangent line to get the closest fev // TODO: change crawl_fev args to delta time? Optional values? - match crate::face_crawler::crawl_fev(infinity_fev,self,&infinity_body,integer::Time::MIN/4,infinity_body.time){ + match crate::face_crawler::crawl_fev(infinity_fev,self,&infinity_body,Time::MIN/4,infinity_body.time){ crate::face_crawler::CrawlResult::Miss(fev)=>Some(fev), crate::face_crawler::CrawlResult::Hit(_,_)=>None, } }) } - pub fn predict_collision_in(&self,relative_body:&crate::physics::Body,time_limit:integer::Time)->Option<(MinkowskiFace,GigaTime)>{ + pub fn predict_collision_in(&self,relative_body:&Body,time_limit:Time)->Option<(MinkowskiFace,GigaTime)>{ self.closest_fev_not_inside(relative_body.clone()).map_or(None,|fev|{ //continue forwards along the body parabola match crate::face_crawler::crawl_fev(fev,self,relative_body,relative_body.time,time_limit){ @@ -723,9 +726,9 @@ impl MinkowskiMesh<'_>{ } }) } - pub fn predict_collision_out(&self,relative_body:&crate::physics::Body,time_limit:integer::Time)->Option<(MinkowskiFace,GigaTime)>{ + pub fn predict_collision_out(&self,relative_body:&Body,time_limit:Time)->Option<(MinkowskiFace,GigaTime)>{ //create an extrapolated body at time_limit - let infinity_body=crate::physics::Body::new( + let infinity_body=Body::new( relative_body.extrapolated_position(time_limit), -relative_body.extrapolated_velocity(time_limit), relative_body.acceleration, @@ -739,7 +742,7 @@ impl MinkowskiMesh<'_>{ } }) } - pub fn predict_collision_face_out(&self,relative_body:&crate::physics::Body,time_limit:integer::Time,contact_face_id:MinkowskiFace)->Option<(MinkowskiEdge,GigaTime)>{ + pub fn predict_collision_face_out(&self,relative_body:&Body,time_limit:Time,contact_face_id:MinkowskiFace)->Option<(MinkowskiEdge,GigaTime)>{ //no algorithm needed, there is only one state and two cases (Edge,None) //determine when it passes an edge ("sliding off" case) let mut best_time={ @@ -766,15 +769,15 @@ impl MinkowskiMesh<'_>{ } best_edge.map(|e|(e.as_undirected(),best_time)) } - fn infinity_in(&self,infinity_body:crate::physics::Body)->Option<(MinkowskiFace,GigaTime)>{ + fn infinity_in(&self,infinity_body:Body)->Option<(MinkowskiFace,GigaTime)>{ let infinity_fev=self.infinity_fev(-infinity_body.velocity,infinity_body.position); - match crate::face_crawler::crawl_fev(infinity_fev,self,&infinity_body,integer::Time::MIN/4,infinity_body.time){ + match crate::face_crawler::crawl_fev(infinity_fev,self,&infinity_body,Time::MIN/4,infinity_body.time){ crate::face_crawler::CrawlResult::Miss(_)=>None, crate::face_crawler::CrawlResult::Hit(face,time)=>Some((face,time)), } } pub fn is_point_in_mesh(&self,point:Planar64Vec3)->bool{ - let infinity_body=crate::physics::Body::new(point,vec3::Y,vec3::ZERO,integer::Time::ZERO); + let infinity_body=Body::new(point,vec3::Y,vec3::ZERO,Time::ZERO); //movement must escape the mesh forwards and backwards in time, //otherwise the point is not inside the mesh self.infinity_in(infinity_body) diff --git a/strafe-client/src/physics.rs b/strafe-client/src/physics.rs index 1fb2571..7b32d8b 100644 --- a/strafe-client/src/physics.rs +++ b/strafe-client/src/physics.rs @@ -5,15 +5,18 @@ use strafesnet_common::map; use strafesnet_common::run; use strafesnet_common::aabb; use strafesnet_common::model::{MeshId,ModelId}; -use strafesnet_common::mouse::MouseState; use strafesnet_common::gameplay_attributes::{self,CollisionAttributesId}; use strafesnet_common::gameplay_modes::{self,StageId}; use strafesnet_common::gameplay_style::{self,StyleModifiers}; use strafesnet_common::controls_bitflag::Controls; use strafesnet_common::instruction::{self,InstructionEmitter,InstructionConsumer,TimedInstruction}; -use strafesnet_common::integer::{self,vec3,mat3,Time,Planar64,Planar64Vec3,Planar64Mat3,Angle32,Ratio64Vec2}; +use strafesnet_common::integer::{self,vec3,mat3,Planar64,Planar64Vec3,Planar64Mat3,Angle32,Ratio64Vec2}; +pub use strafesnet_common::physics::{Time,TimeInner}; use gameplay::ModeState; +pub type Body=crate::body::Body; +type MouseState=strafesnet_common::mouse::MouseState; + //external influence //this is how you influence the physics from outside use strafesnet_common::physics::Instruction as PhysicsInputInstruction; @@ -21,7 +24,7 @@ use strafesnet_common::physics::Instruction as PhysicsInputInstruction; //internal influence //when the physics asks itself what happens next, this is how it's represented #[derive(Debug)] -enum PhysicsInternalInstruction{ +pub enum PhysicsInternalInstruction{ CollisionStart(Collision,model_physics::GigaTime), CollisionEnd(Collision,model_physics::GigaTime), StrafeTick, @@ -29,32 +32,13 @@ enum PhysicsInternalInstruction{ // Water, } #[derive(Debug)] -enum PhysicsInstruction{ +pub enum PhysicsInstruction{ Internal(PhysicsInternalInstruction), //InputInstructions conditionally activate RefreshWalkTarget //(by doing what SetWalkTargetVelocity used to do and then flagging it) Input(PhysicsInputInstruction), } -#[derive(Clone,Copy,Debug,Hash)] -pub struct Body{ - pub position:Planar64Vec3,//I64 where 2^32 = 1 u - pub velocity:Planar64Vec3,//I64 where 2^32 = 1 u/s - pub acceleration:Planar64Vec3,//I64 where 2^32 = 1 u/s/s - pub time:Time,//nanoseconds x xxxxD! -} -impl std::ops::Neg for Body{ - type Output=Self; - fn neg(self)->Self::Output{ - Self{ - position:self.position, - velocity:-self.velocity, - acceleration:self.acceleration, - time:-self.time, - } - } -} - #[derive(Clone,Debug,Default)] pub struct InputState{ mouse:MouseState, @@ -574,7 +558,7 @@ impl MoveState{ =>None, } } - fn next_move_instruction(&self,strafe:&Option,time:Time)->Option>{ + fn next_move_instruction(&self,strafe:&Option,time:Time)->Option>{ //check if you have a valid walk state and create an instruction match self{ MoveState::Walk(walk_state)|MoveState::Ladder(walk_state)=>match &walk_state.target{ @@ -800,8 +784,8 @@ impl TouchingState{ } } } - fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,time:Time){ - let relative_body=VirtualBody::relative(&Body::ZERO,body).body(time); + fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,time:Time){ + let relative_body=crate::body::VirtualBody::relative(&Body::ZERO,body).body(time); for contact in &self.contacts{ //detect face slide off let model_mesh=models.contact_mesh(contact); @@ -833,142 +817,6 @@ impl TouchingState{ } } -impl Body{ - pub const ZERO:Self=Self::new(vec3::ZERO,vec3::ZERO,vec3::ZERO,Time::ZERO); - pub const fn new(position:Planar64Vec3,velocity:Planar64Vec3,acceleration:Planar64Vec3,time:Time)->Self{ - Self{ - position, - velocity, - acceleration, - time, - } - } - pub fn extrapolated_position(&self,time:Time)->Planar64Vec3{ - let dt=time-self.time; - self.position - +(self.velocity*dt).map(|elem|elem.divide().fix_1()) - +self.acceleration.map(|elem|(dt*dt*elem/2).divide().fix_1()) - } - pub fn extrapolated_velocity(&self,time:Time)->Planar64Vec3{ - let dt=time-self.time; - self.velocity+(self.acceleration*dt).map(|elem|elem.divide().fix_1()) - } - pub fn advance_time(&mut self,time:Time){ - self.position=self.extrapolated_position(time); - self.velocity=self.extrapolated_velocity(time); - self.time=time; - } - pub fn extrapolated_position_ratio_dt(&self,dt:integer::Ratio)->Planar64Vec3 - where - // Why? - // All of this can be removed with const generics because the type can be specified as - // Ratio,Fixed> - // which is known to implement all the necessary traits - Num:Copy, - Den:Copy+core::ops::Mul, - D1:Copy, - Num:core::ops::Mul, - Planar64:core::ops::Mul, - N1:core::ops::Add, - Num:core::ops::Mul, - Den:core::ops::Mul, - D2:Copy, - Planar64:core::ops::Mul, - N4:integer::Divide, - T1:integer::Fix, - { - // a*dt^2/2 + v*dt + p - // (a*dt/2+v)*dt+p - (self.acceleration.map(|elem|dt*elem/2)+self.velocity).map(|elem|dt.mul_ratio(elem)) - .map(|elem|elem.divide().fix())+self.position - } - pub fn extrapolated_velocity_ratio_dt(&self,dt:integer::Ratio)->Planar64Vec3 - where - Num:Copy, - Den:Copy, - Num:core::ops::Mul, - Planar64:core::ops::Mul, - N1:integer::Divide, - T1:integer::Fix, - { - // a*dt + v - self.acceleration.map(|elem|(dt*elem).divide().fix())+self.velocity - } - pub fn advance_time_ratio_dt(&mut self,dt:model_physics::GigaTime){ - self.position=self.extrapolated_position_ratio_dt(dt); - self.velocity=self.extrapolated_velocity_ratio_dt(dt); - self.time+=dt.into(); - } - pub fn infinity_dir(&self)->Option{ - if self.velocity==vec3::ZERO{ - if self.acceleration==vec3::ZERO{ - None - }else{ - Some(self.acceleration) - } - }else{ - Some(self.velocity) - } - } - pub fn grow_aabb(&self,aabb:&mut aabb::Aabb,t0:Time,t1:Time){ - aabb.grow(self.extrapolated_position(t0)); - aabb.grow(self.extrapolated_position(t1)); - //v+a*t==0 - //goober code - if !self.acceleration.x.is_zero(){ - let t=-self.velocity.x/self.acceleration.x; - if t0.to_ratio().lt_ratio(t)&&t.lt_ratio(t1.to_ratio()){ - aabb.grow(self.extrapolated_position_ratio_dt(t)); - } - } - if !self.acceleration.y.is_zero(){ - let t=-self.velocity.y/self.acceleration.y; - if t0.to_ratio().lt_ratio(t)&&t.lt_ratio(t1.to_ratio()){ - aabb.grow(self.extrapolated_position_ratio_dt(t)); - } - } - if !self.acceleration.z.is_zero(){ - let t=-self.velocity.z/self.acceleration.z; - if t0.to_ratio().lt_ratio(t)&&t.lt_ratio(t1.to_ratio()){ - aabb.grow(self.extrapolated_position_ratio_dt(t)); - } - } - } - -} -impl std::fmt::Display for Body{ - fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ - write!(f,"p({}) v({}) a({}) t({})",self.position,self.velocity,self.acceleration,self.time) - } -} - -struct VirtualBody<'a>{ - body0:&'a Body, - body1:&'a Body, -} -impl VirtualBody<'_>{ - const fn relative<'a>(body0:&'a Body,body1:&'a Body)->VirtualBody<'a>{ - //(p0,v0,a0,t0) - //(p1,v1,a1,t1) - VirtualBody{ - body0, - body1, - } - } - fn extrapolated_position(&self,time:Time)->Planar64Vec3{ - self.body1.extrapolated_position(time)-self.body0.extrapolated_position(time) - } - fn extrapolated_velocity(&self,time:Time)->Planar64Vec3{ - self.body1.extrapolated_velocity(time)-self.body0.extrapolated_velocity(time) - } - fn acceleration(&self)->Planar64Vec3{ - self.body1.acceleration-self.body0.acceleration - } - fn body(&self,time:Time)->Body{ - Body::new(self.extrapolated_position(time),self.extrapolated_velocity(time),self.acceleration(),time) - } -} - #[derive(Clone,Debug)] pub struct PhysicsState{ time:Time, @@ -1036,7 +884,7 @@ impl PhysicsState{ new_state.camera.sensitivity=self.camera.sensitivity; *self=new_state; } - fn next_move_instruction(&self)->Option>{ + fn next_move_instruction(&self)->Option>{ self.move_state.next_move_instruction(&self.style.strafe,self.time) } fn cull_velocity(&mut self,data:&PhysicsData,velocity:Planar64Vec3){ @@ -1086,14 +934,18 @@ pub struct PhysicsContext{ data:PhysicsData,//data currently loaded into memory which is needded for physics to run, but is not part of the state. } //the physics consumes the generic PhysicsInstruction, but can only emit the more narrow PhysicsInternalInstruction -impl instruction::InstructionConsumer for PhysicsContext{ - fn process_instruction(&mut self,ins:TimedInstruction){ +impl instruction::InstructionConsumer for PhysicsContext{ + type Instruction=PhysicsInstruction; + type TimeInner=TimeInner; + fn process_instruction(&mut self,ins:TimedInstruction){ atomic_state_update(&mut self.state,&self.data,ins) } } -impl instruction::InstructionEmitter for PhysicsContext{ +impl instruction::InstructionEmitter for PhysicsContext{ + type Instruction=PhysicsInternalInstruction; + type TimeInner=TimeInner; //this little next instruction function could cache its return value and invalidate the cached value by watching the State. - fn next_instruction(&self,time_limit:Time)->Option>{ + fn next_instruction(&self,time_limit:Time)->Option>{ next_instruction_internal(&self.state,&self.data,time_limit) } } @@ -1262,7 +1114,7 @@ impl PhysicsContext{ //write hash lol } } - pub fn run_input_instruction(&mut self,instruction:TimedInstruction){ + pub fn run_input_instruction(&mut self,instruction:TimedInstruction){ self.run_internal_exhaustive(instruction.time); self.process_instruction(TimedInstruction{ time:instruction.time, @@ -1272,7 +1124,7 @@ impl PhysicsContext{ } //this is the one who asks - fn next_instruction_internal(state:&PhysicsState,data:&PhysicsData,time_limit:Time)->Option>{ + fn next_instruction_internal(state:&PhysicsState,data:&PhysicsData,time_limit:Time)->Option>{ //JUST POLLING!!! NO MUTATION let mut collector = instruction::InstructionCollector::new(time_limit); @@ -1805,7 +1657,7 @@ fn collision_end_intersect( } } } -fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction){ +fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction){ state.time=ins.time; let (should_advance_body,goober_time)=match ins.instruction{ PhysicsInternalInstruction::CollisionStart(_,dt) @@ -1901,7 +1753,7 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim } } -fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction){ +fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction){ state.time=ins.time; let should_advance_body=match ins.instruction{ //the body may as well be a quantum wave function @@ -2027,7 +1879,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI } } - fn atomic_state_update(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction){ + fn atomic_state_update(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction){ match &ins.instruction{ PhysicsInstruction::Input(PhysicsInputInstruction::Idle) |PhysicsInstruction::Input(PhysicsInputInstruction::SetNextMouse(_)) @@ -2050,6 +1902,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI #[cfg(test)] mod test{ use strafesnet_common::integer::{vec3::{self,int as int3},mat3}; + use crate::body::VirtualBody; use super::*; fn test_collision_axis_aligned(relative_body:Body,expected_collision_time:Option