Skip to content

Commit

Permalink
normalize prop definitions during flatening
Browse files Browse the repository at this point in the history
  • Loading branch information
icewind1991 committed Feb 13, 2021
1 parent 35519d5 commit 0a34318
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 72 deletions.
80 changes: 40 additions & 40 deletions benches/sendprop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
34 changes: 20 additions & 14 deletions src/demo/packet/datatable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -121,22 +122,22 @@ 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);
}
start += 1;
}
}

flat
Ok(flat)
}

fn get_excludes<'a>(&'a self, tables: &'a [ParseSendTable]) -> Vec<SendPropIdentifier> {
Expand All @@ -161,43 +162,48 @@ 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(())
}
}

#[derive(Debug, Clone)]
pub struct SendTable {
pub name: SendTableName,
pub needs_decoder: bool,
pub raw_props: Vec<RawSendPropDefinition>,
pub flattened_props: Vec<SendPropDefinition>,
}

Expand Down
17 changes: 7 additions & 10 deletions src/demo/parser/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;

Expand Down
9 changes: 6 additions & 3 deletions src/demo/sendprop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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(),
})
Expand Down
30 changes: 25 additions & 5 deletions tests/sendprops.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,58 @@
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)
}
}

#[test_case("data/gully.dem", "data/gully_props.json"; "gully.dem")]
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");
Expand All @@ -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(),
)
})
Expand Down

0 comments on commit 0a34318

Please sign in to comment.