mirror of
https://codeberg.org/demostf/parser.git
synced 2026-06-03 18:24:05 +02:00
sendprop decoding
This commit is contained in:
parent
164f88a32a
commit
ff18680a02
25 changed files with 389 additions and 135 deletions
|
|
@ -1,4 +1,4 @@
|
|||
use bitstream_reader::{BitRead, LittleEndian, BitSkip};
|
||||
use bitstream_reader::{BitRead, BitSkip, LittleEndian};
|
||||
|
||||
use crate::demo::sendprop::read_bit_coord;
|
||||
use crate::demo::vector::Vector;
|
||||
|
|
@ -45,4 +45,4 @@ impl BitRead<LittleEndian> for BSPDecalMessage {
|
|||
}
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for BSPDecalMessage{}
|
||||
impl BitSkip<LittleEndian> for BSPDecalMessage {}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use bitstream_reader::{BitRead, BitReadSized, LittleEndian, BitSkip};
|
||||
use bitstream_reader::{BitRead, BitReadSized, BitSkip, LittleEndian};
|
||||
|
||||
use crate::demo::message::stringtable::log_base2;
|
||||
use crate::{ReadResult, Stream};
|
||||
|
|
@ -41,4 +41,4 @@ impl BitRead<LittleEndian> for ClassInfoMessage {
|
|||
}
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for ClassInfoMessage{}
|
||||
impl BitSkip<LittleEndian> for ClassInfoMessage {}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
use std::collections::HashMap;
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use bitstream_reader::{BitRead, LittleEndian, BitSkip};
|
||||
use bitstream_reader::{BitRead, BitSkip, LittleEndian};
|
||||
|
||||
use crate::demo::gameevent_gen::GameEventType;
|
||||
use crate::demo::gamevent::{
|
||||
GameEvent, GameEventDefinition, GameEventEntry, GameEventValue, GameEventValueType,
|
||||
RawGameEvent,
|
||||
};
|
||||
use crate::{Parse, ParserState, ReadResult, Result, Stream, ParseError};
|
||||
use crate::demo::parser::ParseBitSkip;
|
||||
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
|
||||
|
||||
fn read_event_value(stream: &mut Stream, definition: &GameEventEntry) -> Result<GameEventValue> {
|
||||
Ok(match definition.kind {
|
||||
|
|
@ -111,4 +111,4 @@ impl BitRead<LittleEndian> for GameEventListMessage {
|
|||
}
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for GameEventListMessage{}
|
||||
impl BitSkip<LittleEndian> for GameEventListMessage {}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::Stream;
|
||||
/// Messages that consists only of primitives and string and can be derived
|
||||
use bitstream_reader::{BitRead, LittleEndian, BitSize, BitSkip};
|
||||
use bitstream_reader::{BitRead, BitSize, BitSkip, LittleEndian};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(BitRead, Debug)]
|
||||
|
|
@ -10,7 +10,7 @@ pub struct FileMessage {
|
|||
pub requested: bool,
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for FileMessage{}
|
||||
impl BitSkip<LittleEndian> for FileMessage {}
|
||||
|
||||
#[derive(BitRead, BitSize, Debug)]
|
||||
pub struct NetTickMessage {
|
||||
|
|
@ -24,7 +24,7 @@ pub struct StringCmdMessage {
|
|||
pub command: String,
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for StringCmdMessage{}
|
||||
impl BitSkip<LittleEndian> for StringCmdMessage {}
|
||||
|
||||
#[derive(BitRead, BitSize, Debug)]
|
||||
pub struct SigOnStateMessage {
|
||||
|
|
@ -37,7 +37,7 @@ pub struct PrintMessage {
|
|||
pub value: String,
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for PrintMessage{}
|
||||
impl BitSkip<LittleEndian> for PrintMessage {}
|
||||
|
||||
#[derive(BitRead, Debug)]
|
||||
pub struct ServerInfoMessage {
|
||||
|
|
@ -60,7 +60,7 @@ pub struct ServerInfoMessage {
|
|||
pub replay: bool,
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for ServerInfoMessage{}
|
||||
impl BitSkip<LittleEndian> for ServerInfoMessage {}
|
||||
|
||||
#[derive(BitRead, BitSize, Debug)]
|
||||
pub struct SetPauseMessage {
|
||||
|
|
@ -94,7 +94,7 @@ pub struct EntityMessage {
|
|||
pub data: Stream,
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for EntityMessage{}
|
||||
impl BitSkip<LittleEndian> for EntityMessage {}
|
||||
|
||||
#[derive(BitRead, BitSize, Debug)]
|
||||
pub struct PreFetchMessage {
|
||||
|
|
@ -111,7 +111,7 @@ pub struct MenuMessage {
|
|||
pub index: Stream,
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for MenuMessage{}
|
||||
impl BitSkip<LittleEndian> for MenuMessage {}
|
||||
|
||||
#[derive(BitRead, Debug)]
|
||||
pub struct GetCvarValueMessage {
|
||||
|
|
@ -119,7 +119,7 @@ pub struct GetCvarValueMessage {
|
|||
pub value: String,
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for GetCvarValueMessage{}
|
||||
impl BitSkip<LittleEndian> for GetCvarValueMessage {}
|
||||
|
||||
#[derive(BitRead, Debug)]
|
||||
#[endianness = "LittleEndian"]
|
||||
|
|
@ -129,4 +129,4 @@ pub struct CmdKeyValuesMessage {
|
|||
pub data: Stream,
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for CmdKeyValuesMessage{}
|
||||
impl BitSkip<LittleEndian> for CmdKeyValuesMessage {}
|
||||
|
|
|
|||
|
|
@ -5,28 +5,28 @@ pub use generated::*;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
|
||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||
use crate::demo::message::bspdecal::*;
|
||||
use crate::demo::message::classinfo::*;
|
||||
use crate::demo::message::gameevent::*;
|
||||
use crate::demo::message::packetentities::*;
|
||||
use crate::demo::message::setconvar::*;
|
||||
use crate::demo::message::stringtable::*;
|
||||
use crate::demo::message::tempentities::*;
|
||||
use crate::demo::message::usermessage::*;
|
||||
use crate::demo::message::voice::*;
|
||||
use crate::demo::message::setconvar::*;
|
||||
use crate::demo::parser::ParseBitSkip;
|
||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||
|
||||
pub mod bspdecal;
|
||||
pub mod classinfo;
|
||||
pub mod gameevent;
|
||||
pub mod generated;
|
||||
pub mod packetentities;
|
||||
pub mod setconvar;
|
||||
pub mod stringtable;
|
||||
pub mod tempentities;
|
||||
pub mod usermessage;
|
||||
pub mod voice;
|
||||
pub mod setconvar;
|
||||
|
||||
#[derive(Primitive, Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
|
||||
#[repr(u8)]
|
||||
|
|
@ -142,7 +142,11 @@ impl Message {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_type(message_type: MessageType, stream: &mut Stream, state: &ParserState) -> Result<Self> {
|
||||
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)?),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use bitstream_reader::BitRead;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Parse, ParserState, Result, Stream, ParseError};
|
||||
use crate::demo::packet::datatable::ServerClass;
|
||||
use crate::demo::sendprop::SendProp;
|
||||
use crate::demo::parser::ParseBitSkip;
|
||||
use crate::demo::sendprop::SendProp;
|
||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct EntityId(u32);
|
||||
|
|
@ -81,13 +81,11 @@ impl ParseBitSkip for PacketEntitiesMessage {
|
|||
}
|
||||
|
||||
pub struct EntityUpdate {
|
||||
props: Vec<SendProp>
|
||||
props: Vec<SendProp>,
|
||||
}
|
||||
|
||||
impl Parse for EntityUpdate {
|
||||
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||
Ok(EntityUpdate {
|
||||
props: Vec::new()
|
||||
})
|
||||
Ok(EntityUpdate { props: Vec::new() })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use bitstream_reader::{BitRead, BitReadSized, LittleEndian, BitSkip};
|
||||
use bitstream_reader::{BitRead, BitReadSized, BitSkip, LittleEndian};
|
||||
|
||||
use crate::demo::message::stringtable::log_base2;
|
||||
use crate::{ReadResult, Stream};
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SetConVarMessage {
|
||||
vars: Vec<(String, String)>,
|
||||
|
|
@ -14,14 +13,16 @@ impl BitRead<LittleEndian> for SetConVarMessage {
|
|||
let count: u8 = stream.read()?;
|
||||
let mut vars: Vec<(String, String)> = Vec::with_capacity(count as usize);
|
||||
for _ in 0..count {
|
||||
let key = stream.read().unwrap_or_else(|_| "Malformed cvar name".to_string());
|
||||
let value = stream.read().unwrap_or_else(|_| "Malformed cvar value".to_string());
|
||||
let key = stream
|
||||
.read()
|
||||
.unwrap_or_else(|_| "Malformed cvar name".to_string());
|
||||
let value = stream
|
||||
.read()
|
||||
.unwrap_or_else(|_| "Malformed cvar value".to_string());
|
||||
vars.push((key, value));
|
||||
}
|
||||
Ok(SetConVarMessage {
|
||||
vars
|
||||
})
|
||||
Ok(SetConVarMessage { vars })
|
||||
}
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for SetConVarMessage {}
|
||||
impl BitSkip<LittleEndian> for SetConVarMessage {}
|
||||
|
|
|
|||
|
|
@ -2,11 +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::demo::parser::ParseBitSkip;
|
||||
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CreateStringTableMessage {
|
||||
|
|
@ -105,7 +105,6 @@ impl ParseBitSkip for CreateStringTableMessage {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UpdateStringTableMessage {
|
||||
pub entries: Vec<(u16, StringTableEntry)>,
|
||||
|
|
@ -246,7 +245,7 @@ fn read_table_entry(
|
|||
} else {
|
||||
None
|
||||
}
|
||||
.map(ExtraData::new);
|
||||
.map(ExtraData::new);
|
||||
|
||||
Ok(StringTableEntry { text, extra_data })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{Parse, ParserState, Result, Stream, ParseError};
|
||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||
|
||||
use super::packetentities::PacketEntity;
|
||||
use super::stringtable::read_var_int;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use bitstream_reader::{BitRead, LittleEndian};
|
||||
use enum_primitive_derive::Primitive;
|
||||
use num_traits::FromPrimitive;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{ReadResult, Stream, Result, ParseError};
|
||||
use crate::demo::parser::ParseBitSkip;
|
||||
use crate::{ParseError, ReadResult, Result, Stream};
|
||||
|
||||
#[derive(Primitive, Clone, Copy, Debug)]
|
||||
pub enum UserMessageType {
|
||||
|
|
@ -102,12 +102,11 @@ 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)?;
|
||||
let length: u32 = stream.read_int(11)?;
|
||||
stream.skip_bits(length as usize).map_err(ParseError::from)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum ChatMessageKind {
|
||||
#[serde(rename = "TF_Chat_All")]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use bitstream_reader::{BitRead, LittleEndian, BitSkip};
|
||||
use bitstream_reader::{BitRead, BitSkip, LittleEndian};
|
||||
|
||||
use crate::{ReadResult, Stream};
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ impl BitRead<LittleEndian> for VoiceInitMessage {
|
|||
}
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for VoiceInitMessage{}
|
||||
impl BitSkip<LittleEndian> for VoiceInitMessage {}
|
||||
|
||||
#[derive(BitRead, Debug, Clone)]
|
||||
#[endianness = "LittleEndian"]
|
||||
|
|
@ -42,7 +42,7 @@ pub struct VoiceDataMessage {
|
|||
data: Stream,
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for VoiceDataMessage{}
|
||||
impl BitSkip<LittleEndian> for VoiceDataMessage {}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ParseSoundsMessage {
|
||||
|
|
@ -72,4 +72,4 @@ impl BitRead<LittleEndian> for ParseSoundsMessage {
|
|||
}
|
||||
}
|
||||
|
||||
impl BitSkip<LittleEndian> for ParseSoundsMessage{}
|
||||
impl BitSkip<LittleEndian> for ParseSoundsMessage {}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
use bitstream_reader::{BitRead, LittleEndian};
|
||||
|
||||
use crate::demo::sendprop::{SendPropDefinition, SendPropFlag, SendPropType};
|
||||
use crate::{Parse, ParseError, ParserState, Result, Stream, ReadResult};
|
||||
use std::fmt;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::rc::Rc;
|
||||
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(BitRead, Debug)]
|
||||
pub struct ServerClass {
|
||||
|
|
@ -60,20 +60,17 @@ impl Parse for ParseSendTable {
|
|||
let mut props = Vec::with_capacity(prop_count);
|
||||
|
||||
for _ in 0..prop_count {
|
||||
let prop: SendPropDefinition =
|
||||
SendPropDefinition::read(stream, name.clone())?;
|
||||
let prop: SendPropDefinition = SendPropDefinition::read(stream, name.clone())?;
|
||||
if prop.flags.contains(SendPropFlag::InsideArray) {
|
||||
if array_element_prop.is_some()
|
||||
|| prop.flags.contains(SendPropFlag::ChangesOften)
|
||||
{
|
||||
return Err(ParseError::InvalidSendPropArray(
|
||||
if array_element_prop.is_some() || prop.flags.contains(SendPropFlag::ChangesOften) {
|
||||
return Err(ParseError::InvalidSendProp(
|
||||
"Array contents can't have the 'ChangesOften' flag".to_owned(),
|
||||
));
|
||||
}
|
||||
array_element_prop = Some(prop);
|
||||
} else if let Some(array_element) = array_element_prop {
|
||||
if prop.prop_type != SendPropType::Array {
|
||||
return Err(ParseError::InvalidSendPropArray(
|
||||
return Err(ParseError::InvalidSendProp(
|
||||
"Array contents can without array".to_owned(),
|
||||
));
|
||||
}
|
||||
|
|
@ -131,14 +128,25 @@ impl ParseSendTable {
|
|||
}
|
||||
|
||||
// TODO: below is a direct port from the js which is a direct port from C++ and not very optimal
|
||||
fn get_all_props<'a>(&'a self, tables: &'a [ParseSendTable], excludes: &[Exclude], props: &mut Vec<&'a SendPropDefinition>) {
|
||||
fn get_all_props<'a>(
|
||||
&'a self,
|
||||
tables: &'a [ParseSendTable],
|
||||
excludes: &[Exclude],
|
||||
props: &mut Vec<&'a SendPropDefinition>,
|
||||
) {
|
||||
let mut local_props = Vec::new();
|
||||
|
||||
self.get_all_props_iterator_props(tables, excludes, &mut local_props, props);
|
||||
props.extend_from_slice(&local_props);
|
||||
}
|
||||
|
||||
fn get_all_props_iterator_props<'a>(&'a self, tables: &'a [ParseSendTable], excludes: &[Exclude], local_props: &mut Vec<&'a SendPropDefinition>, props: &mut Vec<&'a SendPropDefinition>) {
|
||||
fn get_all_props_iterator_props<'a>(
|
||||
&'a self,
|
||||
tables: &'a [ParseSendTable],
|
||||
excludes: &[Exclude],
|
||||
local_props: &mut Vec<&'a SendPropDefinition>,
|
||||
props: &mut Vec<&'a SendPropDefinition>,
|
||||
) {
|
||||
for prop in self.props.iter() {
|
||||
if prop.is_exclude() {
|
||||
continue;
|
||||
|
|
@ -202,24 +210,22 @@ impl Parse for DataTablePacket {
|
|||
parse_tables.push(table);
|
||||
}
|
||||
|
||||
let flat_props: Vec<_> = parse_tables.iter()
|
||||
let flat_props: Vec<_> = parse_tables
|
||||
.iter()
|
||||
.map(|table| table.flatten_props(&parse_tables))
|
||||
.collect();
|
||||
|
||||
let tables = parse_tables.into_iter()
|
||||
let tables = parse_tables
|
||||
.into_iter()
|
||||
.zip(flat_props.into_iter())
|
||||
.map(|(parse_table, flat)| {
|
||||
SendTable {
|
||||
name: parse_table.name,
|
||||
props: parse_table.props,
|
||||
needs_decoder: parse_table.needs_decoder,
|
||||
flattened_props: flat,
|
||||
}
|
||||
.map(|(parse_table, flat)| SendTable {
|
||||
name: parse_table.name,
|
||||
props: parse_table.props,
|
||||
needs_decoder: parse_table.needs_decoder,
|
||||
flattened_props: flat,
|
||||
})
|
||||
.collect();
|
||||
|
||||
// TODO linked tables?
|
||||
|
||||
let server_class_count = packet_data.read_int(16)?;
|
||||
let server_classes = packet_data.read_sized(server_class_count)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use bitstream_reader::{BitRead, BitSize, LazyBitRead, LittleEndian};
|
||||
|
||||
use crate::{Parse, ParserState, ReadResult, Result, Stream};
|
||||
use crate::demo::message::{Message, MessageType};
|
||||
use crate::demo::vector::Vector;
|
||||
use crate::{Parse, ParserState, ReadResult, Result, Stream};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MessagePacket {
|
||||
|
|
|
|||
|
|
@ -3,16 +3,16 @@ use std::collections::HashMap;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
|
||||
use crate::{ParserState, ReadResult, Stream};
|
||||
use crate::demo::gameevent_gen::{
|
||||
GameEvent, PlayerDeathEvent, PlayerSpawnEvent, TeamPlayRoundWinEvent,
|
||||
};
|
||||
use crate::demo::message::{Message, MessageType};
|
||||
use crate::demo::message::packetentities::EntityId;
|
||||
use crate::demo::message::usermessage::{ChatMessageKind, SayText2Message, UserMessage};
|
||||
use crate::demo::message::{Message, MessageType};
|
||||
use crate::demo::packet::stringtable::StringTableEntry;
|
||||
use crate::demo::parser::handler::MessageHandler;
|
||||
use crate::demo::vector::Vector;
|
||||
use crate::{ParserState, ReadResult, Stream};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct ChatMassage {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::demo::message::{Message, MessageType};
|
||||
use crate::demo::packet::datatable::{SendTable, ServerClass};
|
||||
use crate::demo::packet::Packet;
|
||||
use crate::demo::packet::stringtable::{StringTable, StringTableEntry};
|
||||
use crate::demo::packet::Packet;
|
||||
use crate::demo::parser::analyser::Analyser;
|
||||
use crate::ParserState;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,20 +3,20 @@ use std::collections::HashMap;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
|
||||
use crate::{ParserState, ReadResult, Stream};
|
||||
use crate::demo::gameevent_gen::{
|
||||
GameEvent, PlayerDeathEvent, PlayerSpawnEvent, TeamPlayRoundWinEvent,
|
||||
};
|
||||
use crate::demo::message::{Message, MessageType};
|
||||
use crate::demo::message::packetentities::EntityId;
|
||||
use crate::demo::message::usermessage::{ChatMessageKind, SayText2Message, UserMessage};
|
||||
use crate::demo::packet::PacketType;
|
||||
use crate::demo::message::{Message, MessageType};
|
||||
use crate::demo::packet::stringtable::StringTableEntry;
|
||||
use crate::demo::packet::PacketType;
|
||||
use crate::demo::parser::handler::MessageHandler;
|
||||
use crate::demo::vector::Vector;
|
||||
use crate::{ParserState, ReadResult, Stream};
|
||||
|
||||
pub struct MessageTypeAnalyser {
|
||||
packet_types: Vec<MessageType>
|
||||
packet_types: Vec<MessageType>,
|
||||
}
|
||||
|
||||
impl MessageHandler for MessageTypeAnalyser {
|
||||
|
|
@ -40,7 +40,7 @@ impl MessageHandler for MessageTypeAnalyser {
|
|||
impl MessageTypeAnalyser {
|
||||
pub fn new() -> Self {
|
||||
MessageTypeAnalyser {
|
||||
packet_types: Vec::with_capacity(1024)
|
||||
packet_types: Vec::with_capacity(1024),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use bitstream_reader::{BitRead, BitSkip, LittleEndian, ReadError};
|
||||
|
||||
pub use self::messagetypeanalyser::MessageTypeAnalyser;
|
||||
use crate::demo::gamevent::{GameEventValue, GameEventValueType};
|
||||
use crate::demo::header::Header;
|
||||
use crate::demo::packet::Packet;
|
||||
|
|
@ -8,12 +9,11 @@ pub use crate::demo::parser::analyser::MatchState;
|
|||
pub use crate::demo::parser::handler::{DemoHandler, MessageHandler};
|
||||
pub use crate::demo::parser::state::ParserState;
|
||||
use crate::Stream;
|
||||
pub use self::messagetypeanalyser::MessageTypeAnalyser;
|
||||
|
||||
mod analyser;
|
||||
mod handler;
|
||||
mod state;
|
||||
mod messagetypeanalyser;
|
||||
mod state;
|
||||
|
||||
/// Errors that can occur during parsing
|
||||
#[derive(Debug)]
|
||||
|
|
@ -26,8 +26,8 @@ pub enum ParseError {
|
|||
InvalidMessageType(u8),
|
||||
/// SendProp type is invalid
|
||||
InvalidSendPropType(u8),
|
||||
/// Invalid structure found while creating array SendProp
|
||||
InvalidSendPropArray(String),
|
||||
/// Invalid SendProp
|
||||
InvalidSendProp(String),
|
||||
/// Expected amount of data left after parsing an object
|
||||
DataRemaining(usize),
|
||||
/// String table that was send for update doesn't exist
|
||||
|
|
@ -95,7 +95,10 @@ impl DemoParser {
|
|||
Self::parse_with_analyser(stream, Analyser::new())
|
||||
}
|
||||
|
||||
pub fn parse_with_analyser<T: MessageHandler>(mut stream: Stream, analyser: T) -> Result<(Header, T::Output)> {
|
||||
pub fn parse_with_analyser<T: MessageHandler>(
|
||||
mut stream: Stream,
|
||||
analyser: T,
|
||||
) -> Result<(Header, T::Output)> {
|
||||
let mut handler = DemoHandler::with_analyser(analyser);
|
||||
let header = Header::read(&mut stream)?;
|
||||
loop {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
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::packet::datatable::{SendTable, ServerClass, SendTableName};
|
||||
use crate::demo::message::{Message, MessageType};
|
||||
use crate::demo::packet::datatable::{SendTable, SendTableName, ServerClass};
|
||||
use crate::demo::packet::stringtable::StringTableEntry;
|
||||
use crate::demo::parser::analyser::Analyser;
|
||||
use crate::demo::parser::handler::MessageHandler;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@ use bitstream_reader::{BitRead, LittleEndian};
|
|||
use enumflags2::BitFlags;
|
||||
use enumflags2_derive::EnumFlags;
|
||||
|
||||
use crate::{ReadResult, Result, Stream, Parse};
|
||||
use crate::{Parse, ParseError, ReadResult, Result, Stream};
|
||||
|
||||
use super::packet::datatable::ParseSendTable;
|
||||
use super::vector::{Vector, VectorXY};
|
||||
use crate::demo::message::stringtable::log_base2;
|
||||
use crate::demo::packet::datatable::SendTableName;
|
||||
use std::convert::TryInto;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct SendPropDefinition {
|
||||
|
|
@ -42,7 +44,8 @@ impl SendPropDefinition {
|
|||
///
|
||||
/// Note that this is not the owner table
|
||||
pub fn get_data_table<'a>(&self, tables: &'a [ParseSendTable]) -> Option<&'a ParseSendTable> {
|
||||
self.table_name.as_ref()
|
||||
self.table_name
|
||||
.as_ref()
|
||||
.and_then(|name| tables.iter().find(|table| table.name == *name))
|
||||
}
|
||||
|
||||
|
|
@ -200,12 +203,173 @@ pub enum SendPropValue {
|
|||
Array(Vec<SendPropValue>),
|
||||
}
|
||||
|
||||
impl SendPropValue {
|
||||
pub fn parse(stream: &mut Stream, definition: &SendPropDefinition) -> Result<Self> {
|
||||
match definition.prop_type {
|
||||
SendPropType::Int => Self::read_int(stream, definition).map(SendPropValue::from),
|
||||
SendPropType::Float => Self::read_float(stream, definition).map(SendPropValue::from),
|
||||
SendPropType::String => Self::read_string(stream, definition).map(SendPropValue::from),
|
||||
SendPropType::Vector => Self::read_vector(stream, definition).map(SendPropValue::from),
|
||||
SendPropType::VectorXY => {
|
||||
Self::read_vector_xy(stream, definition).map(SendPropValue::from)
|
||||
}
|
||||
SendPropType::Array => Self::read_array(stream, definition).map(SendPropValue::from),
|
||||
_ => Err(ParseError::InvalidSendProp(
|
||||
"Prop type not allowed in entity".to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_int(stream: &mut Stream, definition: &SendPropDefinition) -> Result<i32> {
|
||||
if definition.flags.contains(SendPropFlag::NormalVarInt) {
|
||||
read_var_int(stream, !definition.flags.contains(SendPropFlag::Unsigned))
|
||||
.map_err(ParseError::from)
|
||||
} else {
|
||||
if definition.flags.contains(SendPropFlag::Unsigned) {
|
||||
let unsigned: u32 = stream.read()?;
|
||||
unsigned.try_into().map_err(|_| {
|
||||
ParseError::InvalidSendProp("SendProp value out of range".to_string())
|
||||
})
|
||||
} else {
|
||||
stream.read().map_err(ParseError::from)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_array(
|
||||
stream: &mut Stream,
|
||||
definition: &SendPropDefinition,
|
||||
) -> Result<Vec<SendPropValue>> {
|
||||
let num_bits = log_base2(definition.element_count.unwrap_or_default());
|
||||
|
||||
let count = stream.read_int(num_bits as usize)?;
|
||||
let mut values = Vec::with_capacity(count);
|
||||
|
||||
for _ in 0..count {
|
||||
let value = Self::parse(
|
||||
stream,
|
||||
definition
|
||||
.array_property
|
||||
.as_ref()
|
||||
.ok_or_else(|| ParseError::InvalidSendProp("Untyped array".to_string()))?,
|
||||
)?;
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
|
||||
fn read_string(stream: &mut Stream, definition: &SendPropDefinition) -> Result<String> {
|
||||
let length = stream.read_int(9)?;
|
||||
stream.read_sized(length).map_err(ParseError::from)
|
||||
}
|
||||
|
||||
fn read_vector(stream: &mut Stream, definition: &SendPropDefinition) -> Result<Vector> {
|
||||
Ok(Vector {
|
||||
x: Self::read_float(stream, definition)?,
|
||||
y: Self::read_float(stream, definition)?,
|
||||
z: Self::read_float(stream, definition)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_vector_xy(stream: &mut Stream, definition: &SendPropDefinition) -> Result<VectorXY> {
|
||||
Ok(VectorXY {
|
||||
x: Self::read_float(stream, definition)?,
|
||||
y: Self::read_float(stream, definition)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_float(stream: &mut Stream, definition: &SendPropDefinition) -> Result<f32> {
|
||||
if definition.flags.contains(SendPropFlag::Coord) {
|
||||
read_bit_coord(stream).map_err(ParseError::from)
|
||||
} else if definition.flags.contains(SendPropFlag::CoordMP) {
|
||||
read_bit_coord_mp(stream, false, false).map_err(ParseError::from)
|
||||
} else if definition.flags.contains(SendPropFlag::CoordMPLowPercision) {
|
||||
read_bit_coord_mp(stream, false, true).map_err(ParseError::from)
|
||||
} else if definition.flags.contains(SendPropFlag::CoordMPIntegral) {
|
||||
read_bit_coord_mp(stream, true, false).map_err(ParseError::from)
|
||||
} else if definition.flags.contains(SendPropFlag::NoScale) {
|
||||
stream.read().map_err(ParseError::from)
|
||||
} else if definition.flags.contains(SendPropFlag::NormalVarInt) {
|
||||
read_bit_normal(stream).map_err(ParseError::from)
|
||||
} else {
|
||||
let bit_count = definition
|
||||
.bit_count
|
||||
.ok_or_else(|| ParseError::InvalidSendProp("Unsized float".to_string()))?;
|
||||
let high = definition
|
||||
.high_value
|
||||
.ok_or_else(|| ParseError::InvalidSendProp("Unsized float".to_string()))?;
|
||||
let low = definition
|
||||
.low_value
|
||||
.ok_or_else(|| ParseError::InvalidSendProp("Unsized float".to_string()))?;
|
||||
let raw: u32 = stream.read_int(bit_count as usize)?;
|
||||
let percentage = (raw as f32) * get_frac_factor(bit_count as usize);
|
||||
Ok(low + ((high - low) * percentage))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for SendPropValue {
|
||||
fn from(value: i32) -> Self {
|
||||
SendPropValue::Integer(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vector> for SendPropValue {
|
||||
fn from(value: Vector) -> Self {
|
||||
SendPropValue::Vector(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VectorXY> for SendPropValue {
|
||||
fn from(value: VectorXY) -> Self {
|
||||
SendPropValue::VectorXY(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for SendPropValue {
|
||||
fn from(value: f32) -> Self {
|
||||
SendPropValue::Float(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for SendPropValue {
|
||||
fn from(value: String) -> Self {
|
||||
SendPropValue::String(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<SendPropValue>> for SendPropValue {
|
||||
fn from(value: Vec<SendPropValue>) -> Self {
|
||||
SendPropValue::Array(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SendProp {
|
||||
definition: SendPropDefinition,
|
||||
value: SendPropValue,
|
||||
}
|
||||
|
||||
pub fn read_var_int(stream: &mut Stream, signed: bool) -> ReadResult<i32> {
|
||||
let mut result: i32 = 0;
|
||||
|
||||
for i in (0..35).step_by(7) {
|
||||
let byte: u8 = stream.read()?;
|
||||
result |= ((byte & 0x7F) << i) as i32;
|
||||
|
||||
if (byte >> 7) == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if signed {
|
||||
Ok((result >> 1) ^ -(result & 1))
|
||||
} else {
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_bit_coord(stream: &mut Stream) -> ReadResult<f32> {
|
||||
let has_int = stream.read()?;
|
||||
let has_frac = stream.read()?;
|
||||
|
|
@ -224,3 +388,54 @@ pub fn read_bit_coord(stream: &mut Stream) -> ReadResult<f32> {
|
|||
0f32
|
||||
})
|
||||
}
|
||||
|
||||
fn get_frac_factor(bits: usize) -> f32 {
|
||||
1.0 / ((1 << bits) as f32)
|
||||
}
|
||||
|
||||
pub fn read_bit_coord_mp(
|
||||
stream: &mut Stream,
|
||||
is_integral: bool,
|
||||
low_precision: bool,
|
||||
) -> ReadResult<f32> {
|
||||
let mut value = 0.0;
|
||||
let mut is_negative = false;
|
||||
|
||||
let in_bounds = stream.read()?;
|
||||
let has_int_val = stream.read()?;
|
||||
|
||||
if is_integral {
|
||||
if has_int_val {
|
||||
is_negative = stream.read()?;
|
||||
|
||||
let int_val = stream.read_sized::<u32>(if in_bounds { 11 } else { 14 })? + 1;
|
||||
value = int_val as f32;
|
||||
}
|
||||
} else {
|
||||
is_negative = stream.read()?;
|
||||
if has_int_val {
|
||||
let int_val = stream.read_sized::<u32>(if in_bounds { 11 } else { 14 })? + 1;
|
||||
value = int_val as f32;
|
||||
}
|
||||
let frac_bits = if low_precision { 3 } else { 5 };
|
||||
let frac_val: u32 = stream.read_sized(frac_bits)?;
|
||||
value += (frac_val as f32) * get_frac_factor(frac_bits);
|
||||
}
|
||||
|
||||
if is_negative {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
pub fn read_bit_normal(stream: &mut Stream) -> ReadResult<f32> {
|
||||
let is_negative = stream.read()?;
|
||||
let frac_val: u16 = stream.read_sized(11)?;
|
||||
let value = (frac_val as f32) * get_frac_factor(11);
|
||||
if is_negative {
|
||||
Ok(-value)
|
||||
} else {
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use bitstream_reader::{BitRead, BitSize};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(BitRead, BitSize, Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Vector {
|
||||
|
|
|
|||
|
|
@ -5,11 +5,9 @@
|
|||
pub use bitstream_reader::Result as ReadResult;
|
||||
|
||||
pub use crate::demo::{
|
||||
Demo,
|
||||
message::MessageType, parser::{
|
||||
DemoParser, MatchState, MessageTypeAnalyser, Parse, ParseError, ParserState, Result,
|
||||
},
|
||||
Stream,
|
||||
message::MessageType,
|
||||
parser::{DemoParser, MatchState, MessageTypeAnalyser, Parse, ParseError, ParserState, Result},
|
||||
Demo, Stream,
|
||||
};
|
||||
|
||||
pub mod demo;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue