add proper errors
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1938,6 +1938,7 @@ dependencies = [
|
||||
"strafesnet_common",
|
||||
"strafesnet_graphics",
|
||||
"strafesnet_roblox_bot_file",
|
||||
"thiserror 2.0.18",
|
||||
"wgpu",
|
||||
]
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use strafesnet_common::session::Time as SessionTime;
|
||||
fn main(){
|
||||
let bot=include_bytes!("../../web-demo/bhop_marble_7cf33a64-7120-4514-b9fa-4fe29d9523d.qbot");
|
||||
let timelines=v0::read_all_to_block(std::io::Cursor::new(bot)).unwrap();
|
||||
let bot=bot::CompleteBot::new(timelines);
|
||||
let bot=bot::CompleteBot::new(timelines).unwrap();
|
||||
let bvh=bvh::Bvh::new(&bot);
|
||||
|
||||
// sample the position at 0.24s
|
||||
@@ -28,7 +28,7 @@ fn main(){
|
||||
fn get_position_no_panic(){
|
||||
let bot_file=include_bytes!("../../files/000002d3-852a-4e9f-b0c9-c95411683806.qbot");
|
||||
let timelines=v0::read_all_to_block(std::io::Cursor::new(bot_file)).unwrap();
|
||||
let bot=bot::CompleteBot::new(timelines);
|
||||
let bot=bot::CompleteBot::new(timelines).unwrap();
|
||||
let head=head::PlaybackHead::new(&bot,SessionTime::ZERO);
|
||||
// This can panic if the head is mismanaged!
|
||||
let _pos=head.get_position(&bot,SessionTime::ZERO);
|
||||
@@ -38,7 +38,7 @@ fn get_position_no_panic(){
|
||||
fn get_position_no_panic2(){
|
||||
let bot_file=include_bytes!("../../files/03f3eb2c-d33d-44ea-ba60-67b685d1140d.qbot");
|
||||
let timelines=v0::read_all_to_block(std::io::Cursor::new(bot_file)).unwrap();
|
||||
let bot=bot::CompleteBot::new(timelines);
|
||||
let bot=bot::CompleteBot::new(timelines).unwrap();
|
||||
println!("duration={}",bot.duration());
|
||||
println!("num_events={}",bot.timelines().output_events.len());
|
||||
for event in &bot.timelines().output_events{
|
||||
|
||||
@@ -9,3 +9,4 @@ wgpu.workspace = true
|
||||
strafesnet_common.workspace = true
|
||||
strafesnet_graphics.workspace = true
|
||||
strafesnet_roblox_bot_file.workspace = true
|
||||
thiserror = "2.0.18"
|
||||
|
||||
@@ -4,6 +4,25 @@ use strafesnet_common::physics::{Time as PhysicsTime,TimeInner as PhysicsTimeInn
|
||||
use strafesnet_roblox_bot_file::v0;
|
||||
|
||||
use crate::head::{Time as PlaybackTime,TimeInner as PlaybackTimeInner};
|
||||
use crate::time;
|
||||
|
||||
#[derive(Debug,thiserror::Error)]
|
||||
pub enum Error{
|
||||
#[error("Bot output timeline has no events")]
|
||||
NoOutputEvents,
|
||||
#[error("Time conversion failed: {0}")]
|
||||
Time(#[from]time::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug,thiserror::Error)]
|
||||
pub enum RunDurationError{
|
||||
#[error("Bot run timeline has no RunStart event")]
|
||||
NoRunStart,
|
||||
#[error("Bot run timeline has no RunFinish event")]
|
||||
NoRunFinish,
|
||||
#[error("Time conversion failed: {0}")]
|
||||
Time(time::Error),
|
||||
}
|
||||
|
||||
/// A loaded bot file.
|
||||
pub struct CompleteBot{
|
||||
@@ -17,19 +36,21 @@ impl CompleteBot{
|
||||
pub(crate) const CAMERA_OFFSET:glam::Vec3=glam::vec3(0.0,2.0,0.0);
|
||||
pub fn new(
|
||||
timelines:v0::Block,
|
||||
)->Self{
|
||||
let start=crate::time::from_float(timelines.output_events.first().unwrap().time).unwrap();
|
||||
let end=crate::time::from_float(timelines.output_events.last().unwrap().time).unwrap();
|
||||
)->Result<Self,Error>{
|
||||
let start_event=timelines.output_events.first().ok_or(Error::NoOutputEvents)?;
|
||||
let end_event=timelines.output_events.last().ok_or(Error::NoOutputEvents)?;
|
||||
let start=time::from_float(start_event.time).map_err(Error::Time)?;
|
||||
let end=time::from_float(end_event.time).map_err(Error::Time)?;
|
||||
let world_position=timelines.world_events.iter().find_map(|event|match &event.event{
|
||||
v0::WorldEvent::Reset(world_reset_event)=>Some(world_reset_event.position),
|
||||
_=>None,
|
||||
}).expect("Map must contain a WorldReset event");
|
||||
Self{
|
||||
Ok(Self{
|
||||
timer:TimerFixed::new(PlaybackTime::ZERO,start),
|
||||
duration:end-start,
|
||||
timelines,
|
||||
world_offset:glam::vec3(world_position.x,world_position.y,world_position.z),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub fn time(&self,time:PlaybackTime)->PhysicsTime{
|
||||
self.timer.time(time)
|
||||
@@ -47,18 +68,18 @@ impl CompleteBot{
|
||||
pub const fn timelines(&self)->&v0::Block{
|
||||
&self.timelines
|
||||
}
|
||||
pub fn run_duration(&self,mode_id:v0::ModeID)->Option<RunTime>{
|
||||
pub fn run_duration(&self,mode_id:v0::ModeID)->Result<RunTime,RunDurationError>{
|
||||
let mut it=self.timelines.run_events.iter().rev();
|
||||
let end=it.find_map(|event|match &event.event{
|
||||
v0::RunEvent::Finish(run_start_event) if run_start_event.mode==mode_id=>Some(event.time),
|
||||
_=>None,
|
||||
})?;
|
||||
}).ok_or(RunDurationError::NoRunStart)?;
|
||||
let start=it.find_map(|event|match &event.event{
|
||||
v0::RunEvent::Start(run_start_event) if run_start_event.mode==mode_id=>Some(event.time),
|
||||
_=>None,
|
||||
})?;
|
||||
let start=crate::time::from_float(start).unwrap();
|
||||
let end=crate::time::from_float(end).unwrap();
|
||||
Some(end-start)
|
||||
}).ok_or(RunDurationError::NoRunFinish)?;
|
||||
let start=time::from_float(start).map_err(RunDurationError::Time)?;
|
||||
let end=time::from_float(end).map_err(RunDurationError::Time)?;
|
||||
Ok(end-start)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
use strafesnet_graphics::graphics::GraphicsState;
|
||||
|
||||
#[derive(Debug,thiserror::Error)]
|
||||
pub enum ChangeMapError{
|
||||
#[error("Map does not have a main mode")]
|
||||
NoMainMode,
|
||||
#[error("Map does not have a start zone")]
|
||||
NoStartZone,
|
||||
}
|
||||
|
||||
/// The graphics state, essentially a handle to all the information on the GPU.
|
||||
pub struct Graphics{
|
||||
graphics:GraphicsState,
|
||||
@@ -13,13 +21,14 @@ impl Graphics{
|
||||
start_offset:glam::Vec3::ZERO,
|
||||
}
|
||||
}
|
||||
pub fn change_map(&mut self,device:&wgpu::Device,queue:&wgpu::Queue,map:&strafesnet_common::map::CompleteMap){
|
||||
pub fn change_map(&mut self,device:&wgpu::Device,queue:&wgpu::Queue,map:&strafesnet_common::map::CompleteMap)->Result<(),ChangeMapError>{
|
||||
self.graphics.clear();
|
||||
self.graphics.generate_models(device,queue,map);
|
||||
let modes=map.modes.clone().denormalize();
|
||||
let mode=modes.get_mode(strafesnet_common::gameplay_modes::ModeId::MAIN).expect("Map does not have a main mode");
|
||||
let start_zone=map.models.get(mode.get_start().get() as usize).expect("Map does not have a start zone");
|
||||
let mode=modes.get_mode(strafesnet_common::gameplay_modes::ModeId::MAIN).ok_or(ChangeMapError::NoMainMode)?;
|
||||
let start_zone=map.models.get(mode.get_start().get() as usize).ok_or(ChangeMapError::NoStartZone)?;
|
||||
self.start_offset=glam::Vec3::from_array(start_zone.transform.translation.map(|f|f.into()).to_array());
|
||||
Ok(())
|
||||
}
|
||||
pub fn resize(&mut self,device:&wgpu::Device,size:glam::UVec2,fov:glam::Vec2){
|
||||
self.graphics.resize(device,size,fov);
|
||||
|
||||
@@ -99,10 +99,10 @@ impl<'a> PlayerWorker<'a>{
|
||||
self.graphics_thread.resize(device,size,fov);
|
||||
},
|
||||
Instruction::ChangeMap(complete_map)=>{
|
||||
self.graphics_thread.change_map(device,queue,&complete_map);
|
||||
self.graphics_thread.change_map(device,queue,&complete_map).unwrap();
|
||||
},
|
||||
Instruction::LoadReplay(bot)=>{
|
||||
let bot=CompleteBot::new(bot);
|
||||
let bot=CompleteBot::new(bot).unwrap();
|
||||
let playback_head=PlaybackHead::new(&bot,SessionTime::ZERO);
|
||||
self.playback=Some(Playback{
|
||||
bot,
|
||||
|
||||
@@ -126,7 +126,7 @@ fn encode(params:EncodeParams)->Result<(),EncodeError>{
|
||||
.map_err(EncodeError::CreateDevice)?;
|
||||
|
||||
// playback
|
||||
let bot=strafesnet_roblox_bot_player::bot::CompleteBot::new(timelines);
|
||||
let bot=strafesnet_roblox_bot_player::bot::CompleteBot::new(timelines).unwrap();
|
||||
let mut playback_head=strafesnet_roblox_bot_player::head::PlaybackHead::new(&bot,SessionTime::ZERO);
|
||||
|
||||
let mut wgpu_state = WgpuState::new(
|
||||
@@ -371,7 +371,7 @@ impl WgpuState {
|
||||
}
|
||||
|
||||
fn change_map(&mut self,map:&strafesnet_common::map::CompleteMap){
|
||||
self.graphics.change_map(&self.device,&self.queue,map);
|
||||
self.graphics.change_map(&self.device,&self.queue,map).unwrap();
|
||||
}
|
||||
|
||||
fn render(&mut self,pos:glam::Vec3,angles:glam::Vec2) {
|
||||
|
||||
@@ -66,8 +66,9 @@ impl Graphics{
|
||||
self.graphics.resize(&self.device,size,[fov_slope_x as f32,fov_slope_y as f32].into());
|
||||
}
|
||||
#[wasm_bindgen]
|
||||
pub fn change_map(&mut self,map:&CompleteMap){
|
||||
self.graphics.change_map(&self.device,&self.queue,&map.map);
|
||||
pub fn change_map(&mut self,map:&CompleteMap)->Result<(),JsError>{
|
||||
self.graphics.change_map(&self.device,&self.queue,&map.map).map_err(|e|JsError::new(&e.to_string()))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +82,7 @@ impl CompleteBot{
|
||||
pub fn new(data:&[u8])->Result<Self,JsError>{
|
||||
let timelines=v0::read_all_to_block(std::io::Cursor::new(data)).map_err(|e|JsError::new(&e.to_string()))?;
|
||||
Ok(Self{
|
||||
bot:bot::CompleteBot::new(timelines),
|
||||
bot:bot::CompleteBot::new(timelines).map_err(|e|JsError::new(&e.to_string()))?,
|
||||
})
|
||||
}
|
||||
#[wasm_bindgen]
|
||||
@@ -89,9 +90,9 @@ impl CompleteBot{
|
||||
self.bot.duration().into()
|
||||
}
|
||||
#[wasm_bindgen]
|
||||
pub fn run_duration(&self,mode_id:u32)->Option<f64>{
|
||||
pub fn run_duration(&self,mode_id:u32)->Result<f64,JsError>{
|
||||
let mode=v0::ModeID(mode_id);
|
||||
Some(self.bot.run_duration(mode)?.into())
|
||||
Ok(self.bot.run_duration(mode).map_err(|e|JsError::new(&e.to_string()))?.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user