use glam::Vec3Swizzles; use strafesnet_common::timer::{Scaled,Timer,TimerState}; use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner}; use strafesnet_roblox_bot_file::v0::{EventType,Head,Timed}; use crate::bot::CompleteBot; use crate::state::PlaybackState; fn vector3_to_glam(v:&strafesnet_roblox_bot_file::v0::Vector3)->glam::Vec3{ glam::vec3(v.x,v.y,v.z) } #[derive(Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd,Debug)] pub enum TimeInner{} pub type Time=strafesnet_common::integer::Time; /// A playback context. Advance time and then generate a camera position to pass to the renderer. pub struct PlaybackHead{ head:Head, timer:Timer>, state:PlaybackState, } impl PlaybackHead{ pub fn new(bot:&CompleteBot,time:SessionTime)->Self{ let timer=Timer::unpaused(time,Time::ZERO); let head=Head::after_time(bot.timelines(),bot.time(Time::ZERO).into()); let mut state=PlaybackState::new(); state.process_head(bot.timelines(),&head); Self{ head, timer, state, } } pub const fn state(&self)->&PlaybackState{ &self.state } pub fn time(&self,time:SessionTime)->Time{ self.timer.time(time) } pub fn timer(&self)->&Timer>{ &self.timer } 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){ let new_time=new_time.rem_euclid(bot.duration().coerce()); self.timer.set_time(time,new_time); // reset head self.head=Head::after_time(bot.timelines(),bot.time(new_time).into()); self.state=PlaybackState::new(); self.state.process_head(bot.timelines(),&self.head); } pub fn get_scale(&self)->strafesnet_common::integer::Ratio64{ self.timer.get_scale() } 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>{ self.head.next_event(bot.timelines()) } pub fn process_event(&mut self,bot:&CompleteBot,event_type:EventType){ self.state.process_event(bot.timelines(),event_type,self.head.get_event_index(event_type)); self.head.push(event_type); } pub fn advance_time(&mut self,bot:&CompleteBot,time:SessionTime){ let mut simulation_time=bot.time(self.time(time)); let mut time_float=simulation_time.into(); loop{ match self.next_event(bot){ Some(next_event)=>{ if next_event.time{ //reset playback self.head=Head::after_time(bot.timelines(),bot.time(Time::ZERO).into()); self.state=PlaybackState::new(); self.state.process_head(bot.timelines(),&self.head); // hack to wind back timer offset without precise session timestamp let (mut state,paused)=self.timer.clone().into_state(); let offset=state.get_offset()-bot.duration().coerce(); state.set_offset(offset); self.timer=Timer::from_state(state,paused); // update loop variables simulation_time-=bot.duration(); time_float=simulation_time.into(); }, } } } fn interpolate_output<'a>(&self,bot:&'a CompleteBot,time:SessionTime)->InterpolateOutput<'a>{ let time=bot.time(self.time(time)); let event0=&bot.timelines().output_events[self.head.get_event_index(EventType::Output)-1]; let event1=&bot.timelines().output_events[self.head.get_event_index(EventType::Output)]; let t0=event0.time; let t1=event1.time; let time_float:f64=time.into(); let t=((time_float-t0)/(t1-t0)) as f32; InterpolateOutput{ event0:&event0.event, event1:&event1.event, t:t, } } pub fn get_position_angles(&self,bot:&CompleteBot,time:SessionTime)->(glam::Vec3,glam::Vec2){ let interp=self.interpolate_output(bot,time); let p=interp.position(); let a=interp.angles(); (p-bot.world_offset()+CompleteBot::CAMERA_OFFSET,a.yx()) } pub fn get_position(&self,bot:&CompleteBot,time:SessionTime)->glam::Vec3{ let interp=self.interpolate_output(bot,time); interp.position() } pub fn get_velocity(&self,bot:&CompleteBot,time:SessionTime)->glam::Vec3{ let interp=self.interpolate_output(bot,time); interp.velocity() } pub fn get_angles(&self,bot:&CompleteBot,time:SessionTime)->glam::Vec3{ let interp=self.interpolate_output(bot,time); interp.angles() } } struct InterpolateOutput<'a>{ event0:&'a strafesnet_roblox_bot_file::v0::OutputEvent, event1:&'a strafesnet_roblox_bot_file::v0::OutputEvent, t:f32, } impl InterpolateOutput<'_>{ fn position(&self)->glam::Vec3{ let p0=vector3_to_glam(&self.event0.position); let p1=vector3_to_glam(&self.event1.position); p0.lerp(p1,self.t) } fn velocity(&self)->glam::Vec3{ let v0=vector3_to_glam(&self.event0.velocity); let v1=vector3_to_glam(&self.event1.velocity); v0.lerp(v1,self.t) } fn angles(&self)->glam::Vec3{ let a0=vector3_to_glam(&self.event0.angles); let a1=vector3_to_glam(&self.event1.angles); a0.lerp(a1,self.t) } }