Compare commits
14 Commits
no-cull-ve
...
map-read-s
Author | SHA1 | Date | |
---|---|---|---|
d2170a3f73 | |||
267c91d005 | |||
32b361b122 | |||
f5c3209c7c | |||
2eb74f2788 | |||
871aadb78a | |||
65b49d2726 | |||
ed70b7c484 | |||
c7575f2e21 | |||
c2f78eab48 | |||
195014400f | |||
ee9585a4c2 | |||
77012d6caa | |||
f9509353dd |
@ -3,6 +3,9 @@
|
||||
# Strafe Project
|
||||
Monorepo for working on projects related to strafe client.
|
||||
|
||||
## Try it out
|
||||
See [releases](https://git.itzana.me/StrafesNET/strafe-project/releases) for downloads.
|
||||
|
||||
## How to build and run
|
||||
1. Have rust and git installed
|
||||
2. `git clone https://git.itzana.me/StrafesNET/strafe-project`
|
||||
|
@ -12,6 +12,20 @@ pub enum CrawlResult<M:MeshQuery>{
|
||||
Miss(FEV<M>),
|
||||
Hit(M::Face,GigaTime),
|
||||
}
|
||||
impl<M:MeshQuery> CrawlResult<M>{
|
||||
pub fn hit(self)->Option<(M::Face,GigaTime)>{
|
||||
match self{
|
||||
CrawlResult::Miss(_)=>None,
|
||||
CrawlResult::Hit(face,time)=>Some((face,time)),
|
||||
}
|
||||
}
|
||||
pub fn miss(self)->Option<FEV<M>>{
|
||||
match self{
|
||||
CrawlResult::Miss(fev)=>Some(fev),
|
||||
CrawlResult::Hit(_,_)=>None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F:Copy,M:MeshQuery<Normal=Vector3<F>,Offset=Fixed<4,128>>> FEV<M>
|
||||
where
|
||||
|
@ -34,11 +34,20 @@ pub enum ReadFormat{
|
||||
}
|
||||
|
||||
pub fn read<R:Read+std::io::Seek>(input:R)->Result<ReadFormat,ReadError>{
|
||||
let t=std::time::Instant::now();
|
||||
println!("reading fourcc...");
|
||||
let mut buf=std::io::BufReader::new(input);
|
||||
let peek=std::io::BufRead::fill_buf(&mut buf).map_err(ReadError::Io)?[0..4].to_owned();
|
||||
let dt=t.elapsed();
|
||||
println!("{:?} elapsed={:?}",core::str::from_utf8(&peek),dt);
|
||||
|
||||
let t=std::time::Instant::now();
|
||||
println!("reading entire file...");
|
||||
// reading the entire file is way faster than round tripping the disk constantly
|
||||
let mut entire_file=Vec::new();
|
||||
buf.read_to_end(&mut entire_file).map_err(ReadError::Io)?;
|
||||
println!("elapsed={:?}",t.elapsed());
|
||||
|
||||
let cursor=std::io::Cursor::new(entire_file);
|
||||
match peek.as_slice(){
|
||||
#[cfg(feature="roblox")]
|
||||
@ -46,10 +55,15 @@ pub fn read<R:Read+std::io::Seek>(input:R)->Result<ReadFormat,ReadError>{
|
||||
#[cfg(feature="source")]
|
||||
b"VBSP"=>Ok(ReadFormat::Source(strafesnet_bsp_loader::read(cursor).map_err(ReadError::Source)?)),
|
||||
#[cfg(feature="snf")]
|
||||
b"SNFM"=>Ok(ReadFormat::SNFM(
|
||||
strafesnet_snf::read_map(cursor).map_err(ReadError::StrafesNET)?
|
||||
.into_complete_map().map_err(ReadError::StrafesNETMap)?
|
||||
)),
|
||||
b"SNFM"=>{
|
||||
let t=std::time::Instant::now();
|
||||
println!("decoding map...");
|
||||
let map=
|
||||
strafesnet_snf::read_map(cursor).map_err(ReadError::StrafesNET)?
|
||||
.into_complete_map().map_err(ReadError::StrafesNETMap)?;
|
||||
println!("elapsed={:?}",t.elapsed());
|
||||
Ok(ReadFormat::SNFM(map))
|
||||
},
|
||||
#[cfg(feature="snf")]
|
||||
b"SNFB"=>Ok(ReadFormat::SNFB(
|
||||
strafesnet_snf::read_bot(cursor).map_err(ReadError::StrafesNET)?
|
||||
|
@ -1,5 +1,6 @@
|
||||
use std::borrow::{Borrow,Cow};
|
||||
use std::collections::{HashSet,HashMap};
|
||||
use core::ops::Range;
|
||||
use strafesnet_common::integer::vec3::Vector3;
|
||||
use strafesnet_common::model::{self,MeshId,PolygonIter};
|
||||
use strafesnet_common::integer::{self,vec3,Fixed,Planar64,Planar64Vec3,Ratio};
|
||||
@ -718,41 +719,34 @@ 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,start_time:Time,)->Option<FEV<MinkowskiMesh>>{
|
||||
infinity_body.infinity_dir().map_or(None,|dir|{
|
||||
fn closest_fev_not_inside(&self,mut infinity_body:Body,start_time:Time)->Option<FEV<MinkowskiMesh>>{
|
||||
infinity_body.infinity_dir().and_then(|dir|{
|
||||
let infinity_fev=self.infinity_fev(-dir,infinity_body.position);
|
||||
//a line is simpler to solve than a parabola
|
||||
infinity_body.velocity=dir;
|
||||
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,start_time){
|
||||
crate::face_crawler::CrawlResult::Miss(fev)=>Some(fev),
|
||||
crate::face_crawler::CrawlResult::Hit(_,_)=>None,
|
||||
}
|
||||
infinity_fev.crawl(self,&infinity_body,Time::MIN/4,start_time).miss()
|
||||
})
|
||||
}
|
||||
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|{
|
||||
pub fn predict_collision_in(&self,relative_body:&Body,Range{start:start_time,end:time_limit}:Range<Time>)->Option<(MinkowskiFace,GigaTime)>{
|
||||
self.closest_fev_not_inside(relative_body.clone(),start_time).and_then(|fev|{
|
||||
//continue forwards along the body parabola
|
||||
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)),
|
||||
}
|
||||
fev.crawl(self,relative_body,start_time,time_limit).hit()
|
||||
})
|
||||
}
|
||||
pub fn predict_collision_out(&self,relative_body:&Body,start_time:Time,time_limit:Time)->Option<(MinkowskiFace,GigaTime)>{
|
||||
pub fn predict_collision_out(&self,relative_body:&Body,Range{start:start_time,end:time_limit}:Range<Time>)->Option<(MinkowskiFace,GigaTime)>{
|
||||
//create an extrapolated body at time_limit
|
||||
let infinity_body=-relative_body.clone();
|
||||
self.closest_fev_not_inside(infinity_body,-time_limit).map_or(None,|fev|{
|
||||
self.closest_fev_not_inside(infinity_body,-time_limit).and_then(|fev|{
|
||||
//continue backwards along the body parabola
|
||||
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
|
||||
}
|
||||
fev.crawl(self,&infinity_body,-time_limit,-start_time).hit()
|
||||
//no need to test -time<time_limit because of the first step
|
||||
.map(|(face,time)|(face,-time))
|
||||
})
|
||||
}
|
||||
pub fn predict_collision_face_out(&self,relative_body:&Body,start_time:Time,time_limit:Time,contact_face_id:MinkowskiFace)->Option<(MinkowskiEdge,GigaTime)>{
|
||||
pub fn predict_collision_face_out(&self,relative_body:&Body,Range{start:start_time,end:time_limit}:Range<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={
|
||||
@ -785,10 +779,7 @@ impl MinkowskiMesh<'_>{
|
||||
}
|
||||
fn infinity_in(&self,infinity_body:Body)->Option<(MinkowskiFace,GigaTime)>{
|
||||
let infinity_fev=self.infinity_fev(-infinity_body.velocity,infinity_body.position);
|
||||
match infinity_fev.crawl(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)),
|
||||
}
|
||||
infinity_fev.crawl(self,&infinity_body,Time::MIN/4,infinity_body.time).hit()
|
||||
}
|
||||
pub fn is_point_in_mesh(&self,point:Planar64Vec3)->bool{
|
||||
let infinity_body=Body::new(point,vec3::Y,vec3::ZERO,Time::ZERO);
|
||||
@ -994,7 +985,7 @@ fn is_empty_volume(normals:Vec<Vector3<Fixed<3,96>>>)->bool{
|
||||
for k in 0..len{
|
||||
if k!=i&&k!=j{
|
||||
let d=n.dot(normals[k]).is_negative();
|
||||
if let Some(comp)=&d_comp{
|
||||
if let &Some(comp)=&d_comp{
|
||||
// This is testing if d_comp*d < 0
|
||||
if comp^d{
|
||||
return true;
|
||||
|
@ -28,9 +28,9 @@ use gameplay::ModeState;
|
||||
// or the only bots which fail are ones exploiting a surgically patched bug.
|
||||
#[derive(Clone,Copy,Hash,Debug,id::Id,Eq,PartialEq,Ord,PartialOrd)]
|
||||
pub struct PhysicsVersion(u32);
|
||||
pub const VERSION:PhysicsVersion=PhysicsVersion(0);
|
||||
pub const VERSION:PhysicsVersion=PhysicsVersion(2);
|
||||
const LATEST_COMPATIBLE_VERSION:[u32;1+VERSION.0 as usize]=const{
|
||||
let compat=[0];
|
||||
let compat=[0,1,2];
|
||||
|
||||
let mut input_version=0;
|
||||
while input_version<compat.len(){
|
||||
@ -200,17 +200,17 @@ fn ground_things(walk_settings:&gameplay_style::WalkSettings,contact:&ContactCol
|
||||
let normal=contact_normal(models,hitbox_mesh,contact);
|
||||
let gravity=touching.base_acceleration(models,style,camera,input_state);
|
||||
let control_dir=style.get_y_control_dir(camera,input_state.controls);
|
||||
let mut target_velocity=walk_settings.get_walk_target_velocity(control_dir,normal);
|
||||
touching.constrain_velocity(models,hitbox_mesh,&mut target_velocity);
|
||||
(gravity,target_velocity)
|
||||
let target_velocity=walk_settings.get_walk_target_velocity(control_dir,normal);
|
||||
let target_velocity_clipped=touching.constrain_velocity(models,hitbox_mesh,target_velocity);
|
||||
(gravity,target_velocity_clipped)
|
||||
}
|
||||
fn ladder_things(ladder_settings:&gameplay_style::LadderSettings,contact:&ContactCollision,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState)->(Planar64Vec3,Planar64Vec3){
|
||||
let normal=contact_normal(models,hitbox_mesh,contact);
|
||||
let gravity=touching.base_acceleration(models,style,camera,input_state);
|
||||
let control_dir=style.get_y_control_dir(camera,input_state.controls);
|
||||
let mut target_velocity=ladder_settings.get_ladder_target_velocity(control_dir,normal);
|
||||
touching.constrain_velocity(models,hitbox_mesh,&mut target_velocity);
|
||||
(gravity,target_velocity)
|
||||
let target_velocity=ladder_settings.get_ladder_target_velocity(control_dir,normal);
|
||||
let target_velocity_clipped=touching.constrain_velocity(models,hitbox_mesh,target_velocity);
|
||||
(gravity,target_velocity_clipped)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@ -807,8 +807,8 @@ impl TouchingState{
|
||||
//TODO: add water
|
||||
a
|
||||
}
|
||||
fn constrain_velocity(&self,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,velocity:&mut Planar64Vec3){
|
||||
let contacts=self.contacts.iter().map(|contact|{
|
||||
fn constrain_velocity(&self,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,velocity:Planar64Vec3)->Planar64Vec3{
|
||||
let contacts:Vec<_>=self.contacts.iter().map(|contact|{
|
||||
let n=contact_normal(models,hitbox_mesh,contact);
|
||||
crate::push_solve::Contact{
|
||||
position:vec3::ZERO,
|
||||
@ -816,10 +816,10 @@ impl TouchingState{
|
||||
normal:n,
|
||||
}
|
||||
}).collect();
|
||||
*velocity=crate::push_solve::push_solve(&contacts,*velocity);
|
||||
crate::push_solve::push_solve(&contacts,velocity)
|
||||
}
|
||||
fn constrain_acceleration(&self,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,acceleration:&mut Planar64Vec3){
|
||||
let contacts=self.contacts.iter().map(|contact|{
|
||||
fn constrain_acceleration(&self,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,acceleration:Planar64Vec3)->Planar64Vec3{
|
||||
let contacts:Vec<_>=self.contacts.iter().map(|contact|{
|
||||
let n=contact_normal(models,hitbox_mesh,contact);
|
||||
crate::push_solve::Contact{
|
||||
position:vec3::ZERO,
|
||||
@ -827,7 +827,7 @@ impl TouchingState{
|
||||
normal:n,
|
||||
}
|
||||
}).collect();
|
||||
*acceleration=crate::push_solve::push_solve(&contacts,*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,start_time:Time){
|
||||
// let relative_body=crate::body::VirtualBody::relative(&Body::ZERO,body).body(time);
|
||||
@ -836,7 +836,7 @@ impl TouchingState{
|
||||
//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,start_time,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(
|
||||
@ -850,7 +850,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,start_time,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(
|
||||
@ -1185,9 +1185,9 @@ 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,state.time,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)|{
|
||||
.and_then(|(face,dt)|{
|
||||
// this must be rounded to avoid the infinite loop when hitting the start zone
|
||||
let time=relative_body.time+dt.into();
|
||||
(state.time<time).then_some((time,face,dt))
|
||||
@ -1303,9 +1303,8 @@ fn set_velocity_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsM
|
||||
set_velocity(body,touching,models,hitbox_mesh,v);
|
||||
culled
|
||||
}
|
||||
fn set_velocity(body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,mut v:Planar64Vec3){
|
||||
touching.constrain_velocity(models,hitbox_mesh,&mut v);
|
||||
body.velocity=v;
|
||||
fn set_velocity(body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,v:Planar64Vec3){
|
||||
body.velocity=touching.constrain_velocity(models,hitbox_mesh,v);;
|
||||
}
|
||||
fn set_acceleration_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,a:Planar64Vec3)->bool{
|
||||
//This is not correct but is better than what I have
|
||||
@ -1321,9 +1320,8 @@ fn set_acceleration_cull(body:&mut Body,touching:&mut TouchingState,models:&Phys
|
||||
set_acceleration(body,touching,models,hitbox_mesh,a);
|
||||
culled
|
||||
}
|
||||
fn set_acceleration(body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,mut a:Planar64Vec3){
|
||||
touching.constrain_acceleration(models,hitbox_mesh,&mut a);
|
||||
body.acceleration=a;
|
||||
fn set_acceleration(body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,a:Planar64Vec3){
|
||||
body.acceleration=touching.constrain_acceleration(models,hitbox_mesh,a);
|
||||
}
|
||||
|
||||
fn teleport(
|
||||
@ -1562,6 +1560,21 @@ fn collision_start_contact(
|
||||
}
|
||||
},
|
||||
}
|
||||
match &attr.general.trajectory{
|
||||
Some(trajectory)=>{
|
||||
match trajectory{
|
||||
gameplay_attributes::SetTrajectory::AirTime(_)=>todo!(),
|
||||
gameplay_attributes::SetTrajectory::Height(_)=>todo!(),
|
||||
gameplay_attributes::SetTrajectory::TargetPointTime{..}=>todo!(),
|
||||
gameplay_attributes::SetTrajectory::TargetPointSpeed{..}=>todo!(),
|
||||
&gameplay_attributes::SetTrajectory::Velocity(velocity)=>{
|
||||
move_state.cull_velocity(velocity,body,touching,models,hitbox_mesh,style,camera,input_state);
|
||||
},
|
||||
gameplay_attributes::SetTrajectory::DotVelocity{..}=>todo!(),
|
||||
}
|
||||
},
|
||||
None=>(),
|
||||
}
|
||||
//I love making functions with 10 arguments to dodge the borrow checker
|
||||
if allow_run_teleport_behaviour{
|
||||
run_teleport_behaviour(model_id,attr.general.wormhole.as_ref(),mode,move_state,body,touching,run,mode_state,models,hitbox_mesh,bvh,style,camera,input_state,time);
|
||||
@ -1589,21 +1602,6 @@ fn collision_start_contact(
|
||||
}
|
||||
}
|
||||
}
|
||||
match &attr.general.trajectory{
|
||||
Some(trajectory)=>{
|
||||
match trajectory{
|
||||
gameplay_attributes::SetTrajectory::AirTime(_)=>todo!(),
|
||||
gameplay_attributes::SetTrajectory::Height(_)=>todo!(),
|
||||
gameplay_attributes::SetTrajectory::TargetPointTime { target_point: _, time: _ }=>todo!(),
|
||||
gameplay_attributes::SetTrajectory::TargetPointSpeed { target_point: _, speed: _, trajectory_choice: _ }=>todo!(),
|
||||
&gameplay_attributes::SetTrajectory::Velocity(velocity)=>{
|
||||
move_state.cull_velocity(velocity,body,touching,models,hitbox_mesh,style,camera,input_state);
|
||||
},
|
||||
gameplay_attributes::SetTrajectory::DotVelocity { direction: _, dot: _ }=>todo!(),
|
||||
}
|
||||
},
|
||||
None=>(),
|
||||
}
|
||||
//doing enum to set the acceleration when surfing
|
||||
//doing input_and_body to refresh the walk state if you hit a wall while accelerating
|
||||
move_state.apply_enum_and_input_and_body(body,touching,models,hitbox_mesh,style,camera,input_state);
|
||||
@ -1845,7 +1843,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
|
||||
let jump_dir=walk_state.jump_direction.direction(&data.models,&data.hitbox_mesh,&walk_state.contact);
|
||||
let booster_option=data.models.contact_attr(walk_state.contact.model_id).general.booster.as_ref();
|
||||
let jumped_velocity=jump_settings.jumped_velocity(&state.style,jump_dir,state.body.velocity,booster_option);
|
||||
state.cull_velocity(&data,jumped_velocity);
|
||||
state.cull_velocity(data,jumped_velocity);
|
||||
}
|
||||
}
|
||||
b_refresh_walk_target=false;
|
||||
@ -1924,7 +1922,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::ZERO,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>){
|
||||
@ -1942,7 +1940,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::ZERO,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>){
|
||||
@ -2267,7 +2265,7 @@ mod test{
|
||||
// spawn threads
|
||||
println!("spawning up to {thread_limit} threads...");
|
||||
let mut active_thread_count=0;
|
||||
for _ in 0..thread_limit{
|
||||
while active_thread_count<thread_limit{
|
||||
if let Some(dir_entry_result)=read_dir.next(){
|
||||
if let Some(file_path)=get_file_path(dir_entry_result?)?{
|
||||
active_thread_count+=1;
|
||||
|
@ -289,7 +289,7 @@ fn get_best_push_ray_and_conts<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
fn get_first_touch<'a>(contacts:&'a Vec<Contact>,ray:&Ray,conts:&Conts)->Option<(Ratio<Fixed<2,64>,Fixed<2,64>>,&'a Contact)>{
|
||||
fn get_first_touch<'a>(contacts:&'a [Contact],ray:&Ray,conts:&Conts)->Option<(Ratio<Fixed<2,64>,Fixed<2,64>>,&'a Contact)>{
|
||||
contacts.iter()
|
||||
.filter(|&contact|
|
||||
!conts.iter().any(|&c|std::ptr::eq(c,contact))
|
||||
@ -299,7 +299,7 @@ fn get_first_touch<'a>(contacts:&'a Vec<Contact>,ray:&Ray,conts:&Conts)->Option<
|
||||
.min_by_key(|&(t,_)|t)
|
||||
}
|
||||
|
||||
pub fn push_solve(contacts:&Vec<Contact>,point:Planar64Vec3)->Planar64Vec3{
|
||||
pub fn push_solve(contacts:&[Contact],point:Planar64Vec3)->Planar64Vec3{
|
||||
let (mut ray,mut conts)=get_best_push_ray_and_conts_0(point);
|
||||
loop{
|
||||
let (next_t,next_cont)=match get_first_touch(contacts,&ray,&conts){
|
||||
|
Reference in New Issue
Block a user