mirror of
https://codeberg.org/demostf/parser.git
synced 2026-06-03 18:24:05 +02:00
packet parsers
This commit is contained in:
parent
4ac2a3cfc6
commit
b41bb56822
19 changed files with 626 additions and 64 deletions
159
Cargo.lock
generated
Normal file
159
Cargo.lock
generated
Normal 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"
|
||||||
|
|
@ -9,3 +9,5 @@ bitstream_reader = { path = "../../bitbuffer" }
|
||||||
rental = "0.5"
|
rental = "0.5"
|
||||||
enum-primitive-derive = "0.1.2"
|
enum-primitive-derive = "0.1.2"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
|
enumflags2 = "0.5"
|
||||||
|
enumflags2_derive = "0.5"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{ParseError, Parse, Result, Stream, ParserState};
|
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||||
//use crate::test::test_parse;
|
//use crate::test::test_parse;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ use rentals::OwnedBuffer;
|
||||||
|
|
||||||
pub mod gamevent;
|
pub mod gamevent;
|
||||||
pub mod header;
|
pub mod header;
|
||||||
|
pub mod packet;
|
||||||
|
pub mod parser;
|
||||||
pub mod sendprop;
|
pub mod sendprop;
|
||||||
pub mod vector;
|
pub mod vector;
|
||||||
pub mod parser;
|
|
||||||
pub mod packet;
|
|
||||||
|
|
||||||
pub type Buffer<'a> = BitBuffer<'a, LittleEndian, NonPadded>;
|
pub type Buffer<'a> = BitBuffer<'a, LittleEndian, NonPadded>;
|
||||||
pub type Stream<'a> = BitStream<'a, LittleEndian, NonPadded>;
|
pub type Stream<'a> = BitStream<'a, LittleEndian, NonPadded>;
|
||||||
|
|
|
||||||
91
src/demo/packet/datatable.rs
Normal file
91
src/demo/packet/datatable.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/demo/packet/message.rs
Normal file
59
src/demo/packet/message.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,21 +1,39 @@
|
||||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
use enum_primitive_derive::Primitive;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
use self::stop::Stop;
|
|
||||||
|
|
||||||
mod stop;
|
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||||
mod synctick;
|
|
||||||
mod consolecmd;
|
|
||||||
mod usercmd;
|
|
||||||
mod stringtable;
|
|
||||||
|
|
||||||
pub enum Packet {
|
use self::consolecmd::ConsoleCmdPacket;
|
||||||
Stop(Stop)
|
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)]
|
#[derive(Primitive)]
|
||||||
pub enum PacketType {
|
pub enum PacketType {
|
||||||
Sigon = 1,
|
Sigon = 1,
|
||||||
Packet = 2,
|
Message = 2,
|
||||||
SyncTick = 3,
|
SyncTick = 3,
|
||||||
ConsoleCmd = 4,
|
ConsoleCmd = 4,
|
||||||
UserCmd = 5,
|
UserCmd = 5,
|
||||||
|
|
@ -24,23 +42,44 @@ pub enum PacketType {
|
||||||
StringTables = 8,
|
StringTables = 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Packet {
|
impl Parse<'_> for PacketType {
|
||||||
fn read_type(stream: &mut Stream) -> Result<PacketType> {
|
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||||
let raw = stream.read(8)?;
|
let raw = stream.read(8)?;
|
||||||
let packet_type: Option<PacketType> = PacketType::from_u8(raw);
|
let prop_type: Option<PacketType> = PacketType::from_u8(raw);
|
||||||
packet_type.ok_or(ParseError::InvalidPacketType(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 {
|
impl<'a> Parse<'a> for Packet<'a> {
|
||||||
// fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
fn parse(stream: &mut Stream<'a>, state: &ParserState<'a>) -> Result<Self> {
|
||||||
// let packet_type = Packet::read_type(stream);
|
let packet_type = PacketType::parse(stream, state)?;
|
||||||
// match packet_type {
|
Ok(match packet_type {
|
||||||
// Sigon => {}
|
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)?),
|
||||||
// fn skip(stream: &mut Stream) -> Result<()> {
|
PacketType::UserCmd => Packet::UserCmd(UserCmdPacket::parse(stream, state)?),
|
||||||
// Ok(())
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::{Parse, ParserState, Result, Stream};
|
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> {
|
fn parse(_stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||||
Ok(Stop)
|
Ok(StopPacket)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip(_stream: &mut Stream) -> Result<()> {
|
fn skip(_stream: &mut Stream) -> Result<()> {
|
||||||
|
|
|
||||||
|
|
@ -56,10 +56,7 @@ impl<'a> StringTableEntry<'a> {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
Ok(StringTableEntry {
|
Ok(StringTableEntry { text, extra_data })
|
||||||
text,
|
|
||||||
extra_data,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,10 +74,7 @@ impl<'a> Parse<'a> for StringTablePacket<'a> {
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
tables.push(StringTable::parse(stream)?);
|
tables.push(StringTable::parse(stream)?);
|
||||||
}
|
}
|
||||||
Ok(StringTablePacket {
|
Ok(StringTablePacket { tick, tables })
|
||||||
tick,
|
|
||||||
tables,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip(stream: &mut Stream) -> Result<()> {
|
fn skip(stream: &mut Stream) -> Result<()> {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||||
|
|
||||||
pub struct SyncTickPacket {
|
pub struct SyncTickPacket {
|
||||||
tick: u32
|
tick: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parse<'a> for SyncTickPacket {
|
impl<'a> Parse<'a> for SyncTickPacket {
|
||||||
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||||
Ok(SyncTickPacket {
|
Ok(SyncTickPacket {
|
||||||
tick: stream.read(32)?
|
tick: stream.read(32)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||||
pub struct UserCmdPacket {
|
pub struct UserCmdPacket {
|
||||||
tick: u32,
|
tick: u32,
|
||||||
command: String,
|
command: String,
|
||||||
sequence_out: u32
|
sequence_out: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parse<'a> for UserCmdPacket {
|
impl<'a> Parse<'a> for UserCmdPacket {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use bitstream_reader::ReadError;
|
|
||||||
pub use crate::demo::parser::state::ParserState;
|
pub use crate::demo::parser::state::ParserState;
|
||||||
use crate::Stream;
|
use crate::Stream;
|
||||||
|
use bitstream_reader::ReadError;
|
||||||
|
|
||||||
mod state;
|
mod state;
|
||||||
|
|
||||||
|
|
@ -11,6 +11,10 @@ pub enum ParseError {
|
||||||
ReadError(ReadError),
|
ReadError(ReadError),
|
||||||
/// Packet identifier is invalid
|
/// Packet identifier is invalid
|
||||||
InvalidPacketType(u8),
|
InvalidPacketType(u8),
|
||||||
|
/// SendProp type is invalid
|
||||||
|
InvalidSendPropType(u8),
|
||||||
|
/// Invalid structure found while creating array SendProp
|
||||||
|
InvalidSendPropArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ReadError> for ParseError {
|
impl From<ReadError> for ParseError {
|
||||||
|
|
@ -26,7 +30,6 @@ pub trait Parse<'a>: Sized {
|
||||||
fn skip(stream: &mut Stream) -> Result<()>;
|
fn skip(stream: &mut Stream) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct DemoParser<'a> {
|
pub struct DemoParser<'a> {
|
||||||
stream: Stream<'a>,
|
stream: Stream<'a>,
|
||||||
state: ParserState<'a>,
|
state: ParserState<'a>,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::demo::gamevent::GameEventDefinition;
|
use crate::demo::gamevent::GameEventDefinition;
|
||||||
use crate::demo::sendprop::SendProp;
|
use crate::demo::sendprop::SendProp;
|
||||||
use std::collections::HashMap;
|
|
||||||
use crate::Stream;
|
use crate::Stream;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct ParserState<'a> {
|
pub struct ParserState<'a> {
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
|
|
|
||||||
|
|
@ -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};
|
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 {
|
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),
|
Vector(Vector),
|
||||||
VectorXY(VectorXY),
|
VectorXY(VectorXY),
|
||||||
Integer(i32),
|
Integer(i32),
|
||||||
Float(f32),
|
Float(f32),
|
||||||
String(String),
|
String(String),
|
||||||
Array(Vec<SendPropType>),
|
Array(Vec<SendPropValue>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SendProp {
|
pub struct SendProp {
|
||||||
definition: SendPropDefinition,
|
definition: SendPropDefinition,
|
||||||
value: SendPropType,
|
value: SendPropValue,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,39 @@
|
||||||
|
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||||
|
|
||||||
pub struct Vector {
|
pub struct Vector {
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
pub y: f32,
|
pub y: f32,
|
||||||
pub z: 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 struct VectorXY {
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
pub y: 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rental;
|
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 demo;
|
||||||
mod state;
|
mod state;
|
||||||
|
|
@ -13,4 +13,3 @@ mod test;
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue