introduce PlaybackTime to abstract bot file timestamps
This commit is contained in:
@@ -1,11 +1,14 @@
|
|||||||
|
use strafesnet_common::timer::{TimerFixed,Realtime,Unpaused};
|
||||||
|
use strafesnet_common::physics::{Time as PhysicsTime,TimeInner as PhysicsTimeInner};
|
||||||
use strafesnet_roblox_bot_file::v0;
|
use strafesnet_roblox_bot_file::v0;
|
||||||
use strafesnet_common::physics::{Time as PhysicsTime};
|
|
||||||
|
use crate::head::{Time as PlaybackTime,TimeInner as PlaybackTimeInner};
|
||||||
|
|
||||||
/// A loaded bot file.
|
/// A loaded bot file.
|
||||||
pub struct CompleteBot{
|
pub struct CompleteBot{
|
||||||
//Instructions
|
//Instructions
|
||||||
timelines:v0::Block,
|
timelines:v0::Block,
|
||||||
time_base:PhysicsTime,
|
timer:TimerFixed<Realtime<PlaybackTimeInner,PhysicsTimeInner>,Unpaused>,
|
||||||
duration:PhysicsTime,
|
duration:PhysicsTime,
|
||||||
}
|
}
|
||||||
impl CompleteBot{
|
impl CompleteBot{
|
||||||
@@ -13,16 +16,16 @@ impl CompleteBot{
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
timelines:v0::Block,
|
timelines:v0::Block,
|
||||||
)->Self{
|
)->Self{
|
||||||
let first=timelines.output_events.first().unwrap();
|
let start=crate::time::from_float(timelines.output_events.first().unwrap().time).unwrap();
|
||||||
let last=timelines.output_events.last().unwrap();
|
let end=crate::time::from_float(timelines.output_events.last().unwrap().time).unwrap();
|
||||||
Self{
|
Self{
|
||||||
time_base:crate::time::from_float(first.time).unwrap(),
|
timer:TimerFixed::new(PlaybackTime::ZERO,start),
|
||||||
duration:crate::time::from_float(last.time-first.time).unwrap(),
|
duration:end-start,
|
||||||
timelines,
|
timelines,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub const fn time_base(&self)->PhysicsTime{
|
pub fn time(&self,time:PlaybackTime)->PhysicsTime{
|
||||||
self.time_base
|
self.timer.time(time)
|
||||||
}
|
}
|
||||||
pub const fn duration(&self)->PhysicsTime{
|
pub const fn duration(&self)->PhysicsTime{
|
||||||
self.duration
|
self.duration
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use glam::Vec3Swizzles;
|
use glam::Vec3Swizzles;
|
||||||
use strafesnet_common::timer::{Scaled,Timer,TimerState};
|
use strafesnet_common::timer::{Scaled,Timer,TimerState};
|
||||||
use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner};
|
use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner};
|
||||||
use strafesnet_common::physics::{Time as PhysicsTime,TimeInner as PhysicsTimeInner};
|
use strafesnet_common::physics::{Time as PhysicsTime};
|
||||||
use strafesnet_roblox_bot_file::v0::{EventType,Head,Timed};
|
use strafesnet_roblox_bot_file::v0::{EventType,Head,Timed};
|
||||||
|
|
||||||
use crate::bot::CompleteBot;
|
use crate::bot::CompleteBot;
|
||||||
@@ -11,11 +11,14 @@ fn vector3_to_glam(v:&strafesnet_roblox_bot_file::v0::Vector3)->glam::Vec3{
|
|||||||
glam::vec3(v.x,v.y,v.z)
|
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<TimeInner>;
|
||||||
|
|
||||||
/// A playback context. Advance time and then generate a camera position to pass to the renderer.
|
/// A playback context. Advance time and then generate a camera position to pass to the renderer.
|
||||||
pub struct PlaybackHead{
|
pub struct PlaybackHead{
|
||||||
head:Head,
|
head:Head,
|
||||||
loop_offset:PhysicsTime,
|
timer:Timer<Scaled<SessionTimeInner,TimeInner>>,
|
||||||
timer:Timer<Scaled<SessionTimeInner,PhysicsTimeInner>>,
|
|
||||||
state:PlaybackState,
|
state:PlaybackState,
|
||||||
}
|
}
|
||||||
const HEAD_NO_CRASH:Head={
|
const HEAD_NO_CRASH:Head={
|
||||||
@@ -26,10 +29,9 @@ const HEAD_NO_CRASH:Head={
|
|||||||
};
|
};
|
||||||
impl PlaybackHead{
|
impl PlaybackHead{
|
||||||
pub fn new(time:SessionTime)->Self{
|
pub fn new(time:SessionTime)->Self{
|
||||||
let timer=Timer::unpaused(time,PhysicsTime::ZERO);
|
let timer=Timer::unpaused(time,Time::ZERO);
|
||||||
Self{
|
Self{
|
||||||
head:HEAD_NO_CRASH,
|
head:HEAD_NO_CRASH,
|
||||||
loop_offset:PhysicsTime::ZERO,
|
|
||||||
timer,
|
timer,
|
||||||
state:PlaybackState::new(),
|
state:PlaybackState::new(),
|
||||||
}
|
}
|
||||||
@@ -37,8 +39,8 @@ impl PlaybackHead{
|
|||||||
pub const fn state(&self)->&PlaybackState{
|
pub const fn state(&self)->&PlaybackState{
|
||||||
&self.state
|
&self.state
|
||||||
}
|
}
|
||||||
pub fn time(&self,bot:&CompleteBot,time:SessionTime)->PhysicsTime{
|
pub fn time(&self,time:SessionTime)->Time{
|
||||||
bot.time_base()+self.timer.time(time)+self.loop_offset
|
self.timer.time(time)
|
||||||
}
|
}
|
||||||
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())
|
||||||
@@ -50,31 +52,16 @@ impl PlaybackHead{
|
|||||||
pub fn set_paused(&mut self,time:SessionTime,paused:bool){
|
pub fn set_paused(&mut self,time:SessionTime,paused:bool){
|
||||||
_=self.timer.set_paused(time,paused);
|
_=self.timer.set_paused(time,paused);
|
||||||
}
|
}
|
||||||
pub fn seek_to(&mut self,time:SessionTime,new_time:PhysicsTime){
|
pub fn set_time(&mut self,time:SessionTime,new_time:Time){
|
||||||
self.timer.set_time(time,new_time);
|
self.timer.set_time(time,new_time);
|
||||||
self.loop_offset=PhysicsTime::ZERO;
|
|
||||||
// reset head
|
// reset head
|
||||||
self.head=HEAD_NO_CRASH;
|
self.head=HEAD_NO_CRASH;
|
||||||
}
|
}
|
||||||
pub fn seek_backward(&mut self,time_offset:SessionTime){
|
|
||||||
let (mut state,paused)=self.timer.clone().into_state();
|
|
||||||
let offset=state.get_time(-time_offset).coerce();
|
|
||||||
state.set_offset(offset);
|
|
||||||
self.timer=Timer::from_state(state,paused);
|
|
||||||
// reset head
|
|
||||||
self.head=HEAD_NO_CRASH;
|
|
||||||
}
|
|
||||||
pub fn seek_forward(&mut self,time_offset:SessionTime){
|
|
||||||
let (mut state,paused)=self.timer.clone().into_state();
|
|
||||||
let offset=state.get_time(time_offset).coerce();
|
|
||||||
state.set_offset(offset);
|
|
||||||
self.timer=Timer::from_state(state,paused);
|
|
||||||
}
|
|
||||||
pub fn set_scale(&mut self,time:SessionTime,new_scale:strafesnet_common::integer::Ratio64){
|
pub fn set_scale(&mut self,time:SessionTime,new_scale:strafesnet_common::integer::Ratio64){
|
||||||
self.timer.set_scale(time,new_scale);
|
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=self.time(bot,time);
|
let mut simulation_time=bot.time(self.time(time));
|
||||||
let mut time_float=simulation_time.get() as f64/PhysicsTime::ONE_SECOND.get() as f64;
|
let mut time_float=simulation_time.get() as f64/PhysicsTime::ONE_SECOND.get() as f64;
|
||||||
loop{
|
loop{
|
||||||
match self.next_event(bot){
|
match self.next_event(bot){
|
||||||
@@ -88,7 +75,14 @@ impl PlaybackHead{
|
|||||||
None=>{
|
None=>{
|
||||||
//reset playback
|
//reset playback
|
||||||
self.head=HEAD_NO_CRASH;
|
self.head=HEAD_NO_CRASH;
|
||||||
self.loop_offset-=bot.duration();
|
|
||||||
|
// 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();
|
simulation_time-=bot.duration();
|
||||||
time_float=simulation_time.get() as f64/PhysicsTime::ONE_SECOND.get() as f64;
|
time_float=simulation_time.get() as f64/PhysicsTime::ONE_SECOND.get() as f64;
|
||||||
},
|
},
|
||||||
@@ -96,7 +90,7 @@ impl PlaybackHead{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_position_angles(&self,bot:&CompleteBot,time:SessionTime)->(glam::Vec3,glam::Vec2){
|
pub fn get_position_angles(&self,bot:&CompleteBot,time:SessionTime)->(glam::Vec3,glam::Vec2){
|
||||||
let time=self.time(bot,time);
|
let time=bot.time(self.time(time));
|
||||||
let event0=&bot.timelines().output_events[self.head.get_event_index(EventType::Output)-1];
|
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 event1=&bot.timelines().output_events[self.head.get_event_index(EventType::Output)];
|
||||||
let p0=vector3_to_glam(&event0.event.position);
|
let p0=vector3_to_glam(&event0.event.position);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use strafesnet_common::instruction::TimedInstruction;
|
use strafesnet_common::instruction::TimedInstruction;
|
||||||
use strafesnet_common::session::Time as SessionTime;
|
use strafesnet_common::session::Time as SessionTime;
|
||||||
use strafesnet_common::physics::Time as PhysicsTime;
|
use strafesnet_roblox_bot_player::{bot::CompleteBot,graphics::Graphics,head::{PlaybackHead,Time as PlaybackTime}};
|
||||||
use strafesnet_roblox_bot_player::{bot::CompleteBot,graphics::Graphics,head::PlaybackHead};
|
|
||||||
|
|
||||||
pub enum SessionControlInstruction{
|
pub enum SessionControlInstruction{
|
||||||
SetPaused(bool),
|
SetPaused(bool),
|
||||||
@@ -55,13 +54,15 @@ impl<'a> PlayerWorker<'a>{
|
|||||||
self.playback_head.set_paused(ins.time,paused);
|
self.playback_head.set_paused(ins.time,paused);
|
||||||
},
|
},
|
||||||
Instruction::SessionControl(SessionControlInstruction::Restart)=>{
|
Instruction::SessionControl(SessionControlInstruction::Restart)=>{
|
||||||
self.playback_head.seek_to(ins.time,PhysicsTime::ZERO);
|
self.playback_head.set_time(ins.time,PlaybackTime::ZERO);
|
||||||
},
|
},
|
||||||
Instruction::SessionControl(SessionControlInstruction::SkipForward)=>{
|
Instruction::SessionControl(SessionControlInstruction::SkipForward)=>{
|
||||||
self.playback_head.seek_forward(SessionTime::from_secs(2));
|
let head_time=self.playback_head.time(ins.time);
|
||||||
|
self.playback_head.set_time(ins.time,head_time+PlaybackTime::from_secs(2));
|
||||||
},
|
},
|
||||||
Instruction::SessionControl(SessionControlInstruction::SkipBack)=>{
|
Instruction::SessionControl(SessionControlInstruction::SkipBack)=>{
|
||||||
self.playback_head.seek_backward(SessionTime::from_secs(2));
|
let head_time=self.playback_head.time(ins.time);
|
||||||
|
self.playback_head.set_time(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);
|
||||||
|
|||||||
@@ -118,9 +118,15 @@ impl PlaybackHead{
|
|||||||
self.head.advance_time(&bot.bot,time);
|
self.head.advance_time(&bot.bot,time);
|
||||||
}
|
}
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
pub fn get_head_time(&self,time:f64)->f64{
|
||||||
|
let time=time::from_float(time).unwrap();
|
||||||
|
let time=self.head.time(time);
|
||||||
|
time.get() as f64/strafesnet_common::run::Time::ONE_SECOND.get() as f64
|
||||||
|
}
|
||||||
|
#[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>{
|
||||||
let time=time::from_float(time).unwrap();
|
let time=time::from_float(time).unwrap();
|
||||||
let time=self.head.time(&bot.bot,time);
|
let time=bot.bot.time(self.head.time(time));
|
||||||
let mode=v0::ModeID(mode_id);
|
let mode=v0::ModeID(mode_id);
|
||||||
let run_time=self.head.state().get_run(mode)?.time(time);
|
let run_time=self.head.state().get_run(mode)?.time(time);
|
||||||
Some(run_time.get() as f64/strafesnet_common::run::Time::ONE_SECOND.get() as f64)
|
Some(run_time.get() as f64/strafesnet_common::run::Time::ONE_SECOND.get() as f64)
|
||||||
@@ -145,21 +151,12 @@ impl PlaybackHead{
|
|||||||
let time=time::from_float(time).unwrap();
|
let time=time::from_float(time).unwrap();
|
||||||
self.head.set_scale(time,scale.try_into().unwrap());
|
self.head.set_scale(time,scale.try_into().unwrap());
|
||||||
}
|
}
|
||||||
|
/// Set the playback head position to new_time.
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn seek_to(&mut self,time:f64,new_time:f64){
|
pub fn set_head_time(&mut self,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.seek_to(time,new_time);
|
self.head.set_time(time,new_time);
|
||||||
}
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn seek_forward(&mut self,time_offset:f64){
|
|
||||||
let time_offset=time::from_float(time_offset).unwrap();
|
|
||||||
self.head.seek_forward(time_offset);
|
|
||||||
}
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn seek_backward(&mut self,time_offset:f64){
|
|
||||||
let time_offset=time::from_float(time_offset).unwrap();
|
|
||||||
self.head.seek_backward(time_offset);
|
|
||||||
}
|
}
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn get_fov_slope_y(&self)->f64{
|
pub fn get_fov_slope_y(&self)->f64{
|
||||||
|
|||||||
@@ -56,17 +56,21 @@ function set_scale(new_scale) {
|
|||||||
|
|
||||||
// Controls
|
// Controls
|
||||||
document.getElementById("control_reset").addEventListener("click", (e) => {
|
document.getElementById("control_reset").addEventListener("click", (e) => {
|
||||||
playback.seek_to(elapsed(), 0.0);
|
playback.set_head_time(elapsed(), 0.0);
|
||||||
});
|
});
|
||||||
document.getElementById("control_pause").addEventListener("click", (e) => {
|
document.getElementById("control_pause").addEventListener("click", (e) => {
|
||||||
paused = !paused;
|
paused = !paused;
|
||||||
playback.set_paused(elapsed(), paused);
|
playback.set_paused(elapsed(), paused);
|
||||||
});
|
});
|
||||||
document.getElementById("control_forward").addEventListener("click", (e) => {
|
document.getElementById("control_forward").addEventListener("click", (e) => {
|
||||||
playback.seek_forward(2.0);
|
const time_now = elapsed();
|
||||||
|
const playback_time = playback.get_head_time(time_now);
|
||||||
|
playback.set_head_time(time_now, playback_time + 2.0);
|
||||||
});
|
});
|
||||||
document.getElementById("control_backward").addEventListener("click", (e) => {
|
document.getElementById("control_backward").addEventListener("click", (e) => {
|
||||||
playback.seek_backward(2.0);
|
const time_now = elapsed();
|
||||||
|
const playback_time = playback.get_head_time(time_now);
|
||||||
|
playback.set_head_time(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);
|
||||||
|
|||||||
Reference in New Issue
Block a user