forked from StrafesNET/strafe-project
Compare commits
1 Commits
roblox-bot
...
web-size-h
Author | SHA1 | Date | |
---|---|---|---|
fb3869b64e |
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -2283,7 +2283,6 @@ dependencies = [
|
||||
"strafesnet_common",
|
||||
"strafesnet_deferred_loader",
|
||||
"strafesnet_rbx_loader",
|
||||
"strafesnet_roblox_bot_file",
|
||||
"strafesnet_snf",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
@ -2340,16 +2339,6 @@ dependencies = [
|
||||
"strafesnet_common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strafesnet_roblox_bot_file"
|
||||
version = "0.2.0"
|
||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||
checksum = "e9c0c75ba772a5c430083c73d352049b84dd218947473189552d2e10785087b6"
|
||||
dependencies = [
|
||||
"binrw",
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strafesnet_snf"
|
||||
version = "0.2.0"
|
||||
|
@ -27,7 +27,6 @@ strafesnet_bsp_loader = { path = "../lib/bsp_loader", registry = "strafesnet", o
|
||||
strafesnet_common = { path = "../lib/common", registry = "strafesnet" }
|
||||
strafesnet_deferred_loader = { path = "../lib/deferred_loader", features = ["legacy"], registry = "strafesnet", optional = true }
|
||||
strafesnet_rbx_loader = { path = "../lib/rbx_loader", registry = "strafesnet", optional = true }
|
||||
strafesnet_roblox_bot_file = { version = "0.2.0", registry = "strafesnet" }
|
||||
strafesnet_snf = { path = "../lib/snf", registry = "strafesnet", optional = true }
|
||||
wasm-bindgen = "0.2.99"
|
||||
wasm-bindgen-futures = "0.4.49"
|
||||
|
@ -59,13 +59,10 @@ impl std::fmt::Display for LoadError{
|
||||
}
|
||||
impl std::error::Error for LoadError{}
|
||||
|
||||
pub fn load_file<P:AsRef<std::path::Path>>(path:P)->Result<strafesnet_common::map::CompleteMap,LoadError>{
|
||||
pub fn load<P:AsRef<std::path::Path>>(path:P)->Result<strafesnet_common::map::CompleteMap,LoadError>{
|
||||
//blocking because it's simpler...
|
||||
let file=std::fs::File::open(path).map_err(LoadError::File)?;
|
||||
load(file)
|
||||
}
|
||||
pub fn load<R:Read+std::io::Seek>(reader:R)->Result<strafesnet_common::map::CompleteMap,LoadError>{
|
||||
match read(reader).map_err(LoadError::ReadError)?{
|
||||
match read(file).map_err(LoadError::ReadError)?{
|
||||
#[cfg(feature="snf")]
|
||||
DataStructure::StrafesNET(map)=>Ok(map),
|
||||
#[cfg(feature="roblox")]
|
||||
|
@ -14,6 +14,9 @@ WorkerDescription{
|
||||
*/
|
||||
//up to three frames in flight, dropping new frame requests when all three are busy, and dropping output frames when one renders out of order
|
||||
|
||||
fn print(message:&str){
|
||||
web_sys::console::log_1(&message.into());
|
||||
}
|
||||
pub fn new<'a>(
|
||||
mut graphics:crate::graphics::GraphicsState,
|
||||
mut config:wgpu::SurfaceConfiguration,
|
||||
@ -33,10 +36,18 @@ pub fn new<'a>(
|
||||
}
|
||||
Instruction::Render(frame_state)=>{
|
||||
if let Some((size,user_settings))=resize.take(){
|
||||
println!("Resizing to {:?}",size);
|
||||
print(format!("Resizing to {:?}",size).as_str());
|
||||
//let t0=std::time::Instant::now();
|
||||
config.width=size.width.clamp(1,2560/2);
|
||||
config.height=size.height.clamp(1,1440/2);
|
||||
match size{
|
||||
winit::dpi::PhysicalSize{width:2560,height:1440}=>{
|
||||
config.width=size.width.clamp(1,2560);
|
||||
config.height=size.height.clamp(1,1440);
|
||||
},
|
||||
_=>{
|
||||
config.width=size.width.clamp(1,1280);
|
||||
config.height=size.height.clamp(1,720);
|
||||
}
|
||||
}
|
||||
surface.configure(&device,&config);
|
||||
graphics.resize(&device,&config,&user_settings);
|
||||
//println!("Resize took {:?}",t0.elapsed());
|
||||
|
@ -273,15 +273,6 @@ 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(
|
||||
@ -974,7 +965,7 @@ pub struct PhysicsState{
|
||||
//input_state
|
||||
input_state:InputState,
|
||||
//style
|
||||
pub style:StyleModifiers,//mode style with custom style updates applied
|
||||
style:StyleModifiers,//mode style with custom style updates applied
|
||||
//gameplay_state
|
||||
mode_state:ModeState,
|
||||
move_state:MoveState,
|
||||
@ -1076,7 +1067,7 @@ impl PhysicsState{
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PhysicsContext{
|
||||
pub state:PhysicsState,//this captures the entire state of the physics.
|
||||
state:PhysicsState,//this captures the entire state of the physics.
|
||||
data:PhysicsData,//data currently loaded into memory which is needded for physics to run, but is not part of the state.
|
||||
}
|
||||
//the physics consumes the generic PhysicsInstruction, but can only emit the more narrow PhysicsInternalInstruction
|
||||
|
@ -212,135 +212,14 @@ impl MouseInterpolator{
|
||||
}
|
||||
}
|
||||
|
||||
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>,
|
||||
physics:crate::physics::PhysicsContext,
|
||||
}
|
||||
impl PlayBacker{
|
||||
pub fn new(
|
||||
physics:crate::physics::PhysicsContext,
|
||||
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,
|
||||
}
|
||||
}
|
||||
pub fn handle_instruction(&mut self,TimedInstruction{time,instruction}:&TimedInstruction<Instruction>){
|
||||
//match the instruction so the playback is pausable :D
|
||||
match instruction{
|
||||
&Instruction::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/Time::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:Time)->crate::graphics::FrameState{
|
||||
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/Time::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=crate::physics::Body{
|
||||
time,
|
||||
position:strafesnet_common::integer::Planar64Vec3::new(p)+self.physics.state.style.camera_offset,
|
||||
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=crate::physics::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)
|
||||
);
|
||||
crate::graphics::FrameState{
|
||||
body,
|
||||
camera,
|
||||
time,
|
||||
}
|
||||
}
|
||||
pub fn user_settings(&self)->crate::settings::UserSettings{
|
||||
//oof, settings ignored
|
||||
crate::settings::UserSettings::default()
|
||||
}
|
||||
pub fn change_map(&mut self,time:Time,map:&strafesnet_common::map::CompleteMap){
|
||||
self.physics.generate_models(&map);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new<'a>(
|
||||
mut graphics_worker:crate::compat_worker::INWorker<'a,crate::graphics_worker::Instruction>,
|
||||
user_settings:crate::settings::UserSettings,
|
||||
)->crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction>>{
|
||||
let physics=crate::physics::PhysicsContext::default();
|
||||
//load bot
|
||||
let data=include_bytes!("/home/quat/strafesnet/roblox_bot_file/files/bhop_marble_7cf33a64-7120-4514-b9fa-4fe29d9523d");
|
||||
let mut bot_file=strafesnet_roblox_bot_file::v0::File::new(std::io::BufReader::new(std::io::Cursor::new(data))).unwrap();
|
||||
let mut interpolator=PlayBacker::new(
|
||||
let mut interpolator=MouseInterpolator::new(
|
||||
physics,
|
||||
bot_file.read_all().unwrap(),
|
||||
user_settings
|
||||
);
|
||||
crate::compat_worker::QNWorker::new(move |ins:TimedInstruction<Instruction>|{
|
||||
interpolator.handle_instruction(&ins);
|
||||
@ -350,7 +229,7 @@ pub fn new<'a>(
|
||||
graphics_worker.send(crate::graphics_worker::Instruction::Render(frame_state)).unwrap();
|
||||
},
|
||||
Instruction::Resize(size)=>{
|
||||
graphics_worker.send(crate::graphics_worker::Instruction::Resize(size,interpolator.user_settings())).unwrap();
|
||||
graphics_worker.send(crate::graphics_worker::Instruction::Resize(size,interpolator.user_settings().clone())).unwrap();
|
||||
},
|
||||
Instruction::ChangeMap(map)=>{
|
||||
interpolator.change_map(ins.time,&map);
|
||||
|
@ -211,13 +211,13 @@ pub async fn setup_and_start(title:String){
|
||||
setup_context,
|
||||
);
|
||||
|
||||
//if let Some(arg)=std::env::args().nth(1){
|
||||
//let path=std::path::PathBuf::from(arg);
|
||||
if let Some(arg)=std::env::args().nth(1){
|
||||
let path=std::path::PathBuf::from(arg);
|
||||
window_thread.send(TimedInstruction{
|
||||
time:integer::Time::ZERO,
|
||||
instruction:WindowInstruction::WindowEvent(winit::event::WindowEvent::DroppedFile("".into())),
|
||||
instruction:WindowInstruction::WindowEvent(winit::event::WindowEvent::DroppedFile(path)),
|
||||
}).unwrap();
|
||||
//};
|
||||
};
|
||||
|
||||
println!("Entering event loop...");
|
||||
let root_time=chrono::Utc::now();
|
||||
|
@ -25,10 +25,8 @@ impl WindowContext<'_>{
|
||||
}
|
||||
fn window_event(&mut self,time:integer::Time,event:winit::event::WindowEvent){
|
||||
match event{
|
||||
winit::event::WindowEvent::DroppedFile(_path)=>{
|
||||
//match crate::file::load_file(path.as_path()){
|
||||
let data=include_bytes!("/run/media/quat/Files/Documents/map-files/verify-scripts/maps/bhop_snfm/5692093612.snfm");
|
||||
match crate::file::load(std::io::Cursor::new(data.as_slice())){
|
||||
winit::event::WindowEvent::DroppedFile(path)=>{
|
||||
match crate::file::load(path.as_path()){
|
||||
Ok(map)=>self.physics_thread.send(TimedInstruction{time,instruction:crate::physics_worker::Instruction::ChangeMap(map)}).unwrap(),
|
||||
Err(e)=>println!("Failed to load map: {e}"),
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>Strafe Client</title>
|
||||
|
||||
<base data-trunk-public-url />
|
||||
@ -13,13 +13,25 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.root {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.main-canvas {
|
||||
margin: 0;
|
||||
/* This allows the flexbox to grow to max size, this is needed for WebGPU */
|
||||
flex: 1;
|
||||
/* This forces CSS to ignore the width/height of the canvas, this is needed for WebGL */
|
||||
contain: size;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas class="main-canvas" id="canvas"></canvas>
|
||||
<div class="root">
|
||||
<canvas class="main-canvas" id="canvas"></canvas>
|
||||
</div>
|
||||
<link data-trunk rel="rust" href="../strafe-client/Cargo.toml"/>
|
||||
</body>
|
||||
</html>
|
||||
|
Reference in New Issue
Block a user