diff --git a/src/bot.rs b/src/bot.rs index c5a5c0c..3c97671 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -1,6 +1,10 @@ +use binrw::{BinReaderExt, binrw}; + pub enum Error{ InvalidHeader, - InvalidSegment, + InvalidSegment(binrw::Error), + InvalidSegmentId(u64), + File(crate::file::Error), } /* block types @@ -28,40 +32,63 @@ loop{ */ -//xdd +//error hiding mock code mod simulation{ + #[super::binrw] + #[brw(little)] pub struct State{} + #[super::binrw] + #[brw(little)] pub struct Instruction{} } mod instruction{ - pub struct TimedInstruction{instruction:Instruction} + #[super::binrw] + #[brw(little)] + pub struct TimedInstruction{ + time:u64, + instruction:Instruction + } } mod timeline{ - pub struct Timeline{timeline:Vec>} + #[super::binrw] + #[brw(little)] + pub struct Timeline{ + #[bw(try_calc(u32::try_from(instructions.len())))] + instruction_count:u32, + #[br(count=instruction_count)] + instructions:Vec> + } } //serious code +#[binrw] +#[brw(little)] struct SegmentId(u64); +#[binrw] +#[brw(little)] pub struct Segment{ state:simulation::State, + #[bw(try_calc(u32::try_from(instructions.len())))] + instruction_count:u32, + #[br(count=instruction_count)] instructions:Vec> } -pub struct StreamableBot{ - file:crate::file::File, +pub struct StreamableBot{ + file:crate::file::File, timeline:timeline::Timeline, + segment_id_to_block_id:Vec, } -impl StreamableBot{ - pub fn new(file:crate::file::File)->Result{ +impl StreamableBot{ + pub(crate) fn new(file:crate::file::File)->Result{ Err(Error::InvalidHeader) } - pub fn load_segment(&mut self,segment_id:u64)->Result{ - //load region from disk - //parse the models and determine what resources need to be loaded - //load resources into self.resources - //return Region - Err(Error::InvalidSegment) + pub fn load_segment(&mut self,segment_id:SegmentId)->Result{ + let block_id=*self.segment_id_to_block_id.get(segment_id.0 as usize).ok_or(Error::InvalidSegmentId(segment_id.0))?; + let mut block=self.file.take_block(block_id).map_err(|e|Error::File(e))?; + let segment=block.read_le().map_err(|e|Error::InvalidSegment(e))?; + Ok(segment) } } \ No newline at end of file diff --git a/src/demo.rs b/src/demo.rs index 486f861..302ea5a 100644 --- a/src/demo.rs +++ b/src/demo.rs @@ -1,3 +1,5 @@ +use binrw::BinReaderExt; + pub enum Error{ InvalidHeader, } @@ -17,12 +19,12 @@ how to do worldstate for deathrun!? */ -pub struct StreamableDemo{ - map:Box, - bots:Vec, +pub struct StreamableDemo{ + map:Box>, + bots:Vec>, } -impl StreamableDemo{ - pub fn new(file:crate::file::File)->Result{ +impl StreamableDemo{ + pub(crate) fn new(file:crate::file::File)->Result{ Err(Error::InvalidHeader) } } \ No newline at end of file diff --git a/src/file.rs b/src/file.rs index f3a2473..f1bf2b0 100644 --- a/src/file.rs +++ b/src/file.rs @@ -1,10 +1,12 @@ //file format "sniff" -use binrw::{binrw, BinReaderExt}; +use binrw::{binrw, BinReaderExt, io::TakeSeekExt}; pub enum Error{ InvalidHeader(binrw::Error), UnexpectedEOF, + InvalidBlockId(usize), + Seek(std::io::Error), } /* spec @@ -56,26 +58,35 @@ struct Header{ priming:u64, /// uuid for this file resource:u128, - #[bw(try_calc(u64::try_from(block_location.len())))] + #[bw(try_calc(u64::try_from(block_location.len()-1)))] block_count:u64, - #[br(count=block_count)] + #[br(count=block_count+1)] block_location:Vec, } +pub struct BlockId(usize); -pub(crate) struct File{ +pub(crate) struct File{ header:Header, //reference to the data + data:R, } -impl File{ - pub(crate) fn new(mut input:R)->Result{ - Ok(Self{ +impl File{ + pub(crate) fn new(mut input:R)->Result,Error>{ + Ok(File{ header:input.read_le().map_err(|e|Error::InvalidHeader(e))?, + data:input, }) } - pub(crate) fn read_block(&mut self,block_id:u64)->Result,Error>{ - Err(Error::UnexpectedEOF) + pub(crate) fn take_block(&mut self,block_id:BlockId)->Result,Error>{ + if self.header.block_location.len()<=block_id.0{ + return Err(Error::InvalidBlockId(block_id.0)) + } + let block_start=self.header.block_location[block_id.0]; + let block_end=self.header.block_location[block_id.0+1]; + self.data.seek(std::io::SeekFrom::Start(block_start)).map_err(|e|Error::Seek(e))?; + Ok((&mut self.data).take_seek(block_end-block_start)) } pub(crate) fn fourcc(&self)->FourCC{ self.header.fourcc diff --git a/src/lib.rs b/src/lib.rs index 6ea292d..d17883a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,13 +13,13 @@ pub enum Error{ Demo(demo::Error), } -pub enum SNF{ - Map(map::StreamableMap), - Bot(bot::StreamableBot), - Demo(demo::StreamableDemo), +pub enum SNF{ + Map(map::StreamableMap), + Bot(bot::StreamableBot), + Demo(demo::StreamableDemo), } -pub fn read_snf(input:R)->Result{ +pub fn read_snf(input:R)->Result,Error>{ let file=file::File::new(input).map_err(|e|Error::Header(e))?; Ok(match file.fourcc(){ file::FourCC::Map=>SNF::Map(map::StreamableMap::new(file).map_err(|e|Error::Map(e))?), @@ -27,21 +27,21 @@ pub fn read_snf(input:R)->Result{ file::FourCC::Demo=>SNF::Demo(demo::StreamableDemo::new(file).map_err(|e|Error::Demo(e))?), }) } -pub fn read_map(input:R)->Result{ +pub fn read_map(input:R)->Result,Error>{ let file=file::File::new(input).map_err(|e|Error::Header(e))?; match file.fourcc(){ file::FourCC::Map=>Ok(map::StreamableMap::new(file).map_err(|e|Error::Map(e))?), _=>Err(Error::UnexpectedFourCC) } } -pub fn read_bot(input:R)->Result{ +pub fn read_bot(input:R)->Result,Error>{ let file=file::File::new(input).map_err(|e|Error::Header(e))?; match file.fourcc(){ file::FourCC::Bot=>Ok(bot::StreamableBot::new(file).map_err(|e|Error::Bot(e))?), _=>Err(Error::UnexpectedFourCC) } } -pub fn read_demo(input:R)->Result{ +pub fn read_demo(input:R)->Result,Error>{ let file=file::File::new(input).map_err(|e|Error::Header(e))?; match file.fourcc(){ file::FourCC::Demo=>Ok(demo::StreamableDemo::new(file).map_err(|e|Error::Demo(e))?), diff --git a/src/map.rs b/src/map.rs index 53e6501..4ed7885 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1,6 +1,10 @@ +use binrw::{BinReaderExt, binrw}; + pub enum Error{ InvalidHeader, - InvalidNode, + InvalidNodeId(u64), + InvalidRegion(binrw::Error), + File(crate::file::Error), } /* block types @@ -53,12 +57,14 @@ for model_id in 0..num_models{ */ -//xdd +//error hiding mock code mod physics{ pub struct StyleModifiers{} } mod model{ pub struct IndexedModel{} + #[super::binrw] + #[brw(little)] pub struct ModelInstance{} } mod image{ @@ -73,17 +79,26 @@ pub struct BvhNodeId(u64); struct BvhNode{ // } +#[binrw] +#[brw(little)] +struct Region{ + #[bw(try_calc(u32::try_from(models.len())))] + model_count:u32, + #[br(count=model_count)] + models:Vec, +} -pub struct StreamableMap{ - file:crate::file::File, +pub struct StreamableMap{ + file:crate::file::File, style:physics::StyleModifiers,//probably should move this out of physics bvh:BvhNode, + node_id_to_block_id:Vec, //do not need this? return only new data with load_node resource_model:std::collections::HashMap, resource_image:std::collections::HashMap, } -impl StreamableMap{ - pub fn new(file:crate::file::File)->Result{ +impl StreamableMap{ + pub(crate) fn new(file:crate::file::File)->Result{ Err(Error::InvalidHeader) } pub fn load_node(&mut self,node_id:BvhNodeId)->Result,Error>{ @@ -91,6 +106,9 @@ impl StreamableMap{ //parse the models and determine what resources need to be loaded //load resources into self.resources //return Region - Err(Error::InvalidNode) + let block_id=*self.node_id_to_block_id.get(node_id.0 as usize).ok_or(Error::InvalidNodeId(node_id.0))?; + let mut block=self.file.take_block(block_id).map_err(|e|Error::File(e))?; + let region:Region=block.read_le().map_err(|e|Error::InvalidRegion(e))?; + Ok(region.models) } } \ No newline at end of file