3 Commits

Author SHA1 Message Date
c8fccfc398 slight buffer 2025-12-14 19:04:24 -08:00
1253777d3d round trip test 2025-12-14 19:03:42 -08:00
f30302f0bf update roblox_bot_file to prerelease version 2025-12-14 18:59:34 -08:00
3 changed files with 62 additions and 1230 deletions

1199
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,9 +4,8 @@ version = "0.1.0"
edition = "2024"
[dependencies]
binrw = "0.15.0"
futures = "0.3.31"
strafesnet_common = { version = "0.8.7", registry = "strafesnet" }
strafesnet_roblox_bot_file = { version = "0.9.4", registry = "strafesnet" }
strafesnet_roblox_bot_player = { version = "0.4.0", registry = "strafesnet" }
strafesnet_roblox_bot_file = { version = "0.7.1-pre1", registry = "strafesnet" }
tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "fs"] }
tokio-stream = { version = "0.1.17", features = ["fs"] }

View File

@@ -1,6 +1,6 @@
use strafesnet_roblox_bot_file::v0;
use std::path::PathBuf;
use std::path::{Path,PathBuf};
use futures::{StreamExt,TryStreamExt};
#[expect(dead_code)]
@@ -10,7 +10,7 @@ enum Error{
Io(std::io::Error),
BotFile{
path:PathBuf,
err:PlaybackError,
err:RoundTripError,
},
Join(tokio::task::JoinError),
}
@@ -24,11 +24,12 @@ impl From<tokio::task::JoinError> for Error{
Self::Join(value)
}
}
#[expect(dead_code)]
#[derive(Debug)]
enum PlaybackError{
enum RoundTripError{
Decode(v0::Error),
Panic,
Encode(binrw::Error),
RoundTripDecode(v0::Error),
NotEqual,
}
#[tokio::main]
async fn main()->Result<(),Error>{
@@ -38,10 +39,43 @@ async fn main()->Result<(),Error>{
return Err(Error::InvalidArgs);
};
const ONE_SECOND:u64=1<<32;
#[derive(Default)]
struct State{
struct FoldState{
count:usize,
errors:Vec<(PathBuf,strafesnet_roblox_bot_player::bot::Error)>,
jumps:u64,
duration:u64,
settings:u64,
outliers:Vec<PathBuf>,
}
impl std::fmt::Display for FoldState{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"count={} jumps={} duration={:.3} settings={}",self.count,self.jumps,self.duration as f64/(ONE_SECOND as f64),self.settings)
}
}
impl FoldState{
fn accumulate(&mut self,path:&Path,block:&v0::Block){
if let (Some(first),Some(last))=(block.output_events.first(),block.output_events.last()){
let last=last.time*ONE_SECOND as f64;
let first=first.time*ONE_SECOND as f64;
let duration=last as u64-first as u64;
if 30000*ONE_SECOND<duration{
self.outliers.push(path.to_owned());
return;
}
self.duration+=duration;
}
self.count+=1;
self.jumps+=block.sound_events.iter()
.filter(|event|event.event.sound_type==v0::SoundType::JumpGround)
.count() as u64;
// find settings events after run has started
if let Some(run_start)=block.run_events.iter().find(|event|matches!(event.event,v0::RunEvent::Start(_))){
self.settings+=block.setting_events.iter()
.filter(|event|run_start.time<event.time)
.count() as u64;
}
}
}
let available_parallelism=std::thread::available_parallelism()?.get();
@@ -56,21 +90,14 @@ async fn main()->Result<(),Error>{
.map(|result:Result<_,Error>|async move{
let (path,file)=result?;
let result=tokio::task::spawn_blocking(move||{
let block=v0::read_all_to_block(std::io::Cursor::new(file.as_slice())).map_err(PlaybackError::Decode)?;
let bot=match strafesnet_roblox_bot_player::bot::CompleteBot::new(block){
Ok(bot)=>bot,
Err(e)=>return Ok(Some(e)),
};
let mut head=strafesnet_roblox_bot_player::head::PlaybackHead::new(&bot,strafesnet_common::session::Time::ZERO);
if let Err(e)=std::panic::catch_unwind(move||{
head.get_position_angles(&bot,strafesnet_common::session::Time::ZERO);
head.set_time(&bot,strafesnet_common::session::Time::ZERO,bot.duration().coerce());
head.get_position_angles(&bot,strafesnet_common::session::Time::ZERO);
}){
println!("{e:?}");
return Err(PlaybackError::Panic);
let block=v0::read_all_to_block(std::io::Cursor::new(file.as_slice())).map_err(RoundTripError::Decode)?;
let mut data=Vec::with_capacity(file.len()+1024);
v0::serialize(&block,&mut std::io::Cursor::new(&mut data)).map_err(RoundTripError::Encode)?;
let block_rt=v0::read_all_to_block(std::io::Cursor::new(data)).map_err(RoundTripError::RoundTripDecode)?;
if block_rt!=block{
return Err(RoundTripError::NotEqual);
}
Ok(None)
Ok(block)
}).await?;
match result{
Err(err)=>Err(Error::BotFile{path,err}),
@@ -78,21 +105,14 @@ async fn main()->Result<(),Error>{
}
})
.buffer_unordered(available_parallelism)
.try_fold(State::default(),async|mut state,(path,bot_error)|{
state.count+=1;
// state.accumulate(&path,&block);
match bot_error{
None=>println!("{:07} {:?}",state.count,path.file_name()),
Some(e)=>{
println!("{:07} {:?} {}",state.count,path.file_name(),e);
state.errors.push((path,e));
},
};
.try_fold(FoldState::default(),async|mut state,(path,block)|{
state.accumulate(&path,&block);
println!("{:?} {}",path.file_name(),state);
Ok(state)
}).await?;
println!("{}",tally.count);
for (path,e) in tally.errors{
println!("error: {:?} {}",path.file_name(),e);
for path in &tally.outliers{
println!("outlier: {:?}",path.file_name());
}
println!("{}",tally);
Ok(())
}