From 77aa83d6acfa24f33af0f43ae866a7fbc1953234 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Mon, 20 Jan 2025 07:51:39 -0800
Subject: [PATCH] physics: explicit start_time

---
 strafe-client/src/model_physics.rs | 31 +++++++++++++++---------------
 strafe-client/src/physics.rs       | 15 ++++++++-------
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/strafe-client/src/model_physics.rs b/strafe-client/src/model_physics.rs
index 1adfd411..57f9ec36 100644
--- a/strafe-client/src/model_physics.rs
+++ b/strafe-client/src/model_physics.rs
@@ -718,7 +718,7 @@ impl MinkowskiMesh<'_>{
 	//
 	// Most of the calculation time is just calculating the starting point
 	// for the "actual" crawling algorithm below (predict_collision_{in|out}).
-	fn closest_fev_not_inside(&self,mut infinity_body:Body)->Option<FEV<MinkowskiMesh>>{
+	fn closest_fev_not_inside(&self,mut infinity_body:Body,start_time:Time,)->Option<FEV<MinkowskiMesh>>{
 		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
@@ -726,40 +726,39 @@ 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 infinity_fev.crawl(self,&infinity_body,Time::MIN/4,infinity_body.time){
+			match infinity_fev.crawl(self,&infinity_body,Time::MIN/4,start_time){
 				crate::face_crawler::CrawlResult::Miss(fev)=>Some(fev),
 				crate::face_crawler::CrawlResult::Hit(_,_)=>None,
 			}
 		})
 	}
