Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
3c31de9f9f
|
|||
|
513602e551
|
|||
|
b147c96240
|
|||
|
8f6b7bb8da
|
|||
|
2304f19239
|
|||
|
a2155f0864
|
|||
|
181f39ff37
|
|||
|
5f99a47cf2
|
|||
|
e44fd7cbb9
|
|||
|
60874fb769
|
|||
|
a2f1572281
|
|||
|
baf6f7e99b
|
|||
|
934be7a28a
|
|||
|
cdd2f5cd89
|
|||
|
2f76e5e63d
|
|||
|
5fa13de6cf
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1,3 @@
|
||||
/bots
|
||||
/replays
|
||||
/target
|
||||
|
||||
195
Cargo.lock
generated
195
Cargo.lock
generated
@@ -8,6 +8,12 @@ version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "binrw"
|
||||
version = "0.15.0"
|
||||
@@ -38,12 +44,21 @@ version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
|
||||
[[package]]
|
||||
name = "bnum"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "119771309b95163ec7aaf79810da82f7cd0599c19722d48b9c03894dca833966"
|
||||
|
||||
[[package]]
|
||||
name = "bot-cruncher"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"strafesnet_common",
|
||||
"strafesnet_physics",
|
||||
"strafesnet_roblox_bot_file",
|
||||
"strafesnet_snf",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
]
|
||||
@@ -54,24 +69,6 @@ version = "1.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
@@ -79,10 +76,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||
name = "fixed_wide"
|
||||
version = "0.2.2"
|
||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||
checksum = "1397e01522f708e80dcf6c17db69139abb57c43212226b60b50fc09d91c607b5"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bnum",
|
||||
"paste",
|
||||
"ratio_ops",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
@@ -174,15 +177,20 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.4"
|
||||
name = "glam"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||
checksum = "74a4d85559e2637d3d839438b5b3d75c31e655276f9544d72475c36b92fabbed"
|
||||
|
||||
[[package]]
|
||||
name = "id"
|
||||
version = "0.1.0"
|
||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||
checksum = "2337e7a6c273082b672e377e159d7a168fb51438461b7c4033c79a515dd7a25a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasip2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -195,21 +203,16 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||
name = "linear_ops"
|
||||
version = "0.1.1"
|
||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||
checksum = "d6ea2e52a83eab4afe56536e6d27f8e815bd994111ccdc3e2c0aafce77014286"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libc",
|
||||
"fixed_wide",
|
||||
"paste",
|
||||
"ratio_ops",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.182"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
@@ -222,6 +225,12 @@ version = "4.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.16"
|
||||
@@ -234,12 +243,6 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
@@ -259,16 +262,10 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
name = "ratio_ops"
|
||||
version = "0.1.1"
|
||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||
checksum = "93f2dc5bfc9d878028a699e77c6f88ac59d23404218af9fcfbfc190610f49c80"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
@@ -276,14 +273,53 @@ version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
|
||||
|
||||
[[package]]
|
||||
name = "strafesnet_common"
|
||||
version = "0.8.0"
|
||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||
checksum = "171f2b754a8c59b335578824d5465d9637fb41ec4906c6a8c1fd39206891b09c"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"fixed_wide",
|
||||
"glam",
|
||||
"id",
|
||||
"linear_ops",
|
||||
"ratio_ops",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strafesnet_physics"
|
||||
version = "0.0.1"
|
||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||
checksum = "8bf75c5ba62556c83da56c70cc1e0f31b842fdd993646dc533ac7a844a05b926"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"glam",
|
||||
"id",
|
||||
"strafesnet_common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strafesnet_roblox_bot_file"
|
||||
version = "0.8.1"
|
||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||
checksum = "33d0fa524476d8b6cf23269b0c9cff6334b70585546b807cb8ec193858defecd"
|
||||
dependencies = [
|
||||
"binrw",
|
||||
"bitflags",
|
||||
"itertools",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strafesnet_snf"
|
||||
version = "0.3.2"
|
||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||
checksum = "aab96a189e3f5c4e5eca1feae704c0d6ceaa0de37a41e29ef3a89816e354292f"
|
||||
dependencies = [
|
||||
"binrw",
|
||||
"id",
|
||||
"strafesnet_common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -334,46 +370,3 @@ name = "unicode-ident"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.2+wasi-0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
|
||||
dependencies = [
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "7.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
|
||||
dependencies = [
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "2.0.16+zstd.1.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
@@ -5,6 +5,9 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3.31"
|
||||
strafesnet_roblox_bot_file = { path = "../roblox_bot_file", registry = "strafesnet" }
|
||||
strafesnet_common = { version = "0.8.0", registry = "strafesnet" }
|
||||
strafesnet_physics = { version = "0.0.1", registry = "strafesnet" }
|
||||
strafesnet_roblox_bot_file = { version = "0.8.1", registry = "strafesnet" }
|
||||
strafesnet_snf = { version = "0.3.2", registry = "strafesnet" }
|
||||
tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "fs"] }
|
||||
tokio-stream = { version = "0.1.17", features = ["fs"] }
|
||||
|
||||
310
src/main.rs
310
src/main.rs
@@ -1,6 +1,8 @@
|
||||
use strafesnet_roblox_bot_file::{v0,v1};
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use strafesnet_common::integer::{Planar64,Planar64Vec3};
|
||||
use strafesnet_physics::physics::{PhysicsData,Time};
|
||||
use strafesnet_roblox_bot_file::v0;
|
||||
use futures::{StreamExt,TryStreamExt};
|
||||
|
||||
#[expect(dead_code)]
|
||||
@@ -8,9 +10,11 @@ use futures::{StreamExt,TryStreamExt};
|
||||
enum Error{
|
||||
InvalidArgs,
|
||||
Io(std::io::Error),
|
||||
DecodeMap(strafesnet_snf::Error),
|
||||
DecodeMap2(strafesnet_snf::map::Error),
|
||||
BotFile{
|
||||
path:PathBuf,
|
||||
err:RoundTripError,
|
||||
err:SimError,
|
||||
},
|
||||
Join(tokio::task::JoinError),
|
||||
}
|
||||
@@ -24,115 +28,243 @@ impl From<tokio::task::JoinError> for Error{
|
||||
Self::Join(value)
|
||||
}
|
||||
}
|
||||
#[expect(dead_code)]
|
||||
#[derive(Debug)]
|
||||
enum RoundTripError{
|
||||
Decode(v0::Error),
|
||||
Encode(strafesnet_roblox_bot_file::BinrwError),
|
||||
RoundTripDecode(v0::Error),
|
||||
NotEqual,
|
||||
|
||||
const fn fly_time(distance:Planar64)->Time{
|
||||
Time::raw(distance.to_raw()*Time::ONE_SECOND.get()/(80*Planar64::ONE.to_raw()))
|
||||
}
|
||||
|
||||
// #[expect(dead_code)]
|
||||
#[derive(Debug)]
|
||||
enum SimError{
|
||||
Decode(v0::Error),
|
||||
}
|
||||
fn run_roblox_bot_in_strafe_client_physics(physics_data:&PhysicsData,block:&v0::Block,file_stem:std::ffi::OsString,offset:Planar64Vec3){
|
||||
use strafesnet_common::instruction::TimedInstruction;
|
||||
use strafesnet_common::mouse::MouseState;
|
||||
use strafesnet_common::physics::{Instruction,MouseInstruction,SetControlInstruction,ModeInstruction,MiscInstruction};
|
||||
use strafesnet_physics::physics::{PhysicsState,PhysicsContext};
|
||||
|
||||
fn vector3(v:&v0::Vector3)->Planar64Vec3{
|
||||
strafesnet_common::integer::vec3::try_from_f32_array([v.x,v.y,v.z]).unwrap()
|
||||
}
|
||||
|
||||
let mut input_it=block.input_events.iter();
|
||||
|
||||
let Some(input)=input_it.next()else{
|
||||
return;
|
||||
};
|
||||
let Some(output)=block.output_events.first()else{
|
||||
return;
|
||||
};
|
||||
let Some(setting)=block.setting_events.iter().find(|event|matches!(event.event.setting_type,v0::SettingType::Sensitivity))else{
|
||||
return;
|
||||
};
|
||||
|
||||
let mut recording=Vec::new();
|
||||
let mut physics=PhysicsState::default();
|
||||
let mut time=Time::ZERO;
|
||||
macro_rules! run{
|
||||
($time:expr,$ins:expr)=>{
|
||||
let ins=TimedInstruction{
|
||||
time:$time,
|
||||
instruction:$ins,
|
||||
};
|
||||
recording.push(ins.clone());
|
||||
PhysicsContext::run_input_instruction(&mut physics,physics_data,ins);
|
||||
};
|
||||
}
|
||||
|
||||
// === State Initialization ===
|
||||
|
||||
// Reset
|
||||
run!(time,Instruction::Mode(ModeInstruction::Reset));
|
||||
// generate an instruction to set the sensitivity (sens is also based on fov in rbhop, but pure in strafe client)
|
||||
let fov=1.0;//tan(90)
|
||||
let zoom=1.0;
|
||||
let pixels_to_radians=setting.event.value*fov*zoom/128.0;
|
||||
// convert radians to Angle32
|
||||
let sensitivity=(pixels_to_radians*strafesnet_common::integer::Angle32::FRAC_PI_2.get() as f64/core::f64::consts::FRAC_PI_2) as i64;
|
||||
let sensitivity_ratio=strafesnet_common::integer::Ratio64::new(sensitivity,1).unwrap();
|
||||
run!(time,Instruction::Misc(MiscInstruction::SetSensitivity(strafesnet_common::integer::Ratio64Vec2{
|
||||
x:sensitivity_ratio,
|
||||
y:sensitivity_ratio,
|
||||
})));
|
||||
run!(time,Instruction::Mode(ModeInstruction::Restart(strafesnet_common::gameplay_modes::ModeId::MAIN)));
|
||||
|
||||
// Fly!
|
||||
run!(time,Instruction::Misc(MiscInstruction::PracticeFly));
|
||||
|
||||
// NoClip!
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetSprint(true)));
|
||||
|
||||
// generate instructions to fly to the starting position
|
||||
let fly_offset=offset+vector3(&output.event.position)-physics.body().position;
|
||||
if fly_offset.x.is_negative(){
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetMoveLeft(true)));
|
||||
time+=fly_time(-fly_offset.x);
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetMoveLeft(false)));
|
||||
}else{
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetMoveRight(true)));
|
||||
time+=fly_time(fly_offset.x);
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetMoveRight(false)));
|
||||
}
|
||||
if fly_offset.y.is_negative(){
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetMoveDown(true)));
|
||||
time+=fly_time(-fly_offset.y);
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetMoveDown(false)));
|
||||
}else{
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetMoveUp(true)));
|
||||
time+=fly_time(fly_offset.y);
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetMoveUp(false)));
|
||||
}
|
||||
if fly_offset.z.is_negative(){
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetMoveForward(true)));
|
||||
time+=fly_time(-fly_offset.z);
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetMoveForward(false)));
|
||||
}else{
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetMoveBack(true)));
|
||||
time+=fly_time(fly_offset.z);
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetMoveBack(false)));
|
||||
}
|
||||
|
||||
// Fly off
|
||||
run!(time,Instruction::Misc(MiscInstruction::PracticeFly));
|
||||
|
||||
// NoClip off
|
||||
run!(time,Instruction::SetControl(SetControlInstruction::SetSprint(false)));
|
||||
|
||||
// TODO: generate instructions to set up the velocity
|
||||
|
||||
let t0=Time::from_nanos((output.time*Time::ONE_SECOND.get() as f64) as i64);
|
||||
// generate an instruction that will rotate the camera to match output.angles
|
||||
let mut last_mouse=&input.event.mouse_pos;
|
||||
// generate an instruction for each pressed key
|
||||
let mut last_controls=v0::GameControls::empty();
|
||||
|
||||
// construct an iterator to detect key changes and mouse movement
|
||||
// run key changes first, then mouse movement
|
||||
let it=input_it.map(|event|{
|
||||
let time=Time::from_nanos((event.time*Time::ONE_SECOND.get() as f64) as i64)-t0+time;
|
||||
// detect controls changes
|
||||
let controls={
|
||||
let new_controls=event.event.game_controls;
|
||||
let mask=new_controls^last_controls;
|
||||
last_controls=new_controls;
|
||||
(mask,new_controls)
|
||||
};
|
||||
// detect mouse changes
|
||||
let mouse=(event.event.mouse_pos.x!=last_mouse.x||event.event.mouse_pos.y!=last_mouse.y).then(||{
|
||||
last_mouse=&event.event.mouse_pos;
|
||||
Instruction::Mouse(MouseInstruction::SetNextMouse(MouseState{
|
||||
pos:[event.event.mouse_pos.x as i32,event.event.mouse_pos.y as i32].into(),
|
||||
time,
|
||||
}))
|
||||
});
|
||||
(time,controls,mouse)
|
||||
});
|
||||
|
||||
// detect deviation from space radius and time range.
|
||||
// if the current position is not near any timeline position within +-1s, abort
|
||||
|
||||
for (time,(mask,controls),mouse) in it{
|
||||
macro_rules! run_control{
|
||||
($control:ident,$ins:ident)=>{
|
||||
if mask.contains(v0::GameControls::$control){
|
||||
let state=controls.contains(v0::GameControls::$control);
|
||||
let instruction=Instruction::SetControl(SetControlInstruction::$ins(state));
|
||||
run!(time,instruction);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
run_control!(MoveForward,SetMoveForward);
|
||||
run_control!(MoveLeft,SetMoveLeft);
|
||||
run_control!(MoveBack,SetMoveBack);
|
||||
run_control!(MoveRight,SetMoveRight);
|
||||
run_control!(MoveUp,SetMoveUp);
|
||||
run_control!(MoveDown,SetMoveDown);
|
||||
// run_control!(LookUp);
|
||||
// run_control!(LookLeft);
|
||||
// run_control!(LookDown);
|
||||
// run_control!(LookRight);
|
||||
run_control!(Jump,SetJump);
|
||||
// run_control!(Crouch);
|
||||
run_control!(Sprint,SetSprint);
|
||||
run_control!(Zoom,SetZoom);
|
||||
// run_control!(Use);
|
||||
// run_control!(Action1);
|
||||
// run_control!(Action2);
|
||||
|
||||
if let Some(instruction)=mouse{
|
||||
run!(time,instruction);
|
||||
}
|
||||
}
|
||||
// idle for 1s just in case we need to glide into the finish zone
|
||||
|
||||
// if the bot completed the map, write a .snfb file
|
||||
match physics.get_finish_time(){
|
||||
Some(time)=>println!("finish time:{}",time),
|
||||
None=>println!("simulation did not end in finished state"),
|
||||
}
|
||||
|
||||
let mut replays_path=std::env::current_dir().unwrap();
|
||||
let mut file_name=PathBuf::from(file_stem);
|
||||
file_name.set_extension("snfb");
|
||||
std::fs::create_dir_all(replays_path.as_path()).unwrap();
|
||||
replays_path.push(file_name);
|
||||
let file=std::fs::File::create(replays_path).unwrap();
|
||||
strafesnet_snf::bot::write_bot(
|
||||
std::io::BufWriter::new(file),
|
||||
strafesnet_physics::VERSION.get(),
|
||||
recording,
|
||||
).unwrap();
|
||||
println!("Finished writing bot file!");
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main()->Result<(),Error>{
|
||||
const PREFETCH_QUEUE:usize=64;
|
||||
|
||||
let Some(dir)=std::env::args().skip(1).next()else{
|
||||
let mut args=std::env::args().skip(1);
|
||||
let (Some(map),Some(dir))=(args.next(),args.next())else{
|
||||
return Err(Error::InvalidArgs);
|
||||
};
|
||||
|
||||
#[derive(Clone,Copy)]
|
||||
struct Ratio{
|
||||
num:u64,
|
||||
den:u64,
|
||||
}
|
||||
impl Ratio{
|
||||
fn float(&self)->f32{
|
||||
self.num as f32/self.den as f32
|
||||
}
|
||||
}
|
||||
impl PartialEq for Ratio{
|
||||
fn eq(&self,other:&Self)->bool{
|
||||
(self.num*other.den).eq(&(other.num*self.den))
|
||||
}
|
||||
}
|
||||
impl Eq for Ratio{}
|
||||
impl PartialOrd for Ratio{
|
||||
fn partial_cmp(&self,other:&Self)->Option<core::cmp::Ordering>{
|
||||
(self.num*other.den).partial_cmp(&(other.num*self.den))
|
||||
}
|
||||
}
|
||||
impl Ord for Ratio{
|
||||
fn cmp(&self,other:&Self)->core::cmp::Ordering{
|
||||
(self.num*other.den).cmp(&(other.num*self.den))
|
||||
}
|
||||
}
|
||||
println!("loading map file..");
|
||||
let data=tokio::fs::read(map).await?;
|
||||
let map=strafesnet_snf::read_map(std::io::Cursor::new(data))
|
||||
.map_err(Error::DecodeMap)?
|
||||
.into_complete_map()
|
||||
.map_err(Error::DecodeMap2)?;
|
||||
|
||||
struct FoldState{
|
||||
count:usize,
|
||||
min_size_ratio:Ratio,
|
||||
max_size_ratio:Ratio,
|
||||
total_size_before:u64,
|
||||
total_size_after:u64,
|
||||
}
|
||||
impl std::fmt::Display for FoldState{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
let count=self.count;
|
||||
let min_size_ratio=self.min_size_ratio.float();
|
||||
let max_size_ratio=self.max_size_ratio.float();
|
||||
let total_size_before=self.total_size_before;
|
||||
let total_size_after=self.total_size_after;
|
||||
write!(f,"count={count} min_size_ratio={min_size_ratio:.02} max_size_ratio={max_size_ratio:.02} total_size_before={total_size_before:.02} total_size_after={total_size_after:.02}")
|
||||
}
|
||||
}
|
||||
impl FoldState{
|
||||
fn new()->Self{
|
||||
FoldState{
|
||||
count:0,
|
||||
min_size_ratio:Ratio{num:u64::MAX,den:1},
|
||||
max_size_ratio:Ratio{num:0,den:1},
|
||||
total_size_before:0,
|
||||
total_size_after:0,
|
||||
}
|
||||
}
|
||||
fn accumulate(&mut self,size_before:u64,size_after:u64){
|
||||
self.count+=1;
|
||||
let ratio=Ratio{num:size_before,den:size_after};
|
||||
self.min_size_ratio=self.min_size_ratio.min(ratio);
|
||||
self.max_size_ratio=self.max_size_ratio.max(ratio);
|
||||
}
|
||||
}
|
||||
// grab mapstart position
|
||||
let start_zone_model_id=map.modes.clone().denormalize().get_mode(strafesnet_common::gameplay_modes::ModeId::MAIN).unwrap().get_start();
|
||||
let offset=map.models[start_zone_model_id.get() as usize].transform.translation;
|
||||
|
||||
// create recording
|
||||
println!("generating models..");
|
||||
let physics_data:&_=Box::leak(Box::new(PhysicsData::new(&map)));
|
||||
|
||||
let available_parallelism=std::thread::available_parallelism()?.get();
|
||||
let read_dir=tokio::fs::read_dir(dir).await?;
|
||||
let tally=tokio_stream::wrappers::ReadDirStream::new(read_dir).map(|dir_entry|async move{
|
||||
tokio_stream::wrappers::ReadDirStream::new(read_dir).map(|dir_entry|async move{
|
||||
let entry=dir_entry?;
|
||||
let path=entry.path();
|
||||
let file=tokio::fs::read(path.as_path()).await?;
|
||||
Ok((path,file))
|
||||
})
|
||||
.buffer_unordered(PREFETCH_QUEUE)
|
||||
.map(|result:Result<_,Error>|async move{
|
||||
let (path,file)=result?;
|
||||
.try_for_each_concurrent(available_parallelism,|(path,file)|async move{
|
||||
let file_stem=path.file_stem().unwrap().to_owned();
|
||||
let result=tokio::task::spawn_blocking(move||{
|
||||
let block_v0=v0::read_all_to_block(std::io::Cursor::new(file.as_slice())).map_err(RoundTripError::Decode)?;
|
||||
let mut data=Vec::with_capacity(file.len());
|
||||
let block_v1=strafesnet_roblox_bot_file::convert::from_v0(&block_v0);
|
||||
v1::serialize(&block_v1,&mut std::io::Cursor::new(&mut data)).map_err(RoundTripError::Encode)?;
|
||||
let size_before=file.len();
|
||||
let size_after=data.len();
|
||||
Ok((size_before,size_after))
|
||||
let block=v0::read_all_to_block(std::io::Cursor::new(file.as_slice())).map_err(SimError::Decode)?;
|
||||
run_roblox_bot_in_strafe_client_physics(physics_data,&block,file_stem,offset);
|
||||
Ok(())
|
||||
}).await?;
|
||||
match result{
|
||||
Err(err)=>Err(Error::BotFile{path,err}),
|
||||
Ok(block)=>Ok((path,block)),
|
||||
Ok(())=>Ok(()),
|
||||
}
|
||||
})
|
||||
.buffer_unordered(available_parallelism)
|
||||
.try_fold(FoldState::new(),async|mut state,(path,(size_before,size_after))|{
|
||||
state.accumulate(size_before as u64,size_after as u64);
|
||||
println!("{:?} {}",path.file_name(),state);
|
||||
Ok(state)
|
||||
}).await?;
|
||||
println!("{}",tally);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user