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

packet parsers

This commit is contained in:
Robin Appelman 2019-02-25 23:20:51 +01:00
commit b41bb56822
19 changed files with 626 additions and 64 deletions

159
Cargo.lock generated Normal file
View file

@ -0,0 +1,159 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "bitstream_reader"
version = "0.2.0"
dependencies = [
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "enum-primitive-derive"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "enumflags2"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "enumflags2_derive"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rental"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rental-impl 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rental-impl"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "stable_deref_trait"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.11.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.15.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synom"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tf-demo-demo"
version = "0.1.0"
dependencies = [
"bitstream_reader 0.2.0",
"enum-primitive-derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"enumflags2 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"enumflags2_derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rental 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-xid"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum enum-primitive-derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b90e520ec62c1864c8c78d637acbfe8baf5f63240f2fb8165b8325c07812dd"
"checksum enumflags2 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "801303a673e02d2110a196d70e4a807f0ff0a68ce1060eebc1e6a0d598db65e8"
"checksum enumflags2_derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e015b3dfedc096cb55cdc5d022d6b4e6b94547212fb94ad2d9ece20bcd88fe3"
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
"checksum rental 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ca24bf9b98e3df0bb359f1bbb8ef993a0093d8432500c5eaf3ae724f30b5f754"
"checksum rental-impl 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a269533a9b93bbaa4848260e51b64564cc445d46185979f31974ec703374803a"
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"

View file

@ -9,3 +9,5 @@ bitstream_reader = { path = "../../bitbuffer" }
rental = "0.5"
enum-primitive-derive = "0.1.2"
num-traits = "0.2"
enumflags2 = "0.5"
enumflags2_derive = "0.5"

View file

@ -1,4 +1,4 @@
use crate::{ParseError, Parse, Result, Stream, ParserState};
use crate::{Parse, ParseError, ParserState, Result, Stream};
//use crate::test::test_parse;
#[derive(Debug, PartialEq)]

View file

@ -3,10 +3,10 @@ use rentals::OwnedBuffer;
pub mod gamevent;
pub mod header;
pub mod packet;
pub mod parser;
pub mod sendprop;
pub mod vector;
pub mod parser;
pub mod packet;
pub type Buffer<'a> = BitBuffer<'a, LittleEndian, NonPadded>;
pub type Stream<'a> = BitStream<'a, LittleEndian, NonPadded>;

View file

@ -0,0 +1,91 @@
use crate::{Parse, ParseError, ParserState, Result, Stream};
use crate::demo::sendprop::{SendPropDefinition, SendPropFlag, SendPropType};
pub struct ServerClass {
id: u32,
name: String,
data_table: String,
}
pub struct SendTable {
name: String,
props: Vec<SendPropDefinition>,
needs_decoder: bool,
flattened_props: Option<Vec<SendPropDefinition>>,
}
pub struct DataTablePacket {
tick: u32,
tables: Vec<SendTable>,
server_classes: Vec<ServerClass>,
}
impl<'a> Parse<'a> for DataTablePacket {
fn parse(stream: &mut Stream<'a>, state: &ParserState<'a>) -> Result<Self> {
let tick = stream.read(32)?;
let _len = stream.read::<u32>(32)?;
let mut tables = vec![];
while stream.read_bool()? {
let needs_decoder = stream.read_bool()?;
let name = stream.read_string(None)?;
let prop_count = stream.read(10)?;
let mut array_element_prop = None;
let mut props = Vec::with_capacity(prop_count);
for i in 0..prop_count {
let prop: SendPropDefinition = SendPropDefinition::parse(stream, state, name.clone())?;
if prop.flags.contains(SendPropFlag::InsideArray) {
if array_element_prop.is_some() || prop.flags.contains(SendPropFlag::ChangesOften) {
return Err(ParseError::InvalidSendPropArray);
}
array_element_prop = Some(prop);
} else if let Some(array_element) = array_element_prop {
if prop.prop_type == SendPropType::Array {
return Err(ParseError::InvalidSendPropArray);
}
array_element_prop = None;
props.push(prop.with_array_property(array_element));
} else {
props.push(prop);
}
}
let table = SendTable {
name,
flattened_props: None,
needs_decoder,
props,
};
tables.push(table);
}
// TODO linked tables?
let server_class_count = stream.read(16)?;
let mut server_classes = Vec::with_capacity(server_class_count);
for i in 0..server_class_count {
let id = stream.read(16)?;
let name = stream.read_string(None)?;
let data_table = stream.read_string(None)?;
server_classes.push(ServerClass {
id,
name,
data_table,
});
}
Ok(DataTablePacket {
tick,
tables,
server_classes,
})
}
fn skip(stream: &mut Stream) -> Result<()> {
let _ = stream.skip(32)?;
let len = stream.read(32)?;
stream.skip(len).map_err(ParseError::from)
}
}

View file

@ -0,0 +1,59 @@
use crate::{Parse, ParseError, ParserState, Result, Stream};
use crate::demo::vector::Vector;
pub struct Message;
pub struct MessagePacket {
tick: u32,
messages: Vec<Message>,
view_origin: (Vector, Vector),
view_angles: (Vector, Vector),
local_view_angles: (Vector, Vector),
sequence_in: u32,
sequence_out: u32,
flags: u32, // TODO
}
impl<'a> Parse<'a> for MessagePacket {
fn parse(stream: &mut Stream<'a>, state: &ParserState<'a>) -> Result<Self> {
let tick = stream.read(32)?;
let flags = stream.read(32)?;
let view_origin_1 = Vector::parse(stream, state)?;
let view_angle_1 = Vector::parse(stream, state)?;
let local_view_angle_1 = Vector::parse(stream, state)?;
let view_origin = (Vector::parse(stream, state)?, view_origin_1);
let view_angles = (Vector::parse(stream, state)?, view_angle_1);
let local_view_angles = (Vector::parse(stream, state)?, local_view_angle_1);
let sequence_in = stream.read(32)?;
let sequence_out = stream.read(32)?;
let length: usize = stream.read(32)?;
let _ = stream.skip(length).map_err(ParseError::from);
let mut messages = vec![];
Ok(MessagePacket {
tick,
messages,
view_origin,
view_angles,
local_view_angles,
sequence_in,
sequence_out,
flags,
})
}
fn skip(stream: &mut Stream) -> Result<()> {
let _ = stream.skip(32 * 2)?;
for i in 0..6 {
Vector::skip(stream)?;
}
let _ = stream.skip(32 * 2)?;
let length: usize = stream.read(32)?;
stream.skip(length).map_err(ParseError::from)
}
}

View file

@ -1,21 +1,39 @@
use crate::{Parse, ParseError, ParserState, Result, Stream};
use enum_primitive_derive::Primitive;
use num_traits::FromPrimitive;
use self::stop::Stop;
mod stop;
mod synctick;
mod consolecmd;
mod usercmd;
mod stringtable;
use crate::{Parse, ParseError, ParserState, Result, Stream};
pub enum Packet {
Stop(Stop)
use self::consolecmd::ConsoleCmdPacket;
use self::datatable::DataTablePacket;
use self::message::MessagePacket;
use self::stop::StopPacket;
use self::stringtable::StringTablePacket;
use self::synctick::SyncTickPacket;
use self::usercmd::UserCmdPacket;
pub mod consolecmd;
pub mod stop;
pub mod stringtable;
pub mod synctick;
pub mod usercmd;
pub mod datatable;
pub mod message;
pub enum Packet<'a> {
Sigon(MessagePacket),
Message(MessagePacket),
SyncTick(SyncTickPacket),
ConsoleCmd(ConsoleCmdPacket),
UserCmd(UserCmdPacket),
DataTables(DataTablePacket),
Stop(StopPacket),
StringTables(StringTablePacket<'a>),
}
#[derive(Primitive)]
pub enum PacketType {
Sigon = 1,
Packet = 2,
Message = 2,
SyncTick = 3,
ConsoleCmd = 4,
UserCmd = 5,
@ -24,23 +42,44 @@ pub enum PacketType {
StringTables = 8,
}
impl Packet {
fn read_type(stream: &mut Stream) -> Result<PacketType> {
impl Parse<'_> for PacketType {
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
let raw = stream.read(8)?;
let packet_type: Option<PacketType> = PacketType::from_u8(raw);
packet_type.ok_or(ParseError::InvalidPacketType(raw))
let prop_type: Option<PacketType> = PacketType::from_u8(raw);
prop_type.ok_or(ParseError::InvalidPacketType(raw))
}
fn skip(stream: &mut Stream) -> Result<()> {
stream.skip(8).map_err(ParseError::from)
}
}
//impl Parse for Packet {
// fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
// let packet_type = Packet::read_type(stream);
// match packet_type {
// Sigon => {}
// }
// }
//
// fn skip(stream: &mut Stream) -> Result<()> {
// Ok(())
// }
//}
impl<'a> Parse<'a> for Packet<'a> {
fn parse(stream: &mut Stream<'a>, state: &ParserState<'a>) -> Result<Self> {
let packet_type = PacketType::parse(stream, state)?;
Ok(match packet_type {
PacketType::Sigon => Packet::Sigon(MessagePacket::parse(stream, state)?),
PacketType::Message => Packet::Message(MessagePacket::parse(stream, state)?),
PacketType::SyncTick => Packet::SyncTick(SyncTickPacket::parse(stream, state)?),
PacketType::ConsoleCmd => Packet::ConsoleCmd(ConsoleCmdPacket::parse(stream, state)?),
PacketType::UserCmd => Packet::UserCmd(UserCmdPacket::parse(stream, state)?),
PacketType::DataTables => Packet::DataTables(DataTablePacket::parse(stream, state)?),
PacketType::Stop => Packet::Stop(StopPacket::parse(stream, state)?),
PacketType::StringTables => Packet::StringTables(StringTablePacket::parse(stream, state)?),
})
}
fn skip(stream: &mut Stream) -> Result<()> {
let packet_type = PacketType::parse(stream, &ParserState::new(&stream))?;
match packet_type {
PacketType::Sigon => MessagePacket::skip(stream),
PacketType::Message => MessagePacket::skip(stream),
PacketType::SyncTick => SyncTickPacket::skip(stream),
PacketType::ConsoleCmd => ConsoleCmdPacket::skip(stream),
PacketType::UserCmd => UserCmdPacket::skip(stream),
PacketType::DataTables => DataTablePacket::skip(stream),
PacketType::Stop => StopPacket::skip(stream),
PacketType::StringTables => StringTablePacket::skip(stream),
}
}
}

View file

@ -1,10 +1,10 @@
use crate::{Parse, ParserState, Result, Stream};
pub struct Stop;
pub struct StopPacket;
impl<'a> Parse<'a> for Stop {
impl<'a> Parse<'a> for StopPacket {
fn parse(_stream: &mut Stream, _state: &ParserState) -> Result<Self> {
Ok(Stop)
Ok(StopPacket)
}
fn skip(_stream: &mut Stream) -> Result<()> {

View file

@ -56,10 +56,7 @@ impl<'a> StringTableEntry<'a> {
} else {
None
};
Ok(StringTableEntry {
text,
extra_data,
})
Ok(StringTableEntry { text, extra_data })
}
}
@ -77,10 +74,7 @@ impl<'a> Parse<'a> for StringTablePacket<'a> {
for _ in 0..count {
tables.push(StringTable::parse(stream)?);
}
Ok(StringTablePacket {
tick,
tables,
})
Ok(StringTablePacket { tick, tables })
}
fn skip(stream: &mut Stream) -> Result<()> {

View file

@ -1,13 +1,13 @@
use crate::{Parse, ParseError, ParserState, Result, Stream};
pub struct SyncTickPacket {
tick: u32
tick: u32,
}
impl<'a> Parse<'a> for SyncTickPacket {
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
Ok(SyncTickPacket {
tick: stream.read(32)?
tick: stream.read(32)?,
})
}

View file

@ -3,7 +3,7 @@ use crate::{Parse, ParseError, ParserState, Result, Stream};
pub struct UserCmdPacket {
tick: u32,
command: String,
sequence_out: u32
sequence_out: u32,
}
impl<'a> Parse<'a> for UserCmdPacket {

View file

@ -1,6 +1,6 @@
use bitstream_reader::ReadError;
pub use crate::demo::parser::state::ParserState;
use crate::Stream;
use bitstream_reader::ReadError;
mod state;
@ -11,6 +11,10 @@ pub enum ParseError {
ReadError(ReadError),
/// Packet identifier is invalid
InvalidPacketType(u8),
/// SendProp type is invalid
InvalidSendPropType(u8),
/// Invalid structure found while creating array SendProp
InvalidSendPropArray,
}
impl From<ReadError> for ParseError {
@ -26,7 +30,6 @@ pub trait Parse<'a>: Sized {
fn skip(stream: &mut Stream) -> Result<()>;
}
pub struct DemoParser<'a> {
stream: Stream<'a>,
state: ParserState<'a>,

View file

@ -1,7 +1,7 @@
use crate::demo::gamevent::GameEventDefinition;
use crate::demo::sendprop::SendProp;
use std::collections::HashMap;
use crate::Stream;
use std::collections::HashMap;
pub struct ParserState<'a> {
pub version: u32,

View file

@ -1,17 +1,203 @@
use enum_primitive_derive::Primitive;
use enumflags2::BitFlags;
use enumflags2_derive::EnumFlags;
use num_traits::cast::FromPrimitive;
use crate::{Parse, ParseError, ParserState, Result, Stream};
use super::packet::datatable::SendTable;
use super::vector::{Vector, VectorXY};
pub struct SendPropDefinition {}
pub struct SendPropDefinition {
pub prop_type: SendPropType,
pub name: String,
pub flags: BitFlags<SendPropFlag>,
pub exclude_dt_name: Option<String>,
pub low_value: Option<f32>,
pub high_value: Option<f32>,
pub bit_count: Option<u32>,
pub original_bit_count: Option<u32>,
pub table: Option<SendTable>,
pub element_count: Option<u16>,
pub array_property: Option<Box<SendPropDefinition>>,
pub owner_table_name: String,
}
impl SendPropDefinition {
pub fn parse<'a>(stream: &mut Stream<'a>, state: &ParserState<'a>, owner_table_name: String) -> Result<Self> {
let prop_type = SendPropType::parse(stream, state)?;
let name = stream.read_string(None)?;
let flags = BitFlags::<SendPropFlag>::parse(stream, state)?;
let mut exclude_dt_name = None;
let mut element_count = None;
let mut low_value = None;
let mut high_value = None;
let mut bit_count = None;
if prop_type == SendPropType::DataTable {
exclude_dt_name = Some(stream.read_string(None)?);
} else {
if flags.contains(SendPropFlag::Exclude) {
exclude_dt_name = Some(stream.read_string(None)?);
} else if prop_type == SendPropType::Array {
element_count = Some(stream.read(10)?);
} else {
low_value = Some(stream.read_float()?);
high_value = Some(stream.read_float()?);
bit_count = Some(stream.read(7)?);
}
}
let original_bit_count = bit_count;
if flags.contains(SendPropFlag::NoScale) {
if prop_type == SendPropType::Float {
bit_count = Some(32);
} else if prop_type == SendPropType::Vector && !flags.contains(SendPropFlag::NormalVarInt) {
bit_count = Some(32 * 3);
}
}
Ok(SendPropDefinition {
prop_type,
name,
flags,
exclude_dt_name,
low_value,
high_value,
bit_count,
original_bit_count,
table: None,
element_count,
array_property: None,
owner_table_name,
})
}
pub fn with_array_property(self, array_property: Self) -> Self {
SendPropDefinition {
prop_type: self.prop_type,
name: self.name,
flags: self.flags,
exclude_dt_name: self.exclude_dt_name,
low_value: self.low_value,
high_value: self.high_value,
bit_count: self.bit_count,
original_bit_count: self.original_bit_count,
table: None,
element_count: self.element_count,
array_property: Some(Box::new(array_property)),
owner_table_name: self.owner_table_name,
}
}
}
#[derive(Primitive, Copy, Clone, PartialEq, Debug)]
pub enum SendPropType {
Int = 0,
Float = 1,
Vector = 2,
VectorXY = 3,
String = 4,
Array = 5,
DataTable = 6,
NumSendPropTypes = 7,
}
impl Parse<'_> for SendPropType {
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
let raw = stream.read(5)?;
let prop_type: Option<SendPropType> = SendPropType::from_u8(raw);
prop_type.ok_or(ParseError::InvalidSendPropType(raw))
}
fn skip(stream: &mut Stream) -> Result<()> {
stream.skip(5).map_err(ParseError::from)
}
}
#[derive(EnumFlags, Copy, Clone, PartialEq, Debug)]
#[repr(u16)]
pub enum SendPropFlag {
Unsigned = 1,
//(1 << 0)
// Unsigned integer data.
Coord = 2,
//(1 << 1)
// If this is set, the float/vector is treated like a world coordinate.
// Note that the bit count is ignored in this case.
NoScale = 4,
//(1 << 2)
// For floating point, don't scale into range, just take value as is.
RoundDown = 8,
//(1 << 3)
// For floating point, limit high value to range minus one bit unit
RoundUp = 16,
//(1 << 4)
// For floating point, limit low value to range minus one bit unit
// Normal = 32, // seems to be depricated
//(1 << 5)
// If this is set, the vector is treated like a normal (only valid for vectors)
Exclude = 64,
//(1 << 6)
// This is an exclude prop (not excludED, but it points at another prop to be excluded).
XYZE = 128,
//(1 << 7)
// Use XYZ/Exponent encoding for vectors.
InsideArray = 256,
//(1 << 8)
// This tells us that the property is inside an array, so it shouldn't be put into the
// flattened property list. Its array will point at it when it needs to.
PropxyAlwaysYes = 512,
//(1 << 9)
// Set for datatable props using one of the default datatable proxies like
// SendProxy_DataTableToDataTable that always send the data to all clients.
ChangesOften = 1024,
//(1 << 10)
// this is an often changed field, moved to head of sendtable so it gets a small index
IsVectorElement = 2048,
//(1 << 11)
// Set automatically if SPROP_VECTORELEM is used.
Collapsible = 4096,
//(1 << 12)
// Set automatically if it's a datatable with an offset of 0 that doesn't change the pointer
// (ie: for all automatically-chained base classes).
// In this case, it can get rid of this SendPropDataTable altogether and spare the
// trouble of walking the hierarchy more than necessary.
CoordMP = 8192,
//(1 << 13)
// Like SPROP_COORD, but special handling for multiplayer games
CoordMPLowPercision = 16384,
//(1 << 14)
// Like SPROP_COORD, but special handling for multiplayer games
// where the fractional component only gets a 3 bits instead of 5
CoordMPIntegral = 32768,
//(1 << 15)
// SPROP_COORD_MP, but coordinates are rounded to integral boundaries
// overloaded as both "Normal" and "VarInt"
NormalVarInt = 32, //(1 << 5)
}
impl Parse<'_> for BitFlags<SendPropFlag> {
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
let raw = stream.read(16)?;
// since all 16 bits worth of flags are used there are no invalid flags
Ok(BitFlags::from_bits_truncate(raw))
}
fn skip(stream: &mut Stream) -> Result<()> {
stream.skip(16).map_err(ParseError::from)
}
}
pub enum SendPropValue {
Vector(Vector),
VectorXY(VectorXY),
Integer(i32),
Float(f32),
String(String),
Array(Vec<SendPropType>),
Array(Vec<SendPropValue>),
}
pub struct SendProp {
definition: SendPropDefinition,
value: SendPropType,
value: SendPropValue,
}

