bot file playback
This commit is contained in:
@@ -262,6 +262,15 @@ pub struct PhysicsCamera{
|
||||
impl PhysicsCamera{
|
||||
const ANGLE_PITCH_LOWER_LIMIT:Angle32=Angle32::NEG_FRAC_PI_2;
|
||||
const ANGLE_PITCH_UPPER_LIMIT:Angle32=Angle32::FRAC_PI_2;
|
||||
pub fn new(
|
||||
sensitivity:Ratio64Vec2,
|
||||
clamped_mouse_pos:glam::IVec2,
|
||||
)->Self{
|
||||
Self{
|
||||
sensitivity,
|
||||
clamped_mouse_pos,
|
||||
}
|
||||
}
|
||||
pub fn move_mouse(&mut self,mouse_delta:glam::IVec2){
|
||||
let mut unclamped_mouse_pos=self.clamped_mouse_pos+mouse_delta;
|
||||
unclamped_mouse_pos.y=unclamped_mouse_pos.y.clamp(
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
use crate::graphics_worker::Instruction as GraphicsInstruction;
|
||||
use strafesnet_settings::{directories::Directories,settings};
|
||||
use strafesnet_session::session::{
|
||||
FrameState,
|
||||
Session,Simulation,SessionInputInstruction,SessionControlInstruction,SessionPlaybackInstruction,ImplicitModeInstruction,
|
||||
Instruction as SessionInstruction,
|
||||
};
|
||||
use strafesnet_common::instruction::{TimedInstruction,InstructionConsumer};
|
||||
use strafesnet_common::physics::Time as PhysicsTime;
|
||||
use strafesnet_common::session::Time as SessionTime;
|
||||
use strafesnet_common::timer::Timer;
|
||||
use strafesnet_common::instruction::TimedInstruction;
|
||||
use strafesnet_common::physics::{Time as PhysicsTime,TimeInner as PhysicsTimeInner};
|
||||
use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner};
|
||||
use strafesnet_common::timer::{Scaled,Timer,TimerState};
|
||||
use strafesnet_physics::physics::PhysicsData;
|
||||
|
||||
pub enum Instruction{
|
||||
SessionInput(SessionInputInstruction),
|
||||
@@ -19,6 +21,126 @@ pub enum Instruction{
|
||||
LoadReplay(strafesnet_snf::bot::Segment),
|
||||
}
|
||||
|
||||
fn vector3_to_glam(v:&strafesnet_roblox_bot_file::v0::Vector3)->glam::Vec3{
|
||||
glam::vec3(v.x,v.y,v.z)
|
||||
}
|
||||
fn f32_to_p64(f:f32)->strafesnet_common::integer::Planar64{
|
||||
f.try_into().unwrap_or(strafesnet_common::integer::Planar64::ZERO)
|
||||
}
|
||||
|
||||
struct PlayBacker{
|
||||
//Instructions
|
||||
timelines:strafesnet_roblox_bot_file::v0::Block,
|
||||
//"Simulation"
|
||||
event_id:usize,
|
||||
offset:f64,
|
||||
duration:f64,
|
||||
timer:Timer<Scaled<SessionTimeInner,PhysicsTimeInner>>,
|
||||
physics_data:PhysicsData,
|
||||
}
|
||||
impl PlayBacker{
|
||||
pub fn new(
|
||||
physics_data:PhysicsData,
|
||||
timelines:strafesnet_roblox_bot_file::v0::Block,
|
||||
)->Self{
|
||||
let first=timelines.output_events.first().unwrap();
|
||||
let last=timelines.output_events.last().unwrap();
|
||||
Self{
|
||||
offset:first.time,
|
||||
duration:last.time-first.time,
|
||||
timelines,
|
||||
event_id:0,
|
||||
timer:Timer::from_state(Scaled::identity(),false),
|
||||
physics_data,
|
||||
}
|
||||
}
|
||||
pub fn handle_instruction(&mut self,TimedInstruction{time,instruction}:&TimedInstruction<SessionInstruction,SessionTime>){
|
||||
//match the instruction so the playback is pausable :D
|
||||
match instruction{
|
||||
&SessionInstruction::Control(SessionControlInstruction::SetPaused(paused))=>{
|
||||
let _=self.timer.set_paused(*time,paused);
|
||||
},
|
||||
_=>(),
|
||||
}
|
||||
let simulation_time=self.timer.time(*time);
|
||||
let mut time_float=simulation_time.get() as f64/PhysicsTime::ONE_SECOND.get() as f64+self.offset;
|
||||
loop{
|
||||
match self.timelines.output_events.get(self.event_id+1){
|
||||
Some(next_event)=>{
|
||||
if next_event.time<time_float{
|
||||
self.event_id+=1;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
},
|
||||
None=>{
|
||||
//reset playback
|
||||
self.event_id=0;
|
||||
self.offset-=self.duration;
|
||||
time_float-=self.duration;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn get_frame_state(&self,time:SessionTime)->FrameState{
|
||||
use strafesnet_physics::physics::{Body,PhysicsCamera};
|
||||
|
||||
let time=self.timer.time(time);
|
||||
let event0=&self.timelines.output_events[self.event_id];
|
||||
let event1=&self.timelines.output_events[self.event_id+1];
|
||||
let p0=vector3_to_glam(&event0.event.position);
|
||||
let p1=vector3_to_glam(&event1.event.position);
|
||||
let v0=vector3_to_glam(&event0.event.velocity);
|
||||
let v1=vector3_to_glam(&event1.event.velocity);
|
||||
let a0=vector3_to_glam(&event0.event.acceleration);
|
||||
let a1=vector3_to_glam(&event1.event.acceleration);
|
||||
let t0=event0.time;
|
||||
let t1=event1.time;
|
||||
let time_float=time.get() as f64/PhysicsTime::ONE_SECOND.get() as f64;
|
||||
let t=((time_float+self.offset-t0)/(t1-t0)) as f32;
|
||||
let p=p0.lerp(p1,t).to_array().map(f32_to_p64);
|
||||
let v=v0.lerp(v1,t).to_array().map(f32_to_p64);
|
||||
let a=a0.lerp(a1,t).to_array().map(f32_to_p64);
|
||||
|
||||
//println!("position={:?}",p);
|
||||
|
||||
let angles0=vector3_to_glam(&event0.event.angles);
|
||||
let angles1=vector3_to_glam(&event1.event.angles);
|
||||
let angles=angles0.lerp(angles1,t);
|
||||
// mask mantissa out and set it to minimum value
|
||||
// let ax_epsilon=f32::from_bits(angles.x.to_bits()&!((1<<23)-1)|1);
|
||||
// let ay_epsilon=f32::from_bits(angles.y.to_bits()&!((1<<23)-1)|1);
|
||||
let body=Body{
|
||||
time,
|
||||
position:strafesnet_common::integer::Planar64Vec3::new(p),
|
||||
velocity:strafesnet_common::integer::Planar64Vec3::new(v),
|
||||
acceleration:strafesnet_common::integer::Planar64Vec3::new(a),
|
||||
};
|
||||
const FLOAT64_TO_ANGLE32_RADIANS:f64=((1i64<<31) as f64)/std::f64::consts::PI;
|
||||
// xy is reversed in strafe client for some reason
|
||||
let (ax,ay)=(
|
||||
-angles.y as f64*FLOAT64_TO_ANGLE32_RADIANS,
|
||||
-angles.x as f64*FLOAT64_TO_ANGLE32_RADIANS,
|
||||
);
|
||||
let camera=PhysicsCamera::new(
|
||||
strafesnet_common::integer::Ratio64Vec2::new(1.0f32.try_into().unwrap(),1.0f32.try_into().unwrap()),
|
||||
glam::ivec2(ax as i64 as i32,ay as i64 as i32)
|
||||
);
|
||||
FrameState{
|
||||
body,
|
||||
camera,
|
||||
time,
|
||||
}
|
||||
}
|
||||
pub fn user_settings(&self)->settings::UserSettings{
|
||||
//oof, settings ignored
|
||||
settings::UserSettings::default()
|
||||
}
|
||||
pub fn change_map(&mut self,_time:SessionTime,map:&strafesnet_common::map::CompleteMap){
|
||||
self.physics_data=PhysicsData::new(&map);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new<'a>(
|
||||
mut graphics_worker:crate::compat_worker::INWorker<'a,crate::graphics_worker::Instruction>,
|
||||
directories:Option<Directories>,
|
||||
@@ -32,11 +154,19 @@ pub fn new<'a>(
|
||||
directories,
|
||||
simulation,
|
||||
);
|
||||
//load bot
|
||||
let physics=PhysicsData::empty();
|
||||
let data=include_bytes!("/home/quat/strafesnet/roblox_bot_file/files/bhop_marble_7cf33a64-7120-4514-b9fa-4fe29d9523d");
|
||||
let bot_file=strafesnet_roblox_bot_file::v0::read_all_to_block(std::io::Cursor::new(data)).unwrap();
|
||||
let mut interpolator=PlayBacker::new(
|
||||
physics,
|
||||
bot_file,
|
||||
);
|
||||
crate::compat_worker::QNWorker::new(move |ins:TimedInstruction<Instruction,SessionTime>|{
|
||||
// excruciating pain
|
||||
macro_rules! run_session_instruction{
|
||||
($time:expr,$instruction:expr)=>{
|
||||
session.process_instruction(TimedInstruction{
|
||||
interpolator.handle_instruction(&TimedInstruction{
|
||||
time:$time,
|
||||
instruction:$instruction,
|
||||
});
|
||||
@@ -59,16 +189,17 @@ pub fn new<'a>(
|
||||
},
|
||||
Instruction::Render=>{
|
||||
run_session_instruction!(ins.time,SessionInstruction::Idle);
|
||||
if let Some(frame_state)=session.get_frame_state(ins.time){
|
||||
if let Some(frame_state)=Some(interpolator.get_frame_state(ins.time)){
|
||||
run_graphics_worker_instruction!(GraphicsInstruction::Render(frame_state));
|
||||
}
|
||||
},
|
||||
Instruction::Resize(physical_size)=>{
|
||||
run_session_instruction!(ins.time,SessionInstruction::Idle);
|
||||
let user_settings=session.user_settings().clone();
|
||||
let user_settings=interpolator.user_settings().clone();
|
||||
run_graphics_worker_instruction!(GraphicsInstruction::Resize(physical_size,user_settings));
|
||||
},
|
||||
Instruction::ChangeMap(complete_map)=>{
|
||||
interpolator.change_map(ins.time,&complete_map);
|
||||
run_session_instruction!(ins.time,SessionInstruction::ChangeMap(&complete_map));
|
||||
run_session_instruction!(ins.time,SessionInstruction::Input(SessionInputInstruction::Mode(ImplicitModeInstruction::ResetAndSpawn(strafesnet_common::gameplay_modes::ModeId::MAIN,strafesnet_common::gameplay_modes::StageId::FIRST))));
|
||||
run_graphics_worker_instruction!(GraphicsInstruction::ChangeMap(complete_map));
|
||||
|
||||
Reference in New Issue
Block a user