use democutter::cut; use pretty_assertions::assert_eq; use std::fs; use tf_demo_parser::demo::message::packetentities::EntityId; use tf_demo_parser::demo::message::Message; use tf_demo_parser::demo::packet::message::MessagePacketMeta; use tf_demo_parser::demo::parser::gamestateanalyser::GameStateAnalyser; use tf_demo_parser::demo::parser::handler::BorrowMessageHandler; use tf_demo_parser::demo::parser::MessageHandler; use tf_demo_parser::demo::sendprop::SendProp; use tf_demo_parser::{Demo, DemoParser, MessageType, ParserState}; fn test_reparse_with_analyser( f: F, ) { let file = fs::read("test_data/gully.dem").unwrap(); let output = cut(&file, 30000, 50000); let original = Demo::new(&file); let cut = Demo::new(&output); let original_parser = DemoParser::new_with_analyser(original.get_stream(), A::default()); let cut_parser = DemoParser::new_with_analyser(cut.get_stream(), A::default()); let mut original_ticks = original_parser.ticker().unwrap().1; let mut cut_ticks = cut_parser.ticker().unwrap().1; while let Some(tick) = original_ticks.next().unwrap() { if tick.tick > 30010 && tick.tick < 50000 { break; } } while let Some(tick) = cut_ticks.next().unwrap() { if tick.tick > 10 && tick.tick < 20000 { break; } } original_ticks .next() .unwrap() .expect("no more ticks in original"); cut_ticks.next().unwrap().expect("no more ticks in cut"); while let (Some(original_tick), Some(cut_tick)) = (original_ticks.next().unwrap(), cut_ticks.next().unwrap()) { if original_tick.tick >= 50000 { break; } // println!("tick {}", original_tick.tick); assert_eq!(original_tick.tick, cut_tick.tick + 30000); let original_state = &original_tick.state; let cut_state = &cut_tick.state; f(original_state, cut_state); } } #[derive(Default)] struct EntityDumper { entities: Vec<(EntityId, (Vec, Vec))>, } impl MessageHandler for EntityDumper { type Output = Vec<(EntityId, (Vec, Vec))>; fn does_handle(message_type: MessageType) -> bool { match message_type { MessageType::PacketEntities => true, _ => false, } } fn handle_message(&mut self, message: &Message, _tick: u32) { match message { Message::PacketEntities(entity_message) => { for entity in &entity_message.entities { self.entities.push(( entity.entity_index, (entity.baseline_props.clone(), entity.props.clone()), )); } } _ => {} } } fn handle_packet_meta(&mut self, _tick: u32, _meta: &MessagePacketMeta) { self.entities.clear(); } fn into_output(self, _state: &ParserState) -> Self::Output { self.entities } } impl BorrowMessageHandler for EntityDumper { fn borrow_output(&self, _state: &ParserState) -> &Self::Output { &self.entities } } #[test] fn test_reparse_game_state() { test_reparse_with_analyser::(|original_state, cut_state| { assert_eq!(original_state.world, cut_state.world); assert_eq!(original_state.players, cut_state.players); assert_eq!(original_state.buildings, cut_state.buildings); }) } #[test] fn test_reparse_entities() { test_reparse_with_analyser::(|original_state, cut_state| { assert_eq!(original_state.len(), cut_state.len()); for (original_entity, cut_entity) in original_state.iter().zip(cut_state) { assert_eq!(original_entity.0, cut_entity.0); assert_eq!(original_entity.1, cut_entity.1); } }) }