1
0
Fork 0
mirror of https://codeberg.org/demostf/parser.git synced 2026-06-03 10:14:06 +02:00

allow changing analyser

This commit is contained in:
Robin Appelman 2019-03-23 17:45:56 +01:00
commit 86be659513
7 changed files with 56 additions and 54 deletions

View file

@ -13,8 +13,7 @@ fn bench_file(input_file: &str, b: &mut Bencher) {
let stream: Stream = demo.get_stream(); let stream: Stream = demo.get_stream();
b.iter(|| { b.iter(|| {
let parser = DemoParser::new(stream.clone()); let (_, state) = DemoParser::parse_demo(stream.clone()).unwrap();
let (_, state) = parser.parse_demo().unwrap();
test::black_box(state); test::black_box(state);
}) })
} }

View file

@ -11,9 +11,7 @@ fn main() -> std::result::Result<(), Box<ParseError>> {
let path = args[1].clone(); let path = args[1].clone();
let file = fs::read(path).expect("Unable to read file"); let file = fs::read(path).expect("Unable to read file");
let demo = Demo::new(file); let demo = Demo::new(file);
let stream: Stream = demo.get_stream(); let (_, state) = DemoParser::parse_demo(demo.get_stream())?;
let parser = DemoParser::new(stream);
let (_, state) = parser.parse_demo()?;
let json = serde_json::to_string(&state).unwrap_or("err".to_string()); let json = serde_json::to_string(&state).unwrap_or("err".to_string());
println!("{}", json); println!("{}", json);
Ok(()) Ok(())

View file

@ -1,18 +1,18 @@
use std::collections::HashMap; use std::collections::HashMap;
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
use serde_repr::{Serialize_repr, Deserialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::{ParserState, ReadResult, Stream};
use crate::demo::gameevent_gen::{ use crate::demo::gameevent_gen::{
GameEvent, PlayerDeathEvent, PlayerSpawnEvent, TeamPlayRoundWinEvent, GameEvent, PlayerDeathEvent, PlayerSpawnEvent, TeamPlayRoundWinEvent,
}; };
use crate::demo::message::{Message, MessageType};
use crate::demo::message::packetentities::EntityId; use crate::demo::message::packetentities::EntityId;
use crate::demo::message::usermessage::{ChatMessageKind, SayText2Message, UserMessage}; use crate::demo::message::usermessage::{ChatMessageKind, SayText2Message, UserMessage};
use crate::demo::message::{Message, MessageType};
use crate::demo::packet::stringtable::StringTableEntry; use crate::demo::packet::stringtable::StringTableEntry;
use crate::demo::parser::handler::{MessageHandler, StringTableEntryHandler}; use crate::demo::parser::handler::MessageHandler;
use crate::demo::vector::Vector; use crate::demo::vector::Vector;
use crate::{ParserState, ReadResult, Stream};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ChatMassage { pub struct ChatMassage {
@ -176,6 +176,8 @@ pub struct Analyser {
} }
impl MessageHandler for Analyser { impl MessageHandler for Analyser {
type Output = MatchState;
fn does_handle(message_type: MessageType) -> bool { fn does_handle(message_type: MessageType) -> bool {
match message_type { match message_type {
MessageType::GameEvent | MessageType::UserMessage => true, MessageType::GameEvent | MessageType::UserMessage => true,
@ -193,9 +195,7 @@ impl MessageHandler for Analyser {
_ => {} _ => {}
} }
} }
}
impl StringTableEntryHandler for Analyser {
fn handle_string_entry(&mut self, table: &String, _index: usize, entry: &StringTableEntry) { fn handle_string_entry(&mut self, table: &String, _index: usize, entry: &StringTableEntry) {
match table.as_str() { match table.as_str() {
"userinfo" => { "userinfo" => {
@ -211,6 +211,17 @@ impl StringTableEntryHandler for Analyser {
_ => {} _ => {}
} }
} }
fn get_output(self, state: ParserState) -> MatchState {
MatchState {
start_tick: self.start_tick,
interval_per_tick: state.demo_meta.interval_per_tick,
chat: self.chat,
deaths: self.deaths,
rounds: self.rounds,
users: UserState::from_users_and_spawn(self.users, self.user_spawns),
}
}
} }
impl Analyser { impl Analyser {
@ -274,17 +285,6 @@ impl Analyser {
} }
Ok(()) Ok(())
} }
pub fn get_match_state(self, state: ParserState) -> MatchState {
MatchState {
start_tick: self.start_tick,
interval_per_tick: state.demo_meta.interval_per_tick,
chat: self.chat,
deaths: self.deaths,
rounds: self.rounds,
users: UserState::from_users_and_spawn(self.users, self.user_spawns),
}
}
} }
#[derive(Debug, Serialize, Deserialize, PartialEq)] #[derive(Debug, Serialize, Deserialize, PartialEq)]

View file

@ -2,30 +2,37 @@ use crate::demo::message::{Message, MessageType};
use crate::demo::packet::datatable::{SendTable, ServerClass}; use crate::demo::packet::datatable::{SendTable, ServerClass};
use crate::demo::packet::stringtable::{StringTable, StringTableEntry}; use crate::demo::packet::stringtable::{StringTable, StringTableEntry};
use crate::demo::packet::Packet; use crate::demo::packet::Packet;
use crate::demo::parser::analyser::{Analyser, MatchState}; use crate::demo::parser::analyser::{Analyser};
use crate::ParserState; use crate::ParserState;
pub trait MessageHandler { pub trait MessageHandler {
type Output;
fn does_handle(message_type: MessageType) -> bool; fn does_handle(message_type: MessageType) -> bool;
fn handle_message(&mut self, message: Message, tick: u32); fn handle_message(&mut self, message: Message, tick: u32);
}
pub trait StringTableEntryHandler {
fn handle_string_entry(&mut self, table: &String, index: usize, entries: &StringTableEntry); fn handle_string_entry(&mut self, table: &String, index: usize, entries: &StringTableEntry);
fn get_output(self, state: ParserState) -> Self::Output;
} }
#[derive(Default)] #[derive(Default)]
pub struct DemoHandler { pub struct DemoHandler<T: MessageHandler> {
tick: u32, tick: u32,
string_table_names: Vec<String>, string_table_names: Vec<String>,
analyser: Analyser, analyser: T,
state_handler: ParserState, state_handler: ParserState,
} }
impl DemoHandler { impl DemoHandler<Analyser> {
pub fn new() -> Self { pub fn new() -> Self {
let analyser = Analyser::new(); Self::with_analyser(Analyser::new())
}
}
impl<T: MessageHandler> DemoHandler<T> {
pub fn with_analyser(analyser: T) -> Self {
let state_handler = ParserState::new(); let state_handler = ParserState::new();
DemoHandler { DemoHandler {
@ -110,8 +117,8 @@ impl DemoHandler {
} }
} }
pub fn get_match_state(self) -> MatchState { pub fn get_output(self) -> T::Output {
self.analyser.get_match_state(self.state_handler) self.analyser.get_output(self.state_handler)
} }
pub fn get_parser_state(&self) -> &ParserState { pub fn get_parser_state(&self) -> &ParserState {

View file

@ -3,8 +3,9 @@ use bitstream_reader::{BitRead, BitSkip, LittleEndian, ReadError};
use crate::demo::gamevent::{GameEventValue, GameEventValueType}; use crate::demo::gamevent::{GameEventValue, GameEventValueType};
use crate::demo::header::Header; use crate::demo::header::Header;
use crate::demo::packet::Packet; use crate::demo::packet::Packet;
use crate::demo::parser::analyser::Analyser;
pub use crate::demo::parser::analyser::MatchState; pub use crate::demo::parser::analyser::MatchState;
use crate::demo::parser::handler::DemoHandler; use crate::demo::parser::handler::{DemoHandler, MessageHandler};
pub use crate::demo::parser::state::ParserState; pub use crate::demo::parser::state::ParserState;
use crate::Stream; use crate::Stream;
@ -85,28 +86,23 @@ impl<T: BitSkip<LittleEndian>> ParseBitSkip for T {
} }
} }
pub struct DemoParser { pub struct DemoParser {}
stream: Stream,
handler: DemoHandler,
}
impl DemoParser { impl DemoParser {
pub fn new(stream: Stream) -> Self { pub fn parse_demo(stream: Stream) -> Result<(Header, MatchState)> {
DemoParser { Self::parse_with_analyser(stream, Analyser::new())
stream,
handler: DemoHandler::new(),
}
} }
pub fn parse_demo(mut self) -> Result<(Header, MatchState)> { pub fn parse_with_analyser<T: MessageHandler>(mut stream: Stream, analyser: T) -> Result<(Header, T::Output)> {
let header = Header::read(&mut self.stream)?; let mut handler = DemoHandler::with_analyser(analyser);
let header = Header::read(&mut stream)?;
loop { loop {
let packet = Packet::parse(&mut self.stream, self.handler.get_parser_state())?; let packet = Packet::parse(&mut stream, handler.get_parser_state())?;
match packet { match packet {
Packet::Stop(_) => break, Packet::Stop(_) => break,
packet => self.handler.handle_packet(packet), packet => handler.handle_packet(packet),
}; };
} }
Ok((header, self.handler.get_match_state())) Ok((header, handler.get_output()))
} }
} }

View file

@ -7,7 +7,7 @@ use crate::demo::message::packetentities::EntityId;
use crate::demo::message::stringtable::StringTableMeta; use crate::demo::message::stringtable::StringTableMeta;
use crate::demo::packet::datatable::{SendTable, ServerClass}; use crate::demo::packet::datatable::{SendTable, ServerClass};
use crate::demo::packet::stringtable::StringTableEntry; use crate::demo::packet::stringtable::StringTableEntry;
use crate::demo::parser::handler::{MessageHandler, StringTableEntryHandler}; use crate::demo::parser::handler::{MessageHandler};
use crate::demo::sendprop::SendProp; use crate::demo::sendprop::SendProp;
use crate::Stream; use crate::Stream;
use crate::demo::parser::analyser::Analyser; use crate::demo::parser::analyser::Analyser;
@ -73,6 +73,8 @@ impl ParserState {
} }
impl MessageHandler for ParserState { impl MessageHandler for ParserState {
type Output = Self;
fn does_handle(message_type: MessageType) -> bool { fn does_handle(message_type: MessageType) -> bool {
match message_type { match message_type {
MessageType::ServerInfo MessageType::ServerInfo
@ -96,9 +98,7 @@ impl MessageHandler for ParserState {
_ => {} _ => {}
} }
} }
}
impl StringTableEntryHandler for ParserState {
fn handle_string_entry(&mut self, table: &String, _index: usize, entry: &StringTableEntry) { fn handle_string_entry(&mut self, table: &String, _index: usize, entry: &StringTableEntry) {
match table.as_str() { match table.as_str() {
"instancebaseline" => match &entry.extra_data { "instancebaseline" => match &entry.extra_data {
@ -114,4 +114,8 @@ impl StringTableEntryHandler for ParserState {
_ => {} _ => {}
} }
} }
fn get_output(self, _state: ParserState) -> Self {
self
}
} }

View file

@ -1,14 +1,12 @@
use std::fs; use std::fs;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use tf_demo_parser::{Demo, DemoParser, Stream, MatchState}; use tf_demo_parser::{Demo, DemoParser, MatchState};
fn snapshot_test(input_file: &str, snapshot_file: &str) { fn snapshot_test(input_file: &str, snapshot_file: &str) {
let file = fs::read(input_file).expect("Unable to read file"); let file = fs::read(input_file).expect("Unable to read file");
let demo = Demo::new(file); let demo = Demo::new(file);
let stream: Stream = demo.get_stream(); let (_, state) = DemoParser::parse_demo(demo.get_stream()).unwrap();
let parser = DemoParser::new(stream);
let (_, state) = parser.parse_demo().unwrap();
let expected: MatchState = serde_json::from_slice(fs::read(snapshot_file).expect("Unable to read file").as_slice()).unwrap(); let expected: MatchState = serde_json::from_slice(fs::read(snapshot_file).expect("Unable to read file").as_slice()).unwrap();
assert_eq!(expected, state); assert_eq!(expected, state);