improve seek algorithmic complexity O(n) -> O(log(n))

This commit is contained in:
2026-02-27 07:05:23 -08:00
parent c3cca22839
commit 197f840246
7 changed files with 73 additions and 34 deletions

4
Cargo.lock generated
View File

@@ -1661,9 +1661,9 @@ dependencies = [
[[package]] [[package]]
name = "strafesnet_roblox_bot_file" name = "strafesnet_roblox_bot_file"
version = "0.9.0" version = "0.9.2"
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
checksum = "3ee6a8c592794145fdbbb2fbdaedbbc5813373e2e2bbbb9bac6ab7944775cc0a" checksum = "f3764f94fb71eba824aeabde808b490ef719331673f3f485c8b176895e4955dd"
dependencies = [ dependencies = [
"binrw", "binrw",
"bitflags 2.10.0", "bitflags 2.10.0",

View File

@@ -14,5 +14,5 @@ codegen-units = 1
[workspace.dependencies] [workspace.dependencies]
strafesnet_common = { version = "0.8.3", registry = "strafesnet" } strafesnet_common = { version = "0.8.3", registry = "strafesnet" }
strafesnet_graphics = { version = "0.0.2", registry = "strafesnet" } strafesnet_graphics = { version = "0.0.2", registry = "strafesnet" }
strafesnet_roblox_bot_file = { version = "0.9.0", registry = "strafesnet" } strafesnet_roblox_bot_file = { version = "0.9.2", registry = "strafesnet" }
strafesnet_snf = { version = "0.3.2", registry = "strafesnet" } strafesnet_snf = { version = "0.3.2", registry = "strafesnet" }

View File

@@ -41,24 +41,35 @@ impl PlaybackHead{
pub fn time(&self,time:SessionTime)->Time{ pub fn time(&self,time:SessionTime)->Time{
self.timer.time(time) self.timer.time(time)
} }
pub fn set_paused(&mut self,time:SessionTime,paused:bool){
_=self.timer.set_paused(time,paused);
}
pub fn set_time(&mut self,bot:&CompleteBot,time:SessionTime,new_time:Time){
self.timer.set_time(time,new_time);
// reset head
self.head=Head::after_time(bot.timelines(),bot.time(new_time).into());
// nudge indices as a hack to avoid oob index
if self.head.get_event_index(EventType::Output)==0{
self.head.push(EventType::Output);
}
if self.head.get_event_index(EventType::Output)==bot.timelines().output_events.len(){
self.head.set_event_index(EventType::Output,bot.timelines().output_events.len()-1);
}
self.state=PlaybackState::new();
self.state.process_head(bot.timelines(),&self.head);
}
pub fn set_scale(&mut self,time:SessionTime,new_scale:strafesnet_common::integer::Ratio64){
self.timer.set_scale(time,new_scale);
}
pub fn next_event(&self,bot:&CompleteBot)->Option<Timed<EventType>>{ pub fn next_event(&self,bot:&CompleteBot)->Option<Timed<EventType>>{
self.head.next_event(bot.timelines()) self.head.next_event(bot.timelines())
} }
pub fn process_event(&mut self,bot:&CompleteBot,event_type:EventType){ pub fn process_event(&mut self,bot:&CompleteBot,event_type:EventType){
self.state.process_event(bot,event_type,self.head.get_event_index(event_type)); self.state.process_event(bot.timelines(),event_type,self.head.get_event_index(event_type));
self.head.push(event_type); self.head.push(event_type);
} }
pub fn set_paused(&mut self,time:SessionTime,paused:bool){
_=self.timer.set_paused(time,paused);
}
pub fn set_time(&mut self,time:SessionTime,new_time:Time){
self.timer.set_time(time,new_time);
// reset head
self.head=HEAD_NO_CRASH;
}
pub fn set_scale(&mut self,time:SessionTime,new_scale:strafesnet_common::integer::Ratio64){
self.timer.set_scale(time,new_scale);
}
pub fn advance_time(&mut self,bot:&CompleteBot,time:SessionTime){ pub fn advance_time(&mut self,bot:&CompleteBot,time:SessionTime){
let mut simulation_time=bot.time(self.time(time)); let mut simulation_time=bot.time(self.time(time));
let mut time_float=simulation_time.into(); let mut time_float=simulation_time.into();
@@ -74,6 +85,7 @@ impl PlaybackHead{
None=>{ None=>{
//reset playback //reset playback
self.head=HEAD_NO_CRASH; self.head=HEAD_NO_CRASH;
self.state=PlaybackState::new();
// hack to wind back timer offset without precise session timestamp // hack to wind back timer offset without precise session timestamp
let (mut state,paused)=self.timer.clone().into_state(); let (mut state,paused)=self.timer.clone().into_state();

View File

@@ -4,8 +4,6 @@ use strafesnet_common::run;
use strafesnet_common::physics::Time as PhysicsTime; use strafesnet_common::physics::Time as PhysicsTime;
use strafesnet_roblox_bot_file::v0; use strafesnet_roblox_bot_file::v0;
use crate::bot::CompleteBot;
pub struct Run{ pub struct Run{
run:run::RunState, run:run::RunState,
flag_reason:Option<v0::FlagReason>, flag_reason:Option<v0::FlagReason>,
@@ -195,16 +193,45 @@ impl PlaybackState{
}, },
} }
} }
pub(crate) fn process_event(&mut self,bot:&CompleteBot,event_type:v0::EventType,event_index:usize){ pub(crate) fn process_head(&mut self,block:&v0::Block,head:&v0::Head){
// The whole point of this is to avoid running the realtime events!
/*
for event in &block.input_events[0..head.get_event_index(v0::EventType::Input)]{
self.push_input(&event.event);
}
for event in &block.output_events[0..head.get_event_index(v0::EventType::Output)]{
self.push_output(&event.event);
}
for event in &bot.sound_events[0..head.get_event_index(v0::EventType::Sound)]{
self.push_sound(&event.event);
}
*/
// for event in &bot.world_events[0..head.get_event_index(v0::EventType::World)]{
// self.push_world(&event.event);
// }
for event in &block.gravity_events[0..head.get_event_index(v0::EventType::Gravity)]{
self.push_gravity(&event.event);
}
for event in &block.run_events[0..head.get_event_index(v0::EventType::Run)]{
self.push_run(event);
}
// for event in &bot.camera_events[0..head.get_event_index(v0::EventType::Camera)]{
// self.push_camera(&event.event);
// }
for event in &block.setting_events[0..head.get_event_index(v0::EventType::Setting)]{
self.push_setting(&event.event);
}
}
pub(crate) fn process_event(&mut self,block:&v0::Block,event_type:v0::EventType,event_index:usize){
match event_type{ match event_type{
v0::EventType::Input=>self.push_input(&bot.timelines().input_events[event_index].event), v0::EventType::Input=>self.push_input(&block.input_events[event_index].event),
v0::EventType::Output=>self.push_output(&bot.timelines().output_events[event_index].event), v0::EventType::Output=>self.push_output(&block.output_events[event_index].event),
v0::EventType::Sound=>{}, v0::EventType::Sound=>{},
v0::EventType::World=>{}, v0::EventType::World=>{},
v0::EventType::Gravity=>self.push_gravity(&bot.timelines().gravity_events[event_index].event), v0::EventType::Gravity=>self.push_gravity(&block.gravity_events[event_index].event),
v0::EventType::Run=>self.push_run(&bot.timelines().run_events[event_index]), v0::EventType::Run=>self.push_run(&block.run_events[event_index]),
v0::EventType::Camera=>{}, v0::EventType::Camera=>{},
v0::EventType::Setting=>self.push_setting(&bot.timelines().setting_events[event_index].event), v0::EventType::Setting=>self.push_setting(&block.setting_events[event_index].event),
} }
} }
pub fn get_fov_y(&self)->f64{ pub fn get_fov_y(&self)->f64{

View File

@@ -53,16 +53,16 @@ impl<'a> PlayerWorker<'a>{
Instruction::SessionControl(SessionControlInstruction::SetPaused(paused))=>{ Instruction::SessionControl(SessionControlInstruction::SetPaused(paused))=>{
self.playback_head.set_paused(ins.time,paused); self.playback_head.set_paused(ins.time,paused);
}, },
Instruction::SessionControl(SessionControlInstruction::Restart)=>{ Instruction::SessionControl(SessionControlInstruction::Restart)=>if let Some(bot)=&self.bot{
self.playback_head.set_time(ins.time,PlaybackTime::ZERO); self.playback_head.set_time(bot,ins.time,PlaybackTime::ZERO);
}, },
Instruction::SessionControl(SessionControlInstruction::SkipForward)=>{ Instruction::SessionControl(SessionControlInstruction::SkipForward)=>if let Some(bot)=&self.bot{
let head_time=self.playback_head.time(ins.time); let head_time=self.playback_head.time(ins.time);
self.playback_head.set_time(ins.time,head_time+PlaybackTime::from_secs(2)); self.playback_head.set_time(bot,ins.time,head_time+PlaybackTime::from_secs(2));
}, },
Instruction::SessionControl(SessionControlInstruction::SkipBack)=>{ Instruction::SessionControl(SessionControlInstruction::SkipBack)=>if let Some(bot)=&self.bot{
let head_time=self.playback_head.time(ins.time); let head_time=self.playback_head.time(ins.time);
self.playback_head.set_time(ins.time,head_time-PlaybackTime::from_secs(2)); self.playback_head.set_time(bot,ins.time,head_time-PlaybackTime::from_secs(2));
}, },
Instruction::SessionControl(SessionControlInstruction::DecreaseTimescale)=>{ Instruction::SessionControl(SessionControlInstruction::DecreaseTimescale)=>{
self.playback_speed=self.playback_speed.saturating_sub(1).max(-27); self.playback_speed=self.playback_speed.saturating_sub(1).max(-27);

View File

@@ -134,10 +134,10 @@ impl PlaybackHead{
} }
/// Set the playback head position to new_time. /// Set the playback head position to new_time.
#[wasm_bindgen] #[wasm_bindgen]
pub fn set_head_time(&mut self,time:f64,new_time:f64){ pub fn set_head_time(&mut self,bot:&CompleteBot,time:f64,new_time:f64){
let time=time::from_float(time).unwrap(); let time=time::from_float(time).unwrap();
let new_time=time::from_float(new_time).unwrap(); let new_time=time::from_float(new_time).unwrap();
self.head.set_time(time,new_time); self.head.set_time(&bot.bot,time,new_time);
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn get_run_time(&self,bot:&CompleteBot,time:f64,mode_id:u32)->Option<f64>{ pub fn get_run_time(&self,bot:&CompleteBot,time:f64,mode_id:u32)->Option<f64>{

View File

@@ -56,7 +56,7 @@ function set_scale(new_scale) {
// Controls // Controls
document.getElementById("control_reset").addEventListener("click", (e) => { document.getElementById("control_reset").addEventListener("click", (e) => {
playback.set_head_time(elapsed(), 0.0); playback.set_head_time(bot, elapsed(), 0.0);
}); });
document.getElementById("control_pause").addEventListener("click", (e) => { document.getElementById("control_pause").addEventListener("click", (e) => {
paused = !paused; paused = !paused;
@@ -65,12 +65,12 @@ document.getElementById("control_pause").addEventListener("click", (e) => {
document.getElementById("control_forward").addEventListener("click", (e) => { document.getElementById("control_forward").addEventListener("click", (e) => {
const time_now = elapsed(); const time_now = elapsed();
const playback_time = playback.get_head_time(time_now); const playback_time = playback.get_head_time(time_now);
playback.set_head_time(time_now, playback_time + 2.0); playback.set_head_time(bot, time_now, playback_time + 2.0);
}); });
document.getElementById("control_backward").addEventListener("click", (e) => { document.getElementById("control_backward").addEventListener("click", (e) => {
const time_now = elapsed(); const time_now = elapsed();
const playback_time = playback.get_head_time(time_now); const playback_time = playback.get_head_time(time_now);
playback.set_head_time(time_now, playback_time - 2.0); playback.set_head_time(bot, time_now, playback_time - 2.0);
}); });
document.getElementById("control_slower").addEventListener("click", (e) => { document.getElementById("control_slower").addEventListener("click", (e) => {
set_scale((scale * 4) / 5); set_scale((scale * 4) / 5);