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

more efficient message handling

This commit is contained in:
Robin Appelman 2019-03-03 15:07:59 +01:00
commit 3c6d814e9b
4 changed files with 114 additions and 40 deletions

View file

@ -1,8 +1,12 @@
use std::mem::discriminant;
use bitstream_reader::{BitRead, LittleEndian};
use enum_primitive_derive::Primitive; use enum_primitive_derive::Primitive;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
pub use generated::*; pub use generated::*;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::demo::message::bspdecal::*; use crate::demo::message::bspdecal::*;
use crate::demo::message::classinfo::*; use crate::demo::message::classinfo::*;
use crate::demo::message::gameevent::*; use crate::demo::message::gameevent::*;
@ -12,8 +16,6 @@ use crate::demo::message::stringtable::*;
use crate::demo::message::tempentities::*; use crate::demo::message::tempentities::*;
use crate::demo::message::usermessage::*; use crate::demo::message::usermessage::*;
use crate::demo::message::voice::*; use crate::demo::message::voice::*;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use bitstream_reader::{BitRead, LittleEndian};
pub mod bspdecal; pub mod bspdecal;
pub mod classinfo; pub mod classinfo;
@ -154,3 +156,38 @@ impl Parse for Message {
}) })
} }
} }
impl Message {
pub fn get_message_type(&self) -> MessageType {
match self {
Message::Empty => MessageType::Empty,
Message::File(_) => MessageType::File,
Message::NetTick(_) => MessageType::NetTick,
Message::StringCmd(_) => MessageType::StringCmd,
Message::SetConVar(_) => MessageType::SetConVar,
Message::SigOnState(_) => MessageType::SigOnState,
Message::Print(_) => MessageType::Print,
Message::ServerInfo(_) => MessageType::ServerInfo,
Message::ClassInfo(_) => MessageType::ClassInfo,
Message::SetPause(_) => MessageType::SetPause,
Message::CreateStringTable(_) => MessageType::CreateStringTable,
Message::UpdateStringTable(_) => MessageType::UpdateStringTable,
Message::VoiceInit(_) => MessageType::VoiceInit,
Message::VoiceData(_) => MessageType::VoiceData,
Message::ParseSounds(_) => MessageType::ParseSounds,
Message::SetView(_) => MessageType::SetView,
Message::FixAngle(_) => MessageType::FixAngle,
Message::BspDecal(_) => MessageType::BspDecal,
Message::UserMessage(_) => MessageType::UserMessage,
Message::EntityMessage(_) => MessageType::EntityMessage,
Message::GameEvent(_) => MessageType::GameEvent,
Message::PacketEntities(_) => MessageType::PacketEntities,
Message::TempEntities(_) => MessageType::TempEntities,
Message::PreFetch(_) => MessageType::PreFetch,
Message::Menu(_) => MessageType::Menu,
Message::GameEventList(_) => MessageType::GameEventList,
Message::GetCvarValue(_) => MessageType::GetCvarValue,
Message::CmdKeyValues(_) => MessageType::CmdKeyValues,
}
}
}

View file

