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

skip messages we dont care about

This commit is contained in:
Robin Appelman 2019-03-17 18:44:33 +01:00
commit 128bf1ceb2
17 changed files with 237 additions and 71 deletions

View file

@ -1,4 +1,4 @@
use bitstream_reader::{BitRead, LittleEndian};
use bitstream_reader::{BitRead, LittleEndian, BitSkip};
use crate::demo::sendprop::read_bit_coord;
use crate::demo::vector::Vector;
@ -44,3 +44,5 @@ impl BitRead<LittleEndian> for BSPDecalMessage {
})
}
}
impl BitSkip<LittleEndian> for BSPDecalMessage{}

View file

@ -1,4 +1,4 @@
use bitstream_reader::{BitRead, BitReadSized, LittleEndian};
use bitstream_reader::{BitRead, BitReadSized, LittleEndian, BitSkip};
use crate::demo::message::stringtable::log_base2;
use crate::{ReadResult, Stream};
@ -40,3 +40,5 @@ impl BitRead<LittleEndian> for ClassInfoMessage {
})
}
}
impl BitSkip<LittleEndian> for ClassInfoMessage{}

View file

@ -1,14 +1,15 @@
use std::collections::HashMap;
use std::iter::FromIterator;
use bitstream_reader::{BitRead, LittleEndian};
use bitstream_reader::{BitRead, LittleEndian, BitSkip};
use crate::demo::gameevent_gen::GameEventType;
use crate::demo::gamevent::{
GameEvent, GameEventDefinition, GameEventEntry, GameEventValue, GameEventValueType,
RawGameEvent,
};
use crate::{Parse, ParserState, ReadResult, Result, Stream};
use crate::{Parse, ParserState, ReadResult, Result, Stream, ParseError};
use crate::demo::parser::ParseBitSkip;
fn read_event_value(stream: &mut Stream, definition: &GameEventEntry) -> Result<GameEventValue> {
Ok(match definition.kind {
@ -52,6 +53,13 @@ impl Parse for GameEventMessage {
}
}
impl ParseBitSkip for GameEventMessage {
fn parse_skip(stream: &mut Stream) -> Result<()> {
let length: u16 = stream.read_sized(11)?;
stream.skip_bits(length as usize).map_err(ParseError::from)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GameEventTypeId(u16);
@ -102,3 +110,5 @@ impl BitRead<LittleEndian> for GameEventListMessage {
Ok(GameEventListMessage { event_list })
}
}
impl BitSkip<LittleEndian> for GameEventListMessage{}

View file

@ -1,6 +1,6 @@
use crate::Stream;
/// Messages that consists only of primitives and string and can be derived
use bitstream_reader::{BitRead, LittleEndian};
use bitstream_reader::{BitRead, LittleEndian, BitSize, BitSkip};
use std::collections::HashMap;
#[derive(BitRead, Debug)]
@ -10,7 +10,9 @@ pub struct FileMessage {
pub requested: bool,
}
#[derive(BitRead, Debug)]
impl BitSkip<LittleEndian> for FileMessage{}
#[derive(BitRead, BitSize, Debug)]
pub struct NetTickMessage {
pub tick: u32,
pub frame_time: u16,
@ -22,7 +24,9 @@ pub struct StringCmdMessage {
pub command: String,
}
#[derive(BitRead, Debug)]
impl BitSkip<LittleEndian> for StringCmdMessage{}
#[derive(BitRead, BitSize, Debug)]
pub struct SigOnStateMessage {
pub state: u8,
pub count: u32,
@ -33,6 +37,8 @@ pub struct PrintMessage {
pub value: String,
}
impl BitSkip<LittleEndian> for PrintMessage{}
#[derive(BitRead, Debug)]
pub struct ServerInfoMessage {
pub version: u16,
@ -54,18 +60,20 @@ pub struct ServerInfoMessage {
pub replay: bool,
}
#[derive(BitRead, Debug)]
impl BitSkip<LittleEndian> for ServerInfoMessage{}
#[derive(BitRead, BitSize, Debug)]
pub struct SetPauseMessage {
pub pause: bool,
}
#[derive(BitRead, Debug)]
#[derive(BitRead, BitSize, Debug)]
pub struct SetViewMessage {
#[size = 11]
pub index: u16,
}
#[derive(BitRead, Debug)]
#[derive(BitRead, BitSize, Debug)]
pub struct FixAngleMessage {
pub relative: bool,
pub x: u16,
@ -86,7 +94,9 @@ pub struct EntityMessage {
pub data: Stream,
}
#[derive(BitRead, Debug)]
impl BitSkip<LittleEndian> for EntityMessage{}
#[derive(BitRead, BitSize, Debug)]
pub struct PreFetchMessage {
#[size = 14]
pub index: u16,
@ -101,12 +111,16 @@ pub struct MenuMessage {
pub index: Stream,
}
impl BitSkip<LittleEndian> for MenuMessage{}
#[derive(BitRead, Debug)]
pub struct GetCvarValueMessage {
pub cookie: u32,
pub value: String,
}
impl BitSkip<LittleEndian> for GetCvarValueMessage{}
#[derive(BitRead, Debug)]
#[endianness = "LittleEndian"]
pub struct CmdKeyValuesMessage {
@ -115,8 +129,12 @@ pub struct CmdKeyValuesMessage {
pub data: Stream,
}
impl BitSkip<LittleEndian> for CmdKeyValuesMessage{}
#[derive(BitRead, Debug)]
pub struct SetConVarMessage {
#[size_bits = 8]
vars: HashMap<String, String>,
}
impl BitSkip<LittleEndian> for SetConVarMessage{}

View file

@ -3,6 +3,7 @@ use num_traits::FromPrimitive;
pub use generated::*;
use crate::{Parse, ParseError, ParserState, Result, Stream};
use crate::demo::message::bspdecal::*;
use crate::demo::message::classinfo::*;
use crate::demo::message::gameevent::*;
@ -11,7 +12,7 @@ use crate::demo::message::stringtable::*;
use crate::demo::message::tempentities::*;
use crate::demo::message::usermessage::*;
use crate::demo::message::voice::*;
use crate::{Parse, ParseError, ParserState, Result, Stream};
use crate::demo::parser::ParseBitSkip;
pub mod bspdecal;
pub mod classinfo;
@ -23,7 +24,7 @@ pub mod tempentities;
pub mod usermessage;
pub mod voice;
#[derive(Primitive, Debug, Clone, Copy)]
#[derive(Primitive, Debug, Clone, Copy, PartialEq, Eq)]
pub enum MessageType {
Empty = 0,
File = 2,
@ -98,6 +99,45 @@ pub enum Message {
impl Parse for Message {
fn parse(stream: &mut Stream, state: &ParserState) -> Result<Self> {
let message_type = MessageType::parse(stream, state)?;
Self::from_type(message_type, stream, state)
}
}
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,
}
}
pub fn from_type(message_type: MessageType, stream: &mut Stream, state: &ParserState) -> Result<Self> {
Ok(match message_type {
MessageType::Empty => Message::Empty,
MessageType::File => Message::File(FileMessage::parse(stream, state)?),
@ -151,39 +191,37 @@ 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,
pub fn skip_type(message_type: MessageType, stream: &mut Stream) -> Result<()> {
match message_type {
MessageType::Empty => Ok(()),
MessageType::File => FileMessage::parse_skip(stream),
MessageType::NetTick => NetTickMessage::parse_skip(stream),
MessageType::StringCmd => StringCmdMessage::parse_skip(stream),
MessageType::SetConVar => SetConVarMessage::parse_skip(stream),
MessageType::SigOnState => SigOnStateMessage::parse_skip(stream),
MessageType::Print => PrintMessage::parse_skip(stream),
MessageType::ServerInfo => ServerInfoMessage::parse_skip(stream),
MessageType::ClassInfo => ClassInfoMessage::parse_skip(stream),
MessageType::SetPause => SetPauseMessage::parse_skip(stream),
MessageType::CreateStringTable => CreateStringTableMessage::parse_skip(stream),
MessageType::UpdateStringTable => UpdateStringTableMessage::parse_skip(stream),
MessageType::VoiceInit => VoiceInitMessage::parse_skip(stream),
MessageType::VoiceData => VoiceDataMessage::parse_skip(stream),
MessageType::ParseSounds => ParseSoundsMessage::parse_skip(stream),
MessageType::SetView => SetViewMessage::parse_skip(stream),
MessageType::FixAngle => FixAngleMessage::parse_skip(stream),
MessageType::BspDecal => BSPDecalMessage::parse_skip(stream),
MessageType::UserMessage => UserMessage::parse_skip(stream),
MessageType::EntityMessage => EntityMessage::parse_skip(stream),
MessageType::GameEvent => GameEventMessage::parse_skip(stream),
MessageType::PacketEntities => PacketEntitiesMessage::parse_skip(stream),
MessageType::TempEntities => TempEntitiesMessage::parse_skip(stream),
MessageType::PreFetch => PreFetchMessage::parse_skip(stream),
MessageType::Menu => MenuMessage::parse_skip(stream),
MessageType::GameEventList => GameEventListMessage::parse_skip(stream),
MessageType::GetCvarValue => GetCvarValueMessage::parse_skip(stream),
MessageType::CmdKeyValues => CmdKeyValuesMessage::parse_skip(stream),
}
}
}

View file

@ -1,9 +1,10 @@
use bitstream_reader::BitRead;
use serde::Serialize;
use crate::{Parse, ParserState, Result, Stream, ParseError};
use crate::demo::packet::datatable::ServerClass;
use crate::demo::sendprop::SendProp;
use crate::{Parse, ParserState, Result, Stream};
use crate::demo::parser::ParseBitSkip;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize)]
pub struct EntityId(u32);
@ -66,3 +67,15 @@ impl Parse for PacketEntitiesMessage {
})
}
}
impl ParseBitSkip for PacketEntitiesMessage {
fn parse_skip(stream: &mut Stream) -> Result<()> {
let _: u16 = stream.read_sized(11)?;
let _: Option<u32> = stream.read()?;
let _: u8 = stream.read_sized(1)?;
let _: u16 = stream.read_sized(11)?;
let length: u32 = stream.read_sized(20)?;
let _: bool = stream.read()?;
stream.skip_bits(length as usize).map_err(ParseError::from)
}
}

View file

@ -2,10 +2,11 @@ use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
use num_traits::{PrimInt, Unsigned};
use snap::Decoder;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::demo::packet::stringtable::{
ExtraData, FixedUserdataSize, StringTable, StringTableEntry,
};
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::demo::parser::ParseBitSkip;
#[derive(Debug)]
pub struct CreateStringTableMessage {
@ -33,13 +34,13 @@ impl Parse for CreateStringTableMessage {
let max_entries: u16 = stream.read()?;
let encode_bits = log_base2(max_entries);
let entity_count: u16 = stream.read_sized(encode_bits as usize + 1)?;
let bit_count = read_var_int(stream)?;
let length = read_var_int(stream)?;
let fixed_userdata_size = stream.read()?;
let compressed = stream.read()?;
let mut table_data = stream.read_bits(bit_count as usize)?;
let mut table_data = stream.read_bits(length as usize)?;
if compressed {
let decompressed_size: u32 = table_data.read()?;
@ -88,6 +89,23 @@ impl Parse for CreateStringTableMessage {
}
}
impl ParseBitSkip for CreateStringTableMessage {
fn parse_skip(stream: &mut Stream) -> Result<()> {
let _: String = stream.read()?;
let max_entries: u16 = stream.read()?;
let encode_bits = log_base2(max_entries);
let _: u16 = stream.read_sized(encode_bits as usize + 1)?;
let length = read_var_int(stream)?;
let _: Option<FixedUserdataSize> = stream.read()?;
let _: bool = stream.read()?;
stream.skip_bits(length as usize).map_err(ParseError::from)
}
}
#[derive(Debug)]
pub struct UpdateStringTableMessage {
pub entries: Vec<(u16, StringTableEntry)>,
@ -99,9 +117,9 @@ impl Parse for UpdateStringTableMessage {
let table_id = stream.read_sized(5)?;
let changed: u16 = if stream.read()? { stream.read()? } else { 1 };
let len = stream.read_int(20)?;
let length: u32 = stream.read_int(20)?;
let mut data = stream.read_bits(len)?;
let mut data = stream.read_bits(length as usize)?;
let entries = match state.string_tables.get(table_id as usize) {
Some(table) => parse_string_table_update(&mut data, table, changed),
@ -112,6 +130,16 @@ impl Parse for UpdateStringTableMessage {
}
}
impl ParseBitSkip for UpdateStringTableMessage {
fn parse_skip(stream: &mut Stream) -> Result<()> {
let _: u8 = stream.read_sized(5)?;
let _: u16 = if stream.read()? { stream.read()? } else { 1 };
let length: u32 = stream.read_int(20)?;
stream.skip_bits(length as usize).map_err(ParseError::from)
}
}
fn parse_string_table_update(
stream: &mut Stream,
table_meta: &StringTableMeta,
@ -218,7 +246,7 @@ fn read_table_entry(
} else {
None
}
.map(ExtraData::new);
.map(ExtraData::new);
Ok(StringTableEntry { text, extra_data })
}

View file

@ -1,7 +1,8 @@
use crate::{Parse, ParserState, Result, Stream};
use crate::{Parse, ParserState, Result, Stream, ParseError};
use super::packetentities::PacketEntity;
use super::stringtable::read_var_int;
use crate::demo::parser::ParseBitSkip;
#[derive(Debug)]
pub struct TempEntitiesMessage {
@ -19,3 +20,11 @@ impl Parse for TempEntitiesMessage {
})
}
}
impl ParseBitSkip for TempEntitiesMessage {
fn parse_skip(stream: &mut Stream) -> Result<()> {
let _: u8 = stream.read()?;
let length = read_var_int(stream)?;
stream.skip_bits(length as usize).map_err(ParseError::from)
}
}

View file

@ -1,9 +1,10 @@
use bitstream_reader::{BitRead, LittleEndian};
use bitstream_reader::{BitRead, BitSkip, LittleEndian};
use enum_primitive_derive::Primitive;
use num_traits::FromPrimitive;
use serde::Serialize;
use crate::{ReadResult, Stream};
use crate::{ReadResult, Stream, Result, ParseError};
use crate::demo::parser::ParseBitSkip;
#[derive(Primitive, Clone, Copy, Debug)]
pub enum UserMessageType {
@ -98,6 +99,15 @@ impl BitRead<LittleEndian> for UserMessage {
}
}
impl ParseBitSkip for UserMessage {
fn parse_skip(stream: &mut Stream) -> Result<()> {
let _ = stream.skip_bits(8)?;
let length:u32 = stream.read_int(11)?;
stream.skip_bits(length as usize).map_err(ParseError::from)
}
}
#[derive(Debug, Clone, Serialize)]
pub enum ChatMessageKind {
#[serde(rename = "TF_Chat_All")]
@ -146,7 +156,7 @@ impl BitRead<LittleEndian> for SayText2Message {
if first == 7 {
let _color = stream.read_string(Some(6))?;
} else {
let _ = stream.skip(8)?;
let _ = stream.skip_bits(8)?;
}
let text: String = stream.read()?;
@ -169,7 +179,7 @@ impl BitRead<LittleEndian> for SayText2Message {
let kind = stream.read()?;
let from = stream.read()?;
let text = stream.read()?;
let _ = stream.skip(16)?;
let _ = stream.skip_bits(16)?;
(kind, from, text)
};

View file

@ -1,4 +1,4 @@
use bitstream_reader::{BitRead, LittleEndian};
use bitstream_reader::{BitRead, LittleEndian, BitSkip};
use crate::{ReadResult, Stream};
@ -30,6 +30,8 @@ impl BitRead<LittleEndian> for VoiceInitMessage {
}
}
impl BitSkip<LittleEndian> for VoiceInitMessage{}
#[derive(BitRead, Debug, Clone)]
#[endianness = "LittleEndian"]
pub struct VoiceDataMessage {
@ -40,6 +42,8 @@ pub struct VoiceDataMessage {
data: Stream,
}
impl BitSkip<LittleEndian> for VoiceDataMessage{}
#[derive(Debug, Clone)]
pub struct ParseSoundsMessage {
pub reliable: bool,
@ -67,3 +71,5 @@ impl BitRead<LittleEndian> for ParseSoundsMessage {
})
}
}
impl BitSkip<LittleEndian> for ParseSoundsMessage{}

View file

@ -1,4 +1,4 @@
use bitstream_reader::{BitRead, LazyBitReadSized, LittleEndian};
use bitstream_reader::{BitRead, LittleEndian};
use crate::{ReadResult, Stream};

View file

@ -1,8 +1,8 @@
use bitstream_reader::{BitRead, BitSize, LazyBitRead, LittleEndian};
use crate::demo::message::Message;
use crate::demo::vector::Vector;
use crate::{Parse, ParserState, ReadResult, Result, Stream};
use crate::demo::message::{Message, MessageType};
use crate::demo::vector::Vector;
#[derive(Debug)]
pub struct MessagePacket {
@ -57,10 +57,13 @@ impl Parse for MessagePacket {
let mut messages: Vec<Message> = Vec::with_capacity(25);
while packet_data.bits_left() > 6 {
let message = Message::parse(&mut packet_data, state)?;
match message {
Message::Empty => {}
_ => messages.push(message),
let message_type = MessageType::parse(&mut packet_data, state)?;
if state.parse_message_types.contains(&message_type) {
let message = Message::from_type(message_type, &mut packet_data, state)?;
messages.push(message);
} else {
let _ = Message::skip_type(message_type, &mut packet_data)?;
}
}

View file

@ -13,7 +13,7 @@ impl BitRead<LittleEndian> for UserCmdPacket {
let tick = stream.read()?;
let sequence_out = stream.read()?;
let len: u32 = stream.read()?;
let _ = stream.skip(len as usize * 8)?;
let _ = stream.skip_bits(len as usize * 8)?;
// TODO parse the packet data
Ok(UserCmdPacket { tick, sequence_out })
}

View file

@ -218,6 +218,10 @@ impl Analyser {
Self::default()
}
pub fn get_message_types(&self) -> Vec<MessageType> {
vec![MessageType::GameEvent, MessageType::UserMessage]
}
fn handle_user_message(&mut self, message: UserMessage, tick: u32) {
match message {
UserMessage::SayText2(message) => match message.kind {

View file

@ -25,11 +25,15 @@ pub struct DemoHandler {
impl DemoHandler {
pub fn new() -> Self {
let mut state = ParserState::new();
let analyser = Analyser::new();
state.parse_message_types.extend(analyser.get_message_types());
DemoHandler {
tick: 0,
string_table_names: Vec::new(),
analyser: Analyser::new(),
state_handler: ParserState::new(),
analyser,
state_handler: state,
}
}

View file

@ -1,4 +1,4 @@
use bitstream_reader::{BitRead, LittleEndian, ReadError};
use bitstream_reader::{BitRead, BitSkip, LittleEndian, ReadError};
use crate::demo::gamevent::{GameEventValue, GameEventValueType};
use crate::demo::header::Header;
@ -74,6 +74,17 @@ impl<T: BitRead<LittleEndian>> Parse for T {
}
}
pub trait ParseBitSkip {
fn parse_skip(stream: &mut Stream) -> Result<()>;
}
impl<T: BitSkip<LittleEndian>> ParseBitSkip for T {
#[inline(always)]
fn parse_skip(stream: &mut Stream) -> Result<()> {
Self::skip(stream).map_err(ParseError::from)
}
}
pub struct DemoParser {
stream: Stream,
handler: DemoHandler,

View file

@ -1,10 +1,10 @@
use std::collections::HashMap;
use crate::demo::gamevent::GameEventDefinition;
use crate::demo::message::{Message, MessageType};
use crate::demo::message::gameevent::GameEventTypeId;
use crate::demo::message::packetentities::EntityId;
use crate::demo::message::stringtable::StringTableMeta;
use crate::demo::message::{Message, MessageType};
use crate::demo::packet::datatable::{SendTable, ServerClass};
use crate::demo::packet::stringtable::StringTableEntry;
use crate::demo::parser::handler::{MessageHandler, StringTableEntryHandler};
@ -28,6 +28,7 @@ pub struct ParserState {
pub server_classes: Vec<ServerClass>,
pub instance_baselines: [HashMap<EntityId, Vec<SendProp>>; 2],
pub demo_meta: DemoMeta,
pub parse_message_types: Vec<MessageType>,
}
pub struct StaticBaseline {
@ -48,7 +49,14 @@ impl StaticBaseline {
impl ParserState {
pub fn new() -> Self {
ParserState::default()
let mut state = ParserState::default();
state.parse_message_types.extend_from_slice(&[
MessageType::ServerInfo,
MessageType::GameEventList,
MessageType::CreateStringTable,
MessageType::UpdateStringTable
]);
state
}
pub fn handle_data_table(