From 102dd7fa6fa86a64f9c08ef2a930859bbc6c2d1e Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 17 Mar 2026 11:19:33 -0700 Subject: [PATCH] improve closest_time_to_point accuracy --- lib/src/bvh.rs | 98 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 82 insertions(+), 16 deletions(-) diff --git a/lib/src/bvh.rs b/lib/src/bvh.rs index d7c5acc..14a0ec9 100644 --- a/lib/src/bvh.rs +++ b/lib/src/bvh.rs @@ -2,12 +2,16 @@ use core::ops::Range; use strafesnet_common::aabb::Aabb; use strafesnet_common::bvh::generate_bvh; use strafesnet_common::integer::vec3; -use strafesnet_common::integer::Fixed; +use strafesnet_common::integer::{Fixed,Planar64}; use strafesnet_common::physics::Time as PhysicsTime; use crate::bot::CompleteBot; +use strafesnet_roblox_bot_file::v0; const MAX_SLICE_LEN:usize=16; -struct EventSlice(Range); +struct EventSlice{ + slice:Range, + inclusive:bool, +} pub struct Bvh{ bvh:strafesnet_common::bvh::BvhNode, @@ -40,19 +44,23 @@ impl Bvh{ // 0123456789 // split into groups of MAX_SLICE_LEN=4 // [0123][4567][89] - let mut push_slice=|slice:Range|{ + let mut push_slice=|slice:Range,inclusive:bool|{ let mut aabb=Aabb::default(); for event in &output_events[slice.start..slice.end]{ aabb.grow(vec3::try_from_f32_array([event.event.position.x,event.event.position.y,event.event.position.z]).unwrap()); } - bvh_nodes.push((EventSlice(slice),aabb)); + if inclusive{ + let event=&output_events[slice.end]; + aabb.grow(vec3::try_from_f32_array([event.event.position.x,event.event.position.y,event.event.position.z]).unwrap()); + } + bvh_nodes.push((EventSlice{slice,inclusive},aabb)); }; // push fixed-size groups for i in 0..count-1{ - push_slice((last_index+i*slice_len)..(last_index+(i+1)*slice_len)); + push_slice((last_index+i*slice_len)..(last_index+(i+1)*slice_len),true); } // push last group which may be shorter - push_slice((last_index+(count-1)*slice_len)..index); + push_slice((last_index+(count-1)*slice_len)..index,false); last_index=index; }; // find discontinuities (teleports) and avoid forming a bvh node across them @@ -66,31 +74,89 @@ impl Bvh{ Self{bvh} } /// Find the exact timestamp on the bot timeline that is closest to the given point. - pub fn closest_time_to_point(&self,bot:&CompleteBot,point:glam::Vec3)->Option{ + pub fn closest_time_to_point<'a>(&self,bot:&'a CompleteBot,point:glam::Vec3)->Option{ let point=point+bot.world_offset(); let start_point=vec3::try_from_f32_array(point.to_array()).unwrap(); let output_events=&bot.timelines().output_events; // grow a sphere starting at start_point until we find the closest point on the bot output events - let intersect_leaf=|EventSlice(slice):&EventSlice|{ + let intersect_leaf=|event_slice:&EventSlice|{ // calculate the distance to the leaf contents - output_events[slice.start..slice.end].iter().map(|event|{ + let mut best_distance=output_events[event_slice.slice.start..event_slice.slice.end].iter().map(|event|{ let p=event.event.position; let p=vec3::try_from_f32_array([p.x,p.y,p.z]).unwrap(); (start_point-p).length_squared() - }).min() + }).min()?; + let mut prev_event=&output_events[event_slice.slice.start]; + let mut f=|event:&'a v0::Timed|{ + let p0=vec3::try_from_f32_array([prev_event.event.position.x,prev_event.event.position.y,prev_event.event.position.z]).unwrap(); + let p1=vec3::try_from_f32_array([event.event.position.x,event.event.position.y,event.event.position.z]).unwrap(); + let d=p1-p0; + let d0=p0.dot(d); + let d1=p1.dot(d); + let sp_d=start_point.dot(d); + // must be on the segment + if d0|{ + let p0=vec3::try_from_f32_array([prev_event.event.position.x,prev_event.event.position.y,prev_event.event.position.z]).unwrap(); + let p1=vec3::try_from_f32_array([event.event.position.x,event.event.position.y,event.event.position.z]).unwrap(); + let d=p1-p0; + let d0=p0.dot(d); + let d1=p1.dot(d); + let sp_d=start_point.dot(d); + // must be on the segment + if d0