@ -1,8 +1,9 @@
use serde::Serialize; use serde::Serialize;
use crate::demo::gameevent_gen::{GameEvent, PlayerDeathEvent}; use crate::demo::gameevent_gen::{GameEvent, PlayerDeathEvent};
use crate::demo::message::Message; use crate::demo::message::{Message, MessageType};
use crate::demo::message::usermessage::{SayText2Kind, UserMessage}; use crate::demo::message::usermessage::{SayText2Kind, UserMessage};
use crate::demo::parser::MessageHandler;
use crate::demo::vector::Vector; use crate::demo::vector::Vector;
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
@ -58,18 +59,28 @@ pub struct Analyser {
pub world: World, pub world: World,
} }
impl Analyser { impl MessageHandler for Analyser {
pub fn new() -> Self { fn does_handle(&self, message_type: MessageType) -> bool {
Self::default() match message_type {
MessageType::GameEvent |
MessageType::UserMessage => true,
_ => false
}
} }
pub fn handle_message(&mut self, message: Message, tick: u32) { fn handle_message(&mut self, message: Message, tick: u32) {
match message { match message {
Message::GameEvent(message) => self.handle_event(message.event, tick), Message::GameEvent(message) => self.handle_event(message.event, tick),
Message::UserMessage(message) => self.handle_user_message(message, tick), Message::UserMessage(message) => self.handle_user_message(message, tick),
_ => {} _ => {}
} }
} }
}
impl Analyser {
pub fn new() -> Self {
Self::default()
}
fn handle_user_message(&mut self, message: UserMessage, tick: u32) { fn handle_user_message(&mut self, message: UserMessage, tick: u32) {
match message { match message {

View file

@ -4,6 +4,7 @@ use bitstream_reader::{BitRead, LittleEndian, ReadError};
use crate::demo::gamevent::GameEventValue; use crate::demo::gamevent::GameEventValue;
use crate::demo::header::Header; use crate::demo::header::Header;
use crate::demo::message::{Message, MessageType};
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::state::ParserState; pub use crate::demo::parser::state::ParserState;
@ -70,6 +71,12 @@ impl<T: BitRead<LittleEndian>> Parse for T {
} }
} }
pub trait MessageHandler {
fn does_handle(&self, message_type: MessageType) -> bool;
fn handle_message(&mut self, message: Message, tick: u32);
}
pub struct DemoParser { pub struct DemoParser {
stream: Stream, stream: Stream,
state: ParserState, state: ParserState,
@ -99,17 +106,29 @@ impl DemoParser {
Ok(()) Ok(())
} }
fn dispatch_messages(&mut self, messages: Vec<Message>) {
let tick = self.state.tick;
for message in messages {
let message_type = message.get_message_type();
if self.state.does_handle(message_type) {
self.state.handle_message(message, tick);
} else if self.analyser.does_handle(message_type) {
self.analyser.handle_message(message, tick);
}
}
}
pub fn parse_demo(mut self) -> Result<(Header, Analyser)> { pub fn parse_demo(mut self) -> Result<(Header, Analyser)> {
let header = self.read::<Header>()?; let header = self.read::<Header>()?;
loop { loop {
let packet = self.read::<Packet>()?; let packet = self.read::<Packet>()?;
let messages = match packet { match packet {
Packet::Stop(_) => break, Packet::Stop(_) => break,
Packet::Message(packet) | Packet::Sigon(packet) => {
self.dispatch_messages(packet.messages);
}
packet => self.state.handle_packet(packet), packet => self.state.handle_packet(packet),
}; };
for message in messages {
self.analyser.handle_message(message, self.state.tick);
}
} }
Ok((header, self.analyser)) Ok((header, self.analyser))
} }

View file

@ -2,11 +2,12 @@ use std::collections::HashMap;
use crate::demo::gameevent_gen::GameEventType; use crate::demo::gameevent_gen::GameEventType;
use crate::demo::gamevent::GameEventDefinition; use crate::demo::gamevent::GameEventDefinition;
use crate::demo::message::Message; use crate::demo::message::{Message, MessageType};
use crate::demo::message::packetentities::EntityId; use crate::demo::message::packetentities::EntityId;
use crate::demo::packet::datatable::{SendTable, ServerClass}; use crate::demo::packet::datatable::{SendTable, ServerClass};
use crate::demo::packet::Packet; use crate::demo::packet::Packet;
use crate::demo::packet::stringtable::{StringTable, StringTableEntry}; use crate::demo::packet::stringtable::{StringTable, StringTableEntry};
use crate::demo::parser::MessageHandler;
use crate::demo::sendprop::SendProp; use crate::demo::sendprop::SendProp;
use crate::Stream; use crate::Stream;
@ -36,13 +37,8 @@ impl ParserState {
ParserState::default() ParserState::default()
} }
pub fn handle_packet(&mut self, packet: Packet) -> Vec<Message> { pub fn handle_packet(&mut self, packet: Packet) {
match packet { match packet {
Packet::Message(packet) | Packet::Sigon(packet) => {
return packet.messages.into_iter()
.filter_map(|message| self.handle_message(message))
.collect();
}
Packet::DataTables(packet) => { Packet::DataTables(packet) => {
if self.send_tables.len() > 0 { if self.send_tables.len() > 0 {
unreachable!("overwriting tables"); unreachable!("overwriting tables");
@ -59,28 +55,6 @@ impl ParserState {
} }
_ => {} _ => {}
} }
Vec::new()
}
fn handle_message(&mut self, message: Message) -> Option<Message> {
match message {
Message::NetTick(message) => self.tick = message.tick,
Message::ServerInfo(message) => {
self.version = message.version;
self.game = message.game;
}
Message::GameEventList(message) => {
self.event_definitions = message.event_list;
}
Message::CreateStringTable(message) => {
self.handle_table(message.table);
}
Message::UpdateStringTable(message) => {
self.handle_table_update(message.table_id, message.entries);
}
_ => return Some(message)
}
None
} }
fn handle_table(&mut self, table: StringTable) { fn handle_table(&mut self, table: StringTable) {
@ -102,3 +76,36 @@ impl ParserState {
} }
} }
} }
impl MessageHandler for ParserState {
fn does_handle(&self, message_type: MessageType) -> bool {
match message_type {
MessageType::NetTick |
MessageType::ServerInfo |
MessageType::GameEventList |
MessageType::CreateStringTable |
MessageType::UpdateStringTable => true,
_ => false
}
}
fn handle_message(&mut self, message: Message, _tick: u32) {
match message {
Message::NetTick(message) => self.tick = message.tick,
Message::ServerInfo(message) => {
self.version = message.version;
self.game = message.game;
}
Message::GameEventList(message) => {
self.event_definitions = message.event_list;
}
Message::CreateStringTable(message) => {
self.handle_table(message.table);
}
Message::UpdateStringTable(message) => {
self.handle_table_update(message.table_id, message.entries);
}
_ => {}
}
}
}