Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
a2caa1e7d3
|
|||
|
8d2da1b053
|
|||
|
8369831668
|
|||
|
0c6226a4b6
|
|||
|
6526ca13b6
|
|||
|
a0a9be7101
|
|||
|
5d4643b8c9
|
1200
Cargo.lock
generated
1200
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,8 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3.31"
|
||||
strafesnet_roblox_bot_file = { version = "0.9.3", registry = "strafesnet" }
|
||||
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" }
|
||||
tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "fs"] }
|
||||
tokio-stream = { version = "0.1.17", features = ["fs"] }
|
||||
|
||||
96
src/main.rs
96
src/main.rs
@@ -1,6 +1,6 @@
|
||||
use strafesnet_roblox_bot_file::v0;
|
||||
|
||||
use std::path::{Path,PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use futures::{StreamExt,TryStreamExt};
|
||||
|
||||
#[expect(dead_code)]
|
||||
@@ -10,7 +10,7 @@ enum Error{
|
||||
Io(std::io::Error),
|
||||
BotFile{
|
||||
path:PathBuf,
|
||||
err:RoundTripError,
|
||||
err:PlaybackError,
|
||||
},
|
||||
Join(tokio::task::JoinError),
|
||||
}
|
||||
@@ -26,11 +26,9 @@ impl From<tokio::task::JoinError> for Error{
|
||||
}
|
||||
#[expect(dead_code)]
|
||||
#[derive(Debug)]
|
||||
enum RoundTripError{
|
||||
enum PlaybackError{
|
||||
Decode(v0::Error),
|
||||
Encode(strafesnet_roblox_bot_file::BinrwError),
|
||||
RoundTripDecode(v0::Error),
|
||||
NotEqual,
|
||||
Panic,
|
||||
}
|
||||
#[tokio::main]
|
||||
async fn main()->Result<(),Error>{
|
||||
@@ -40,43 +38,10 @@ async fn main()->Result<(),Error>{
|
||||
return Err(Error::InvalidArgs);
|
||||
};
|
||||
|
||||
const ONE_SECOND:u64=1<<32;
|
||||
#[derive(Default)]
|
||||
struct FoldState{
|
||||
struct State{
|
||||
count:usize,
|
||||
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;
|
||||
}
|
||||
}
|
||||
errors:Vec<(PathBuf,strafesnet_roblox_bot_player::bot::Error)>,
|
||||
}
|
||||
|
||||
let available_parallelism=std::thread::available_parallelism()?.get();
|
||||
@@ -91,23 +56,21 @@ 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(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.input_events.len()==block.input_events.len()&&
|
||||
block_rt.output_events.len()==block.output_events.len()&&
|
||||
block_rt.sound_events.len()==block.sound_events.len()&&
|
||||
block_rt.world_events.len()==block.world_events.len()&&
|
||||
block_rt.gravity_events.len()==block.gravity_events.len()&&
|
||||
block_rt.run_events.len()==block.run_events.len()&&
|
||||
block_rt.camera_events.len()==block.camera_events.len()&&
|
||||
block_rt.setting_events.len()==block.setting_events.len()
|
||||
){
|
||||
return Err(RoundTripError::NotEqual);
|
||||
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);
|
||||
}
|
||||
Ok(block)
|
||||
Ok(None)
|
||||
}).await?;
|
||||
match result{
|
||||
Err(err)=>Err(Error::BotFile{path,err}),
|
||||
@@ -115,14 +78,21 @@ async fn main()->Result<(),Error>{
|
||||
}
|
||||
})
|
||||
.buffer_unordered(available_parallelism)
|
||||
.try_fold(FoldState::default(),async|mut state,(path,block)|{
|
||||
state.accumulate(&path,&block);
|
||||
println!("{:?} {}",path.file_name(),state);
|
||||
.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));
|
||||
},
|
||||
};
|
||||
Ok(state)
|
||||
}).await?;
|
||||
for path in &tally.outliers{
|
||||
println!("outlier: {:?}",path.file_name());
|
||||
println!("{}",tally.count);
|
||||
for (path,e) in tally.errors{
|
||||
println!("error: {:?} {}",path.file_name(),e);
|
||||
}
|
||||
println!("{}",tally);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user