-	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|{
+	pub fn predict_collision_in(&self,relative_body:&Body,start_time:Time,time_limit:Time)->Option<(MinkowskiFace,GigaTime)>{
+		self.closest_fev_not_inside(relative_body.clone(),start_time).map_or(None,|fev|{
 			//continue forwards along the body parabola
-			match fev.crawl(self,relative_body,relative_body.time,time_limit){
+			match fev.crawl(self,relative_body,start_time,time_limit){
 				crate::face_crawler::CrawlResult::Miss(_)=>None,
 				crate::face_crawler::CrawlResult::Hit(face,time)=>Some((face,time)),
 			}
 		})
 	}
-	pub fn predict_collision_out(&self,relative_body:&Body,time_limit:Time)->Option<(MinkowskiFace,GigaTime)>{
+	pub fn predict_collision_out(&self,relative_body:&Body,start_time:Time,time_limit:Time)->Option<(MinkowskiFace,GigaTime)>{
 		//create an extrapolated body at time_limit
-		let infinity_body=Body::new(
-			relative_body.extrapolated_position(time_limit),
-			-relative_body.extrapolated_velocity(time_limit),
-			relative_body.acceleration,
-			-time_limit,
-		);
-		self.closest_fev_not_inside(infinity_body).map_or(None,|fev|{
+		let infinity_body=-relative_body.clone();
+		self.closest_fev_not_inside(infinity_body,-time_limit).map_or(None,|fev|{
 			//continue backwards along the body parabola
-			match fev.crawl(self,&-relative_body.clone(),-time_limit,-relative_body.time){
+			match fev.crawl(self,&infinity_body,-time_limit,-start_time){
 				crate::face_crawler::CrawlResult::Miss(_)=>None,
 				crate::face_crawler::CrawlResult::Hit(face,time)=>Some((face,-time)),//no need to test -time<time_limit because of the first step
 			}
 		})
 	}
-	pub fn predict_collision_face_out(&self,relative_body:&Body,time_limit:Time,contact_face_id:MinkowskiFace)->Option<(MinkowskiEdge,GigaTime)>{
+	pub fn predict_collision_face_out(&self,relative_body:&Body,start_time:Time,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 start_time={
+			let r=(start_time-relative_body.time).to_ratio();
+			Ratio::new(r.num,r.den)
+		};
 		let mut best_time={
 			let r=(time_limit-relative_body.time).to_ratio();
 			Ratio::new(r.num.fix_4(),r.den.fix_4())
@@ -775,7 +774,7 @@ impl MinkowskiMesh<'_>{
 			//WARNING! d outside of *2
 			//WARNING: truncated precision
 			for dt in Fixed::<4,128>::zeroes2(((n.dot(relative_body.position))*2-d).fix_4(),n.dot(relative_body.velocity).fix_4()*2,n.dot(relative_body.acceleration).fix_4()){
-				if Ratio::new(Planar64::ZERO,Planar64::EPSILON).le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(relative_body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
+				if start_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(relative_body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
 					best_time=dt;
 					best_edge=Some(directed_edge_id);
 					break;
diff --git a/strafe-client/src/physics.rs b/strafe-client/src/physics.rs
index 29758ed4..b0388764 100644
--- a/strafe-client/src/physics.rs
+++ b/strafe-client/src/physics.rs
@@ -776,13 +776,14 @@ impl TouchingState{
 		}).collect();
 		*acceleration=crate::push_solve::push_solve(&contacts,*acceleration);
 	}
-	fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector<InternalInstruction,TimeInner>,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,time:Time){
-		let relative_body=crate::body::VirtualBody::relative(&Body::ZERO,body).body(time);
+	fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector<InternalInstruction,TimeInner>,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,start_time:Time){
+		// let relative_body=crate::body::VirtualBody::relative(&Body::ZERO,body).body(time);
+		let relative_body=body;
 		for contact in &self.contacts{
 			//detect face slide off
 			let model_mesh=models.contact_mesh(contact);
 			let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
-			collector.collect(minkowski.predict_collision_face_out(&relative_body,collector.time(),contact.face_id).map(|(_face,time)|{
+			collector.collect(minkowski.predict_collision_face_out(&relative_body,start_time,collector.time(),contact.face_id).map(|(_face,time)|{
 				TimedInstruction{
 					time:relative_body.time+time.into(),
 					instruction:InternalInstruction::CollisionEnd(
@@ -796,7 +797,7 @@ impl TouchingState{
 			//detect model collision in reverse
 			let model_mesh=models.intersect_mesh(intersect);
 			let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
-			collector.collect(minkowski.predict_collision_out(&relative_body,collector.time()).map(|(_face,time)|{
+			collector.collect(minkowski.predict_collision_out(&relative_body,start_time,collector.time()).map(|(_face,time)|{
 				TimedInstruction{
 					time:relative_body.time+time.into(),
 					instruction:InternalInstruction::CollisionEnd(
@@ -1128,7 +1129,7 @@ impl PhysicsData{
 			//no checks are needed because of the time limits.
 			let model_mesh=data.models.mesh(convex_mesh_id);
 			let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,data.hitbox_mesh.transformed_mesh());
-			collector.collect(minkowski.predict_collision_in(relative_body,collector.time())
+			collector.collect(minkowski.predict_collision_in(relative_body,state.time,collector.time())
 				//temp (?) code to avoid collision loops
 				.map_or(None,|(face,dt)|{
 					// this must be rounded to avoid the infinite loop when hitting the start zone
@@ -1868,7 +1869,7 @@ mod test{
 		let hitbox_mesh=h1.transformed_mesh();
 		let platform_mesh=h0.transformed_mesh();
 		let minkowski=model_physics::MinkowskiMesh::minkowski_sum(platform_mesh,hitbox_mesh);
-		let collision=minkowski.predict_collision_in(&relative_body,Time::from_secs(10));
+		let collision=minkowski.predict_collision_in(&relative_body,Time::ZERO,Time::from_secs(10));
 		assert_eq!(collision.map(|tup|relative_body.time+tup.1.into()),expected_collision_time,"Incorrect time of collision");
 	}
 	fn test_collision_rotated(relative_body:Body,expected_collision_time:Option<Time>){
@@ -1886,7 +1887,7 @@ mod test{
 		let hitbox_mesh=h1.transformed_mesh();
 		let platform_mesh=h0.transformed_mesh();
 		let minkowski=model_physics::MinkowskiMesh::minkowski_sum(platform_mesh,hitbox_mesh);
-		let collision=minkowski.predict_collision_in(&relative_body,Time::from_secs(10));
+		let collision=minkowski.predict_collision_in(&relative_body,Time::ZERO,Time::from_secs(10));
 		assert_eq!(collision.map(|tup|relative_body.time+tup.1.into()),expected_collision_time,"Incorrect time of collision");
 	}
 	fn test_collision(relative_body:Body,expected_collision_time:Option<Time>){