1
0
Fork 0
mirror of https://codeberg.org/demostf/parser.git synced 2026-06-03 10:14:06 +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
*.data*
*.iml
*.bench

View file

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

View file

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

View file

@ -11,9 +11,11 @@ pub trait MessageHandler {
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;
}
@ -98,6 +100,7 @@ impl<T: MessageHandler> DemoHandler<T> {
}
fn handle_data_table(&mut self, send_tables: Vec<SendTable>, server_classes: Vec<ServerClass>) {
self.analyser.handle_data_tables(&send_tables);
self.state_handler
.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::header::Header;
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::parser::analyser::Analyser;
pub use crate::demo::parser::analyser::MatchState;
@ -81,7 +81,7 @@ pub enum MalformedDemoError {
found_type: GameEventValueType,
},
#[error(display = "An entity with an unknown server class({}) was read", _0)]
UnknownServerClass(usize),
UnknownServerClass(ClassId),
#[error(display = "Unknown send table: {}", _0)]
UnknownSendTable(SendTableName),
#[error(

View file

@ -27,7 +27,7 @@ pub struct ParserState {
pub event_definitions: Vec<GameEventDefinition>,
pub string_tables: Vec<StringTableMeta>,
pub entity_classes: HashMap<EntityId, ClassId>,
pub send_tables: HashMap<SendTableName, SendTable>,
pub send_tables: HashMap<ClassId, SendTable>,
pub server_classes: Vec<ServerClass>,
pub instance_baselines: [HashMap<EntityId, Vec<SendProp>>; 2],
pub demo_meta: DemoMeta,
@ -90,10 +90,20 @@ impl ParserState {
send_tables: Vec<SendTable>,
server_classes: Vec<ServerClass>,
) {
for table in send_tables {
self.send_tables.insert(table.name.clone(), table);
let mut send_tables: HashMap<SendTableName, SendTable> = send_tables
.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) {

View file

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