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

normalize prop definitions during flatening

This commit is contained in:
Robin Appelman 2021-02-13 16:39:11 +01:00
commit 0a34318c65
5 changed files with 98 additions and 72 deletions

View file

@ -19,43 +19,43 @@ use tf_demo_parser::{Demo, DemoParser, MatchState, MessageType, MessageTypeAnaly
pub struct SendPropAnalyser;
// impl MessageHandler for SendPropAnalyser {
// type Output = Vec<ParseSendTable>;
//
// fn does_handle(message_type: MessageType) -> bool {
// false
// }
//
// fn into_output(self, state: &ParserState) -> Self::Output {
// state
// .send_tables
// .iter()
// .map(|v| ParseSendTable {
// name: v.name.clone(),
// props: v.props.clone(),
// needs_decoder: v.needs_decoder,
// })
// .collect()
// }
// }
//
// fn flatten_bench(input_file: &str, b: &mut Bencher) {
// let file = fs::read(input_file).expect("Unable to read file");
// let demo = Demo::new(&file);
// let stream = demo.get_stream();
// let (_, send_tables) = DemoParser::new_with_analyser(stream.clone(), SendPropAnalyser)
// .parse()
// .unwrap();
// b.iter(|| {
// let flat: Vec<_> = send_tables
// .iter()
// .map(|table| table.flatten_props(&send_tables))
// .collect();
// test::black_box(flat);
// });
// }
//
// #[bench]
// fn sendprop_test_gully(b: &mut Bencher) {
// flatten_bench("data/gully.dem", b);
// }
impl MessageHandler for SendPropAnalyser {
type Output = Vec<ParseSendTable>;
fn does_handle(message_type: MessageType) -> bool {
false
}
fn into_output(self, state: &ParserState) -> Self::Output {
state
.send_tables
.iter()
.map(|v| ParseSendTable {
name: v.name.clone(),
props: v.raw_props.clone(),
needs_decoder: v.needs_decoder,
})
.collect()
}
}
fn flatten_bench(input_file: &str, b: &mut Bencher) {
let file = fs::read(input_file).expect("Unable to read file");
let demo = Demo::new(&file);
let stream = demo.get_stream();
let (_, send_tables) = DemoParser::new_with_analyser(stream.clone(), SendPropAnalyser)
.parse()
.unwrap();
b.iter(|| {
let flat: Vec<_> = send_tables
.iter()
.map(|table| table.flatten_props(&send_tables))
.collect();
test::black_box(flat);
});
}
#[bench]
fn sendprop_test_gully(b: &mut Bencher) {
flatten_bench("data/gully.dem", b);
}

View file

@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize};
use std::cmp::min;
use std::convert::TryFrom;
use std::rc::Rc;
#[derive(BitRead, Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Display, FromStr)]
@ -121,14 +122,14 @@ impl ParseSendTable {
}
impl ParseSendTable {
pub fn flatten_props(&self, tables: &[ParseSendTable]) -> Vec<RawSendPropDefinition> {
pub fn flatten_props(&self, tables: &[ParseSendTable]) -> Result<Vec<SendPropDefinition>> {
let mut flat = Vec::with_capacity(32);
self.get_all_props(tables, &self.get_excludes(tables), &mut flat);
self.get_all_props(tables, &self.get_excludes(tables), &mut flat)?;
// sort often changed props before the others
let mut start = 0;
for i in 0..flat.len() {
if flat[i].flags.contains(SendPropFlag::ChangesOften) {
if flat[i].changes_often {
if i != start {
flat.swap(i, start);
}
@ -136,7 +137,7 @@ impl ParseSendTable {
}
}
flat
Ok(flat)
}
fn get_excludes<'a>(&'a self, tables: &'a [ParseSendTable]) -> Vec<SendPropIdentifier> {
@ -161,36 +162,40 @@ impl ParseSendTable {
&self,
tables: &[ParseSendTable],
excludes: &[SendPropIdentifier],
props: &mut Vec<RawSendPropDefinition>,
) {
props: &mut Vec<SendPropDefinition>,
) -> Result<()> {
let mut local_props = Vec::new();
self.get_all_props_iterator_props(tables, excludes, &mut local_props, props);
self.get_all_props_iterator_props(tables, excludes, &mut local_props, props)?;
props.extend_from_slice(&local_props);
Ok(())
}
fn get_all_props_iterator_props(
&self,
tables: &[ParseSendTable],
excludes: &[SendPropIdentifier],
local_props: &mut Vec<RawSendPropDefinition>,
props: &mut Vec<RawSendPropDefinition>,
) {
local_props: &mut Vec<SendPropDefinition>,
props: &mut Vec<SendPropDefinition>,
) -> Result<()> {
self.props
.iter()
.filter(|prop| !prop.is_exclude())
.filter(|prop| !excludes.iter().any(|exclude| *exclude == prop.identifier()))
.for_each(|prop| {
.map(|prop| {
if let Some(table) = prop.get_data_table(tables) {
if prop.flags.contains(SendPropFlag::Collapsible) {
table.get_all_props_iterator_props(tables, excludes, local_props, props);
table.get_all_props_iterator_props(tables, excludes, local_props, props)?;
} else {
table.get_all_props(tables, excludes, props);
table.get_all_props(tables, excludes, props)?;
}
} else {
local_props.push(prop.clone());
local_props.push(SendPropDefinition::try_from(prop)?);
}
Ok(())
})
.collect::<Result<()>>()?;
Ok(())
}
}
@ -198,6 +203,7 @@ impl ParseSendTable {
pub struct SendTable {
pub name: SendTableName,
pub needs_decoder: bool,
pub raw_props: Vec<RawSendPropDefinition>,
pub flattened_props: Vec<SendPropDefinition>,
}

View file

@ -11,11 +11,10 @@ use crate::demo::packet::datatable::{
};
use crate::demo::packet::stringtable::StringTableEntry;
use crate::demo::sendprop::{SendProp, SendPropDefinition};
use crate::demo::sendprop::SendProp;
use crate::nullhasher::NullHasherBuilder;
use crate::{Result, Stream};
use std::cell::RefCell;
use std::convert::TryFrom;
#[derive(Default, Clone)]
pub struct DemoMeta {
@ -106,25 +105,23 @@ impl<'a> ParserState {
let flat_props: Vec<_> = parse_tables
.iter()
.map(|table| table.flatten_props(&parse_tables))
.collect();
.collect::<Result<Vec<_>>>()?;
let mut send_tables: FnvHashMap<SendTableName, SendTable> = parse_tables
.into_iter()
.zip(flat_props.into_iter())
.map(|(parse_table, flat)| {
Ok((
(
parse_table.name.clone(),
SendTable {
name: parse_table.name,
needs_decoder: parse_table.needs_decoder,
flattened_props: flat
.into_iter()
.map(|raw| SendPropDefinition::try_from(raw))
.collect::<std::result::Result<Vec<_>, _>>()?,
raw_props: parse_table.props,
flattened_props: flat,
},
))
)
})
.collect::<Result<_>>()?;
.collect();
self.server_classes = server_classes;

View file

@ -16,6 +16,7 @@ use std::convert::{TryFrom, TryInto};
use fnv::FnvHasher;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::num::NonZeroU64;
use std::rc::Rc;
#[derive(
@ -347,16 +348,18 @@ impl FloatDefinition {
#[derive(Debug, Clone)]
pub struct SendPropDefinition {
pub changes_often: bool,
pub identifier: SendPropIdentifier,
pub parse_definition: SendPropParseDefinition,
}
impl TryFrom<RawSendPropDefinition> for SendPropDefinition {
impl TryFrom<&RawSendPropDefinition> for SendPropDefinition {
type Error = MalformedSendPropDefinitionError;
fn try_from(definition: RawSendPropDefinition) -> std::result::Result<Self, Self::Error> {
let parse_definition = (&definition).try_into()?;
fn try_from(definition: &RawSendPropDefinition) -> std::result::Result<Self, Self::Error> {
let parse_definition = definition.try_into()?;
Ok(SendPropDefinition {
changes_often: definition.flags.contains(SendPropFlag::ChangesOften),
parse_definition,
identifier: definition.identifier(),
})

View file

@ -1,34 +1,50 @@
use std::fs;
use test_case::test_case;
use fnv::FnvHashMap;
use std::collections::{HashMap, HashSet};
use tf_demo_parser::demo::packet::datatable::{ParseSendTable, SendTableName, ServerClass};
use tf_demo_parser::demo::parser::MessageHandler;
use tf_demo_parser::demo::sendprop::{SendPropIdentifier, SendPropName};
use tf_demo_parser::{Demo, DemoParser, MessageType, ParserState};
#[derive(Default)]
pub struct SendPropAnalyser {
tables: Vec<ParseSendTable>,
prop_names: FnvHashMap<SendPropIdentifier, (SendTableName, SendPropName)>,
}
impl SendPropAnalyser {
pub fn new() -> Self {
SendPropAnalyser { tables: Vec::new() }
SendPropAnalyser::default()
}
}
impl MessageHandler for SendPropAnalyser {
type Output = Vec<ParseSendTable>;
type Output = (
Vec<ParseSendTable>,
FnvHashMap<SendPropIdentifier, (SendTableName, SendPropName)>,
);
fn does_handle(_message_type: MessageType) -> bool {
false
}
fn handle_data_tables(&mut self, tables: &[ParseSendTable], _server_classes: &[ServerClass]) {
for table in tables {
for prop_def in &table.props {
self.prop_names.insert(
prop_def.identifier(),
(prop_def.owner_table.clone(), prop_def.name.clone()),
);
}
}
self.tables = tables.to_vec()
}
fn into_output(self, _state: &ParserState) -> Self::Output {
self.tables
(self.tables, self.prop_names)
}
}
@ -36,7 +52,7 @@ impl MessageHandler for SendPropAnalyser {
fn flatten_test(input_file: &str, snapshot_file: &str) {
let file = fs::read(input_file).expect("Unable to read file");
let demo = Demo::new(&file);
let (_, send_tables) =
let (_, (send_tables, prop_names)) =
DemoParser::new_with_analyser(demo.get_stream(), SendPropAnalyser::new())
.parse()
.expect("Failed to parse");
@ -47,8 +63,12 @@ fn flatten_test(input_file: &str, snapshot_file: &str) {
table.name.clone(),
table
.flatten_props(&send_tables)
.unwrap()
.into_iter()
.map(|prop| format!("{}.{}", prop.owner_table, prop.name))
.map(|prop| {
let (table_name, prop_name) = &prop_names[&prop.identifier];
format!("{}.{}", table_name, prop_name)
})
.collect(),
)
})