use binrw::{BinReaderExt, binrw}; pub enum Error{ InvalidHeader, InvalidSegment(binrw::Error), InvalidSegmentId(u64), File(crate::file::Error), } /* block types BLOCK_BOT_HEADER: u128 map_resource_uuid //which map is this bot running //don't include style info in bot header because it's in the simulation state //blocks are laid out in chronological order, but indices may jump around. u64 num_segments for _ in 0..num_segments{ i64 time //simulation_state timestamp u64 block_id } BLOCK_BOT_SEGMENT: //format version indicates what version of these structures to use SimulationState simulation_state //SimulationState is just under ClientState which includes Play/Pause events that the simulation doesn't know about. //to read, greedily decode instructions until eof loop{ //delta encode as much as possible (time,mousepos) //strafe ticks are implied //physics can be implied in an input-only bot file TimedInstruction instruction } */ //error hiding mock code mod simulation{ #[super::binrw] #[brw(little)] pub struct State{} #[super::binrw] #[brw(little)] pub struct Instruction{} } mod instruction{ #[super::binrw] #[brw(little)] pub struct TimedInstruction{ time:u64, instruction:Instruction } } mod timeline{ #[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, timeline:timeline::Timeline, segment_id_to_block_id:Vec, } impl StreamableBot{ pub(crate) fn new(file:crate::file::File)->Result{ Err(Error::InvalidHeader) } 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) } }