View file

@ -1,10 +1,39 @@
use crate::{Parse, ParseError, ParserState, Result, Stream};
pub struct Vector {
pub x: f32,
pub y: f32,
pub z: f32,
}
impl Parse<'_> for Vector {
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
Ok(Vector {
x: stream.read_float()?,
y: stream.read_float()?,
z: stream.read_float()?,
})
}
fn skip(stream: &mut Stream) -> Result<()> {
stream.skip(32 * 3).map_err(ParseError::from)
}
}
pub struct VectorXY {
pub x: f32,
pub y: f32,
}
impl Parse<'_> for VectorXY {
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
Ok(VectorXY {
x: stream.read_float()?,
y: stream.read_float()?,
})
}
fn skip(stream: &mut Stream) -> Result<()> {
stream.skip(32 * 2).map_err(ParseError::from)
}
}

View file

@ -1,10 +1,10 @@
#[macro_use]
extern crate rental;
#[macro_use]
extern crate enum_primitive_derive;
extern crate num_traits;
pub use demo::{Demo, parser::{Parse, ParseError, ParserState, Result, DemoParser}, Stream};
pub use demo::{
parser::{DemoParser, Parse, ParseError, ParserState, Result},
Demo, Stream,
};
mod demo;
mod state;
@ -13,4 +13,3 @@ mod test;
fn main() {
println!("Hello, world!");
}

View file

@ -0,0 +1 @@