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:
parent
b09d0507d6
commit
86be659513
7 changed files with 56 additions and 54 deletions
|
|
@ -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);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(())
|
||||||
|
|
|
||||||
|
|
@ -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)]
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue