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

save sendtables by classid

since we only really need to get them by classid
This commit is contained in:
Robin Appelman 2019-08-29 02:39:21 +02:00
commit bf65dffb13
8 changed files with 83 additions and 78 deletions

1
.gitignore vendored
View file

@ -4,3 +4,4 @@
*.svg *.svg
*.data* *.data*
*.iml *.iml
*.bench

View file

@ -34,7 +34,7 @@ impl MessageHandler for SendPropAnalyser {
state state
.send_tables .send_tables
.into_iter() .into_iter()
.map(|(_k, v)| ParseSendTable { .map(|(_, v)| ParseSendTable {
name: v.name, name: v.name,
props: v.props, props: v.props,
needs_decoder: v.needs_decoder, needs_decoder: v.needs_decoder,

View file

@ -105,40 +105,32 @@ pub struct PacketEntitiesMessage {
pub updated_base_line: bool, pub updated_base_line: bool,
} }
fn get_send_table<'a>(state: &'a ParserState, table: &SendTableName) -> Result<&'a SendTable> { fn get_send_table(state: &ParserState, class: ClassId) -> Result<&SendTable> {
state state
.send_tables .send_tables
.get(table) .get(&class)
.ok_or_else(|| MalformedDemoError::UnknownSendTable(table.clone()).into()) .ok_or_else(|| MalformedDemoError::UnknownServerClass(class).into())
} }
fn get_entity_for_update( fn get_entity_for_update(
state: &ParserState, state: &ParserState,
entity_index: EntityId, entity_index: EntityId,
pvs: PVS, pvs: PVS,
) -> Result<(PacketEntity, &ServerClass)> { ) -> Result<PacketEntity> {
let class_id = *state let class_id = *state
.entity_classes .entity_classes
.get(&entity_index) .get(&entity_index)
.ok_or_else(|| MalformedDemoError::UnknownEntity(entity_index))?; .ok_or_else(|| MalformedDemoError::UnknownEntity(entity_index))?;
let server_class = state Ok(PacketEntity {
.server_classes server_class: class_id,
.get(usize::from(class_id)) entity_index,
.ok_or_else(|| MalformedDemoError::UnknownServerClass(class_id.into()))?; props: Vec::new(),
in_pvs: false,
Ok(( pvs,
PacketEntity { serial_number: 0,
server_class: class_id, delay: None,
entity_index, })
props: Vec::new(),
in_pvs: false,
pvs,
serial_number: 0,
delay: None,
},
server_class,
))
} }
impl Parse for PacketEntitiesMessage { impl Parse for PacketEntitiesMessage {
@ -163,23 +155,23 @@ impl Parse for PacketEntitiesMessage {
let pvs = data.read()?; let pvs = data.read()?;
if pvs == PVS::Enter { if pvs == PVS::Enter {
let (mut entity, server_class) = let mut entity =
Self::read_enter(&mut data, entity_index, state, base_line as usize)?; Self::read_enter(&mut data, entity_index, state, base_line as usize)?;
let send_table = get_send_table(state, &server_class.data_table)?; let send_table = get_send_table(state, entity.server_class)?;
let updated_props = Self::read_update(&mut data, send_table)?; let updated_props = Self::read_update(&mut data, send_table)?;
entity.apply_update(updated_props); entity.apply_update(updated_props);
entities.push(entity); entities.push(entity);
} else if pvs == PVS::Preserve { } else if pvs == PVS::Preserve {
let (mut entity, server_class) = get_entity_for_update(state, entity_index, pvs)?; let mut entity = get_entity_for_update(state, entity_index, pvs)?;
let send_table = get_send_table(state, &server_class.data_table)?; let send_table = get_send_table(state, entity.server_class)?;
let updated_props = Self::read_update(&mut data, send_table)?; let updated_props = Self::read_update(&mut data, send_table)?;
entity.props = updated_props; entity.props = updated_props;
entities.push(entity); entities.push(entity);
} else if state.entity_classes.contains_key(&entity_index) { } else if state.entity_classes.contains_key(&entity_index) {
let (entity, server_class) = get_entity_for_update(state, entity_index, pvs)?; let entity = get_entity_for_update(state, entity_index, pvs)?;
entities.push(entity); entities.push(entity);
} }
} }
@ -202,47 +194,38 @@ impl Parse for PacketEntitiesMessage {
} }
impl PacketEntitiesMessage { impl PacketEntitiesMessage {
fn read_enter<'a>( fn read_enter(
stream: &mut Stream, stream: &mut Stream,
entity_index: EntityId, entity_index: EntityId,
state: &'a ParserState, state: &ParserState,
baseline_index: usize, baseline_index: usize,
) -> Result<(PacketEntity, &'a ServerClass)> { ) -> Result<PacketEntity> {
let bits = log_base2(state.server_classes.len()) + 1; let bits = log_base2(state.server_classes.len()) + 1;
let class_index = stream.read_sized::<u16>(bits as usize)? as usize; let class_index: ClassId = stream.read_sized::<u16>(bits as usize)?.into();
let server_class = state
.server_classes
.get(class_index)
.ok_or_else(|| ParseError::from(MalformedDemoError::UnknownServerClass(class_index)))?;
let serial = stream.read_sized(10)?; let serial = stream.read_sized(10)?;
let send_table = state let send_table = state
.send_tables .send_tables
.get(&server_class.data_table) .get(&class_index)
.ok_or_else(|| MalformedDemoError::UnknownSendTable(server_class.data_table.clone()))?; .ok_or_else(|| MalformedDemoError::UnknownServerClass(class_index))?;
let props = match state.instance_baselines[baseline_index].get(&entity_index) { let props = match state.instance_baselines[baseline_index].get(&entity_index) {
Some(baseline) => baseline.clone(), Some(baseline) => baseline.clone(),
None => match state.static_baselines.get(&server_class.id) { None => match state.static_baselines.get(&class_index) {
Some(static_baseline) => { Some(static_baseline) => state.get_static_baseline(class_index, send_table)?,
state.get_static_baseline((class_index as u16).into(), send_table)?
}
None => Vec::new(), None => Vec::new(),
}, },
}; };
Ok(( Ok(PacketEntity {
PacketEntity { server_class: class_index,
server_class: server_class.id, entity_index,
entity_index, props,
props, in_pvs: true,
in_pvs: true, pvs: PVS::Enter,
pvs: PVS::Enter, serial_number: serial,
serial_number: serial, delay: None,
delay: None, })
},
server_class,
))
} }
pub fn read_update(stream: &mut Stream, send_table: &SendTable) -> Result<Vec<SendProp>> { pub fn read_update(stream: &mut Stream, send_table: &SendTable) -> Result<Vec<SendProp>> {

View file

@ -52,7 +52,9 @@ pub struct ServerClass {
pub data_table: SendTableName, pub data_table: SendTableName,
} }
#[derive(BitRead, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Clone, Display)] #[derive(
BitRead, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Clone, Display, PartialOrd, Ord,
)]
pub struct SendTableName(Rc<String>); pub struct SendTableName(Rc<String>);
impl From<String> for SendTableName { impl From<String> for SendTableName {
@ -190,7 +192,7 @@ impl<'a> Exclude<'a> {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct SendTable { pub struct SendTable {
pub name: SendTableName, pub name: SendTableName,
pub props: Vec<Rc<SendPropDefinition>>, pub props: Vec<Rc<SendPropDefinition>>,

View file

@ -11,9 +11,11 @@ pub trait MessageHandler {
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) {}
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 handle_data_tables(&mut self, tables: &[SendTable]) {}
fn get_output(self, state: ParserState) -> Self::Output; fn get_output(self, state: ParserState) -> Self::Output;
} }
@ -98,6 +100,7 @@ impl<T: MessageHandler> DemoHandler<T> {
} }
fn handle_data_table(&mut self, send_tables: Vec<SendTable>, server_classes: Vec<ServerClass>) { fn handle_data_table(&mut self, send_tables: Vec<SendTable>, server_classes: Vec<ServerClass>) {
self.analyser.handle_data_tables(&send_tables);
self.state_handler self.state_handler
.handle_data_table(send_tables, server_classes); .handle_data_table(send_tables, server_classes);
} }

View file

@ -4,7 +4,7 @@ pub use self::messagetypeanalyser::MessageTypeAnalyser;
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::message::packetentities::EntityId; use crate::demo::message::packetentities::EntityId;
use crate::demo::packet::datatable::SendTableName; use crate::demo::packet::datatable::{ClassId, SendTableName};
use crate::demo::packet::Packet; use crate::demo::packet::Packet;
use crate::demo::parser::analyser::Analyser; use crate::demo::parser::analyser::Analyser;
pub use crate::demo::parser::analyser::MatchState; pub use crate::demo::parser::analyser::MatchState;
@ -81,7 +81,7 @@ pub enum MalformedDemoError {
found_type: GameEventValueType, found_type: GameEventValueType,
}, },
#[error(display = "An entity with an unknown server class({}) was read", _0)] #[error(display = "An entity with an unknown server class({}) was read", _0)]
UnknownServerClass(usize), UnknownServerClass(ClassId),
#[error(display = "Unknown send table: {}", _0)] #[error(display = "Unknown send table: {}", _0)]
UnknownSendTable(SendTableName), UnknownSendTable(SendTableName),
#[error( #[error(

View file

@ -27,7 +27,7 @@ pub struct ParserState {
pub event_definitions: Vec<GameEventDefinition>, pub event_definitions: Vec<GameEventDefinition>,
pub string_tables: Vec<StringTableMeta>, pub string_tables: Vec<StringTableMeta>,
pub entity_classes: HashMap<EntityId, ClassId>, pub entity_classes: HashMap<EntityId, ClassId>,
pub send_tables: HashMap<SendTableName, SendTable>, pub send_tables: HashMap<ClassId, SendTable>,
pub server_classes: Vec<ServerClass>, pub server_classes: Vec<ServerClass>,
pub instance_baselines: [HashMap<EntityId, Vec<SendProp>>; 2], pub instance_baselines: [HashMap<EntityId, Vec<SendProp>>; 2],
pub demo_meta: DemoMeta, pub demo_meta: DemoMeta,
@ -90,10 +90,20 @@ impl ParserState {
send_tables: Vec<SendTable>, send_tables: Vec<SendTable>,
server_classes: Vec<ServerClass>, server_classes: Vec<ServerClass>,
) { ) {
for table in send_tables { let mut send_tables: HashMap<SendTableName, SendTable> = send_tables
self.send_tables.insert(table.name.clone(), table); .into_iter()
.map(|table| (table.name.clone(), table))
.collect();
self.server_classes = server_classes;
self.send_tables.reserve(self.server_classes.len());
for class in self.server_classes.iter() {
if let Some(table) = send_tables.remove(&class.data_table) {
self.send_tables.insert(class.id, table);
}
} }
self.server_classes = server_classes
} }
pub fn handle_string_table_meta(&mut self, table: StringTableMeta) { pub fn handle_string_table_meta(&mut self, table: StringTableMeta) {

View file

@ -7,13 +7,21 @@ use std::fs;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use tf_demo_parser::demo::message::Message; use tf_demo_parser::demo::message::Message;
use tf_demo_parser::demo::packet::datatable::{ParseSendTable, SendTableName}; use tf_demo_parser::demo::packet::datatable::{ParseSendTable, SendTable, SendTableName};
use tf_demo_parser::demo::packet::stringtable::StringTableEntry; use tf_demo_parser::demo::packet::stringtable::StringTableEntry;
use tf_demo_parser::demo::parser::MessageHandler; use tf_demo_parser::demo::parser::MessageHandler;
use tf_demo_parser::demo::sendprop::SendPropDefinition; use tf_demo_parser::demo::sendprop::SendPropDefinition;
use tf_demo_parser::{Demo, DemoParser, MatchState, MessageType, MessageTypeAnalyser, ParserState}; use tf_demo_parser::{Demo, DemoParser, MatchState, MessageType, MessageTypeAnalyser, ParserState};
pub struct SendPropAnalyser; pub struct SendPropAnalyser {
tables: Vec<ParseSendTable>,
}
impl SendPropAnalyser {
pub fn new() -> Self {
SendPropAnalyser { tables: Vec::new() }
}
}
impl MessageHandler for SendPropAnalyser { impl MessageHandler for SendPropAnalyser {
type Output = Vec<ParseSendTable>; type Output = Vec<ParseSendTable>;
@ -22,28 +30,27 @@ impl MessageHandler for SendPropAnalyser {
false false
} }
fn handle_message(&mut self, message: Message, tick: u32) {} fn handle_data_tables(&mut self, tables: &[SendTable]) {
self.tables = tables
fn handle_string_entry(&mut self, table: &String, _index: usize, entry: &StringTableEntry) {} .iter()
.map(|v| ParseSendTable {
fn get_output(self, state: ParserState) -> Self::Output { name: v.name.clone(),
state props: v.props.clone(),
.send_tables
.into_iter()
.map(|(_k, v)| ParseSendTable {
name: v.name,
props: v.props,
needs_decoder: v.needs_decoder, needs_decoder: v.needs_decoder,
}) })
.collect() .collect()
} }
fn get_output(self, state: ParserState) -> Self::Output {
self.tables
}
} }
fn flatten_test(input_file: &str, snapshot_file: &str) { fn flatten_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 (_, send_tables) = let (_, send_tables) =
DemoParser::parse_with_analyser(demo.get_stream(), SendPropAnalyser).unwrap(); DemoParser::parse_with_analyser(demo.get_stream(), SendPropAnalyser::new()).unwrap();
let flat_props: HashMap<SendTableName, Vec<String>> = send_tables let flat_props: HashMap<SendTableName, Vec<String>> = send_tables
.iter() .iter()
.map(|table| { .map(|table| {
@ -70,7 +77,6 @@ fn flatten_test(input_file: &str, snapshot_file: &str) {
assert_eq!(expected_tables, actual_tables); assert_eq!(expected_tables, actual_tables);
for table in expected_tables { for table in expected_tables {
dbg!(table);
assert_eq!(expected[table], flat_props[table]); assert_eq!(expected[table], flat_props[table]);
} }
} }