mirror of
https://codeberg.org/demostf/parser.git
synced 2026-06-03 18:24:05 +02:00
update to new bitreader
This commit is contained in:
parent
f5e236c58b
commit
e7b9f5ecbb
25 changed files with 378 additions and 590 deletions
44
Cargo.lock
generated
44
Cargo.lock
generated
|
|
@ -2,11 +2,21 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitstream_reader"
|
name = "bitstream_reader"
|
||||||
version = "0.2.0"
|
version = "0.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bitstream_reader_derive 0.3.0",
|
||||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitstream_reader_derive"
|
||||||
|
version = "0.3.0"
|
||||||
|
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]]
|
[[package]]
|
||||||
name = "enum-primitive-derive"
|
name = "enum-primitive-derive"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
|
@ -66,30 +76,6 @@ dependencies = [
|
||||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "0.11.11"
|
version = "0.11.11"
|
||||||
|
|
@ -119,15 +105,14 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tf-demo-demo"
|
name = "tf-demo-parser"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitstream_reader 0.2.0",
|
"bitstream_reader 0.3.1",
|
||||||
"enum-primitive-derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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 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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
|
|
@ -149,9 +134,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
|
"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.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 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.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 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 synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||||
|
|
|
||||||
12
Cargo.toml
12
Cargo.toml
|
|
@ -1,12 +1,18 @@
|
||||||
[package]
|
[package]
|
||||||
name = "tf-demo-demo"
|
name = "tf-demo-parser"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Robin Appelman <robin@icewind.nl>"]
|
authors = ["Robin Appelman <robin@icewind.nl>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "tf_demo_parser"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "test"
|
||||||
|
path = "src/bin/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitstream_reader = { path = "../../bitbuffer" }
|
bitstream_reader = { version = "0.3", path = "../../bitbuffer" }
|
||||||
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 = "0.5"
|
||||||
|
|
|
||||||
45
parse_gen/Cargo.lock
generated
45
parse_gen/Cargo.lock
generated
|
|
@ -1,45 +0,0 @@
|
||||||
[[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.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 = "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 = "tf-demo-demo-derive"
|
|
||||||
version = "0.1.0"
|
|
||||||
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 = "unicode-xid"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[metadata]
|
|
||||||
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
|
|
||||||
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
|
|
||||||
"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
|
|
||||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "tf-demo-parser-derive"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Robin Appelman <robin@icewind.nl>"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
name = "tf_demo_parse_derive"
|
|
||||||
proc-macro = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
syn = "0.15"
|
|
||||||
quote = "0.6"
|
|
||||||
proc-macro2 = "0.4"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
tf-demo-parser = { path = ".." }
|
|
||||||
bitstream_reader = { path = "../../../bitbuffer" }
|
|
||||||
|
|
@ -1,149 +0,0 @@
|
||||||
extern crate proc_macro;
|
|
||||||
|
|
||||||
use proc_macro2::{TokenStream, Span};
|
|
||||||
use quote::{quote, quote_spanned};
|
|
||||||
use quote::{TokenStreamExt, ToTokens};
|
|
||||||
use syn::{Data, DeriveInput, Field, Fields, GenericParam, Generics, Ident, Index, Lit, Meta, parse_macro_input, parse_quote, Path, Token, Type, TypePath};
|
|
||||||
use syn::spanned::Spanned;
|
|
||||||
|
|
||||||
#[proc_macro_derive(Parse, attributes(size))]
|
|
||||||
pub fn derive_helper_attr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
|
||||||
|
|
||||||
// Used in the quasi-quotation below as `#name`.
|
|
||||||
let name = input.ident;
|
|
||||||
|
|
||||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
|
||||||
|
|
||||||
let parse = parse(&input.data, &name);
|
|
||||||
|
|
||||||
let expanded = quote! {
|
|
||||||
impl #impl_generics ::tf_demo_parser::Parse<'_> for #name #ty_generics #where_clause {
|
|
||||||
fn parse(stream: &mut ::tf_demo_parser::Stream, _state: &::tf_demo_parser::ParserState) -> ::tf_demo_parser::Result<Self> {
|
|
||||||
Ok(#parse)
|
|
||||||
}
|
|
||||||
fn skip(stream: &mut ::tf_demo_parser::Stream) -> ::tf_demo_parser::Result<()> {
|
|
||||||
// TODO
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//panic!("{}", TokenStream::to_string(&expanded));
|
|
||||||
|
|
||||||
// Hand the output tokens back to the compiler
|
|
||||||
proc_macro::TokenStream::from(expanded)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a bound `T: HeapSize` to every type parameter T.
|
|
||||||
fn add_trait_bounds(mut generics: Generics) -> Generics {
|
|
||||||
for param in &mut generics.params {
|
|
||||||
if let GenericParam::Type(ref mut type_param) = *param {
|
|
||||||
type_param.bounds.push(parse_quote!(::heapsize::HeapSize));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
generics
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse(data: &Data, struct_name: &Ident) -> TokenStream {
|
|
||||||
match *data {
|
|
||||||
Data::Struct(ref data) => {
|
|
||||||
match data.fields {
|
|
||||||
Fields::Named(ref fields) => {
|
|
||||||
let recurse = fields.named.iter().map(|f| {
|
|
||||||
let name = &f.ident;
|
|
||||||
// Get attributes `#[..]` on each field
|
|
||||||
let size = get_field_size(f);
|
|
||||||
let parser = parse_type(&f.ty, size);
|
|
||||||
quote_spanned! { f.span()=>
|
|
||||||
#name: #parser?,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
quote! {
|
|
||||||
#struct_name {
|
|
||||||
#(#recurse)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_field_size(field: &Field) -> Option<usize> {
|
|
||||||
for attr in field.attrs.iter() {
|
|
||||||
// Parse the attribute
|
|
||||||
let meta = attr.parse_meta().unwrap();
|
|
||||||
match meta {
|
|
||||||
// Matches attribute with single word like `#[nng_member]` (as opposed to `#[derive(NngGetOps)]` or `#[nng_member = "socket"]`)
|
|
||||||
Meta::NameValue(ref nameValue) if nameValue.ident == "size" =>
|
|
||||||
match &nameValue.lit {
|
|
||||||
Lit::Int(size) => {
|
|
||||||
return Some(size.value() as usize);
|
|
||||||
}
|
|
||||||
_ => panic!("Invalid size for field")
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_type(ty: &Type, size: Option<usize>) -> TokenStream {
|
|
||||||
match ty {
|
|
||||||
Type::Path(path) => {
|
|
||||||
let types: Vec<(TypePath, Option<usize>, &str)> = vec![
|
|
||||||
(parse_quote!(String), None, "read_string"),
|
|
||||||
(parse_quote!(bool), None, "read"),
|
|
||||||
(parse_quote!(u8), Some(8), "read"),
|
|
||||||
(parse_quote!(u16), Some(16), "read"),
|
|
||||||
(parse_quote!(u32), Some(32), "read"),
|
|
||||||
(parse_quote!(i8), Some(8), "read"),
|
|
||||||
(parse_quote!(i16), Some(16), "read"),
|
|
||||||
(parse_quote!(i32), Some(32), "read"),
|
|
||||||
(parse_quote!(f32), None, "read_float"),
|
|
||||||
(parse_quote!(f64), None, "read_float"),
|
|
||||||
];
|
|
||||||
for (type_option, default_size, method) in types {
|
|
||||||
let method_ident = Ident::new(method,Span::call_site());
|
|
||||||
if type_option == *path {
|
|
||||||
match default_size {
|
|
||||||
Some(default) => {
|
|
||||||
let size = size.unwrap_or(default);
|
|
||||||
return quote! {
|
|
||||||
stream.#method_ident(#size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if method == "read_string" {
|
|
||||||
let size = QuoteOption(size);
|
|
||||||
return quote! {
|
|
||||||
stream.#method_ident(#size)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return quote! {
|
|
||||||
stream.#method_ident()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unimplemented!("a");
|
|
||||||
}
|
|
||||||
_ => unimplemented!("b"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct QuoteOption<T>(Option<T>);
|
|
||||||
|
|
||||||
impl<T: ToTokens> ToTokens for QuoteOption<T> {
|
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
||||||
tokens.append_all(match self.0 {
|
|
||||||
Some(ref t) => quote! { ::std::option::Option::Some(#t) },
|
|
||||||
None => quote! { ::std::option::Option::None },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
|
|
||||||
|
|
||||||
use tf_demo_parse_derive::Parse;
|
|
||||||
use tf_demo_parser::Parse;
|
|
||||||
use tf_demo_parser::ParserState;
|
|
||||||
|
|
||||||
#[derive(Parse, PartialEq, Debug)]
|
|
||||||
struct TestStruct {
|
|
||||||
foo: u8,
|
|
||||||
str: String,
|
|
||||||
#[size = 2]
|
|
||||||
truncated: String,
|
|
||||||
bar: u16,
|
|
||||||
float: f32,
|
|
||||||
#[size = 3]
|
|
||||||
asd: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_read_struct() {
|
|
||||||
let float: [u8; 4] = 12.5f32.to_bits().to_le_bytes();
|
|
||||||
let bytes = &[
|
|
||||||
12, 'h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8, 0, 'f' as u8,
|
|
||||||
'o' as u8, 'o' as u8, 0, float[0], float[1], float[2], float[3], 0b0101_0101
|
|
||||||
];
|
|
||||||
let buffer = BitBuffer::new(bytes, LittleEndian);
|
|
||||||
let mut stream = BitStream::new(buffer, None, None);
|
|
||||||
let state = ParserState::new(&stream);
|
|
||||||
assert_eq!(TestStruct {
|
|
||||||
foo: 12,
|
|
||||||
str: "hello".to_owned(),
|
|
||||||
truncated: "fo".to_owned(),
|
|
||||||
bar: 'o' as u16,
|
|
||||||
float: 12.5,
|
|
||||||
asd: 0b101,
|
|
||||||
}, TestStruct::parse(&mut stream, &state).unwrap());
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +1,7 @@
|
||||||
#[macro_use]
|
|
||||||
extern crate rental;
|
|
||||||
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
pub use demo::{
|
pub use tf_demo_parser::{Demo, DemoParser, Parse, ParseError, ParserState, Result, Stream};
|
||||||
Demo,
|
|
||||||
parser::{DemoParser, Parse, ParseError, ParserState, Result}, Stream,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod demo;
|
|
||||||
mod state;
|
|
||||||
mod test;
|
|
||||||
|
|
||||||
fn main() -> std::result::Result<(), Box<ParseError>> {
|
fn main() -> std::result::Result<(), Box<ParseError>> {
|
||||||
let file = fs::read("data/small.dem").expect("Unable to read file");
|
let file = fs::read("data/small.dem").expect("Unable to read file");
|
||||||
|
|
@ -1,62 +1,23 @@
|
||||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
use bitstream_reader::{BitRead, LittleEndian};
|
||||||
//use crate::test::test_parse;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug, PartialEq)]
|
||||||
pub struct Header {
|
pub struct Header {
|
||||||
|
#[size = 8]
|
||||||
pub demo_type: String,
|
pub demo_type: String,
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
pub protocol: u32,
|
pub protocol: u32,
|
||||||
|
#[size = 260]
|
||||||
pub server: String,
|
pub server: String,
|
||||||
|
#[size = 260]
|
||||||
pub nick: String,
|
pub nick: String,
|
||||||
|
#[size = 260]
|
||||||
pub map: String,
|
pub map: String,
|
||||||
|
#[size = 260]
|
||||||
pub game: String,
|
pub game: String,
|
||||||
pub duration: f32,
|
pub duration: f32,
|
||||||
pub ticks: u32,
|
pub ticks: u32,
|
||||||
pub frames: u32,
|
pub frames: u32,
|
||||||
pub sigon: u32,
|
pub sigon: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parse<'a> for Header {
|
|
||||||
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Header> {
|
|
||||||
Ok(Header {
|
|
||||||
demo_type: stream.read_string(Some(8))?,
|
|
||||||
version: stream.read(32)?,
|
|
||||||
protocol: stream.read(32)?,
|
|
||||||
server: stream.read_string(Some(260))?,
|
|
||||||
nick: stream.read_string(Some(260))?,
|
|
||||||
map: stream.read_string(Some(260))?,
|
|
||||||
game: stream.read_string(Some(260))?,
|
|
||||||
duration: stream.read_float()?,
|
|
||||||
ticks: stream.read(32)?,
|
|
||||||
frames: stream.read(32)?,
|
|
||||||
sigon: stream.read(32)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn skip(stream: &mut Stream) -> Result<()> {
|
|
||||||
stream
|
|
||||||
.skip(8 * 8 + (32 * 2) + (260 * 8 * 4) + (32 * 4))
|
|
||||||
.map_err(ParseError::from)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//#[test]
|
|
||||||
//fn test_header() {
|
|
||||||
// test_parse(
|
|
||||||
// "data/small.dem",
|
|
||||||
// Header {
|
|
||||||
// demo_type: "HL2DEMO".to_owned(),
|
|
||||||
// version: 3,
|
|
||||||
// protocol: 24,
|
|
||||||
// server: "localhost:27015".to_owned(),
|
|
||||||
// nick: "Icewind | demos.tf".to_owned(),
|
|
||||||
// map: "cp_gullywash".to_owned(),
|
|
||||||
// game: "tf".to_owned(),
|
|
||||||
// duration: 1.7249999,
|
|
||||||
// ticks: 115,
|
|
||||||
// frames: 111,
|
|
||||||
// sigon: 218908,
|
|
||||||
// },
|
|
||||||
// 0,
|
|
||||||
// );
|
|
||||||
//}
|
|
||||||
|
|
|
||||||
93
src/demo/message/generated.rs
Normal file
93
src/demo/message/generated.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
/// Messages that consists only of primitives and string and can be derived
|
||||||
|
|
||||||
|
use bitstream_reader::BitRead;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug)]
|
||||||
|
pub struct FileMessage {
|
||||||
|
pub transfer_id: u32,
|
||||||
|
pub file_name: String,
|
||||||
|
pub requested: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug)]
|
||||||
|
pub struct NetTickMessage {
|
||||||
|
pub tick: u32,
|
||||||
|
pub frame_time: u16,
|
||||||
|
pub std_dev: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug)]
|
||||||
|
pub struct StringCmdMessage {
|
||||||
|
pub command: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug)]
|
||||||
|
pub struct SigOnStateMessage {
|
||||||
|
pub state: u8,
|
||||||
|
pub count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug)]
|
||||||
|
pub struct PrintMessage {
|
||||||
|
pub value: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug)]
|
||||||
|
pub struct ServerInfoMessage {
|
||||||
|
pub version: u16,
|
||||||
|
pub server_count: u32,
|
||||||
|
pub stv: bool,
|
||||||
|
pub dedicated: bool,
|
||||||
|
pub max_crc: u32,
|
||||||
|
pub max_classes: u16,
|
||||||
|
pub map_hash: u128,
|
||||||
|
pub player_count: u8,
|
||||||
|
pub max_player_count: u8,
|
||||||
|
pub interval_per_tick: f32,
|
||||||
|
#[size = 1]
|
||||||
|
pub platform: String,
|
||||||
|
pub game: String,
|
||||||
|
pub map: String,
|
||||||
|
pub skybox: String,
|
||||||
|
pub server_name: String,
|
||||||
|
pub replay: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug)]
|
||||||
|
pub struct SetPauseMessage {
|
||||||
|
pub pause: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug)]
|
||||||
|
pub struct SetViewMessage {
|
||||||
|
#[size = 11]
|
||||||
|
pub index: u16
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug)]
|
||||||
|
pub struct FixAngleMessage {
|
||||||
|
pub relative: bool,
|
||||||
|
pub x: u16,
|
||||||
|
pub y: u16,
|
||||||
|
pub z: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug)]
|
||||||
|
pub struct PreFetchMessage {
|
||||||
|
#[size = 14]
|
||||||
|
pub index: u16
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug)]
|
||||||
|
pub struct GetCvarMessage {
|
||||||
|
pub cookie: u32,
|
||||||
|
pub value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug)]
|
||||||
|
pub struct SetConVarMessage {
|
||||||
|
#[size_bits = 8]
|
||||||
|
vars: HashMap<String, String>
|
||||||
|
}
|
||||||
51
src/demo/message/mod.rs
Normal file
51
src/demo/message/mod.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
use enum_primitive_derive::Primitive;
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
|
|
||||||
|
pub use generated::*;
|
||||||
|
|
||||||
|
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||||
|
|
||||||
|
mod generated;
|
||||||
|
|
||||||
|
#[derive(Primitive, Debug)]
|
||||||
|
pub enum MessageType {
|
||||||
|
File = 2,
|
||||||
|
NetTick = 3,
|
||||||
|
StringCmd = 4,
|
||||||
|
SetConVar = 5,
|
||||||
|
SigOnState = 6,
|
||||||
|
Print = 7,
|
||||||
|
ServerInfo = 8,
|
||||||
|
ClassInfo = 10,
|
||||||
|
SetPause = 11,
|
||||||
|
CreateStringTable = 12,
|
||||||
|
UpdateStringTable = 13,
|
||||||
|
VoiceInit = 14,
|
||||||
|
VoiceData = 15,
|
||||||
|
ParseSounds = 17,
|
||||||
|
SetView = 18,
|
||||||
|
FixAngle = 19,
|
||||||
|
BspDecal = 21,
|
||||||
|
UserMessage = 23,
|
||||||
|
EntityMessage = 24,
|
||||||
|
GameEvent = 25,
|
||||||
|
PacketEntities = 26,
|
||||||
|
TempEntities = 27,
|
||||||
|
PreFetch = 28,
|
||||||
|
Menu = 29,
|
||||||
|
GameEventList = 30,
|
||||||
|
GetCvarValue = 31,
|
||||||
|
CmdKeyValues = 32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for MessageType {
|
||||||
|
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||||
|
let raw = stream.read_int(6)?;
|
||||||
|
let prop_type: Option<MessageType> = MessageType::from_u8(raw);
|
||||||
|
prop_type.ok_or(ParseError::InvalidMessageType(raw))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip(stream: &mut Stream) -> Result<()> {
|
||||||
|
stream.skip(6).map_err(ParseError::from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,41 +1,31 @@
|
||||||
use bitstream_reader::{BitBuffer, BitStream, LittleEndian, NonPadded};
|
use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
|
||||||
use crate::{ParserState, Parse, ParseError, Result};
|
|
||||||
use rentals::OwnedBuffer;
|
use crate::{Parse, ParseError, ParserState, Result};
|
||||||
|
|
||||||
pub mod gamevent;
|
pub mod gamevent;
|
||||||
pub mod header;
|
pub mod header;
|
||||||
|
pub mod message;
|
||||||
pub mod packet;
|
pub mod packet;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod sendprop;
|
pub mod sendprop;
|
||||||
pub mod vector;
|
pub mod vector;
|
||||||
|
|
||||||
pub type Buffer<'a> = BitBuffer<'a, LittleEndian, NonPadded>;
|
pub type Buffer = BitBuffer<LittleEndian>;
|
||||||
pub type Stream<'a> = BitStream<'a, LittleEndian, NonPadded>;
|
pub type Stream = BitStream<LittleEndian>;
|
||||||
|
|
||||||
rental! {
|
|
||||||
mod rentals {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[rental_mut(covariant)]
|
|
||||||
pub struct OwnedBuffer {
|
|
||||||
source_vec: Vec<u8>,
|
|
||||||
stream: Buffer<'source_vec>,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Demo {
|
pub struct Demo {
|
||||||
data: OwnedBuffer,
|
stream: Stream,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Demo {
|
impl Demo {
|
||||||
pub fn new(vec: Vec<u8>) -> Self {
|
pub fn new(vec: Vec<u8>) -> Self {
|
||||||
let data = OwnedBuffer::new(vec, |bytes| BitBuffer::new(bytes, LittleEndian));
|
let data = Buffer::new(vec, LittleEndian);
|
||||||
Demo { data }
|
let stream = Stream::new(data);
|
||||||
|
Demo { stream }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a new stream with the data of the demo
|
/// Get a new stream with the data of the demo
|
||||||
pub fn get_stream(&self) -> Stream {
|
pub fn get_stream(&self) -> Stream {
|
||||||
BitStream::new(self.data.suffix().clone(), None, None)
|
self.stream.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
use bitstream_reader::{BitRead, LittleEndian};
|
||||||
|
|
||||||
|
use crate::{Parse, ParseError, ParserState, Result, Stream, ReadResult};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ConsoleCmdPacket {
|
pub struct ConsoleCmdPacket {
|
||||||
|
|
@ -6,21 +8,12 @@ pub struct ConsoleCmdPacket {
|
||||||
command: String,
|
command: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parse<'a> for ConsoleCmdPacket {
|
impl BitRead<LittleEndian> for ConsoleCmdPacket {
|
||||||
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
fn read(stream: &mut Stream) -> ReadResult<Self> {
|
||||||
let tick = stream.read(32)?;
|
let tick = stream.read_int(32)?;
|
||||||
let len = stream.read::<usize>(32)?;
|
let len = stream.read_int::<usize>(32)?;
|
||||||
let mut packet_data = stream.read_bits(len * 8)?;
|
let mut packet_data = stream.read_bits(len * 8)?;
|
||||||
let command = packet_data.read_string(None)?;
|
let command = packet_data.read_string(None)?;
|
||||||
Ok(ConsoleCmdPacket {
|
Ok(ConsoleCmdPacket { tick, command })
|
||||||
tick,
|
|
||||||
command,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn skip(stream: &mut Stream) -> Result<()> {
|
|
||||||
let _ = stream.skip(32)?;
|
|
||||||
let len = stream.read::<usize>(32)?;
|
|
||||||
stream.skip(len * 8).map_err(ParseError::from)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
use bitstream_reader::{BitRead, LittleEndian};
|
||||||
|
|
||||||
|
use crate::{Parse, ParseError, ParserState, Result, Stream, ReadResult};
|
||||||
use crate::demo::sendprop::{SendPropDefinition, SendPropFlag, SendPropType};
|
use crate::demo::sendprop::{SendPropDefinition, SendPropFlag, SendPropType};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -23,32 +25,39 @@ pub struct DataTablePacket {
|
||||||
server_classes: Vec<ServerClass>,
|
server_classes: Vec<ServerClass>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parse<'a> for DataTablePacket {
|
impl Parse for DataTablePacket {
|
||||||
fn parse(stream: &mut Stream<'a>, state: &ParserState<'a>) -> Result<Self> {
|
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||||
let tick = stream.read(32)?;
|
let tick = stream.read()?;
|
||||||
let start = stream.pos();
|
let start = stream.pos();
|
||||||
let len = stream.read::<usize>(32)?;
|
let len = stream.read_int::<usize>(32)?;
|
||||||
let mut packet_data = stream.read_bits(len * 8)?;
|
let mut packet_data = stream.read_bits(len * 8)?;
|
||||||
|
|
||||||
let mut tables = vec![];
|
let mut tables = vec![];
|
||||||
while packet_data.read_bool()? {
|
while packet_data.read_bool()? {
|
||||||
let needs_decoder = packet_data.read_bool()?;
|
let needs_decoder = packet_data.read_bool()?;
|
||||||
let name = packet_data.read_string(None)?;
|
let name = packet_data.read_string(None)?;
|
||||||
let prop_count = packet_data.read(10)?;
|
let prop_count = packet_data.read_int(10)?;
|
||||||
|
|
||||||
let mut array_element_prop = None;
|
let mut array_element_prop = None;
|
||||||
let mut props = Vec::with_capacity(prop_count);
|
let mut props = Vec::with_capacity(prop_count);
|
||||||
|
|
||||||
for i in 0..prop_count {
|
for i in 0..prop_count {
|
||||||
let prop: SendPropDefinition = SendPropDefinition::parse(&mut packet_data, state, name.clone())?;
|
let prop: SendPropDefinition =
|
||||||
|
SendPropDefinition::read(&mut packet_data, name.clone())?;
|
||||||
if prop.flags.contains(SendPropFlag::InsideArray) {
|
if prop.flags.contains(SendPropFlag::InsideArray) {
|
||||||
if array_element_prop.is_some() || prop.flags.contains(SendPropFlag::ChangesOften) {
|
if array_element_prop.is_some()
|
||||||
return Err(ParseError::InvalidSendPropArray("Array contents can't have the 'ChangesOften' flag".to_owned()));
|
|| prop.flags.contains(SendPropFlag::ChangesOften)
|
||||||
|
{
|
||||||
|
return Err(ParseError::InvalidSendPropArray(
|
||||||
|
"Array contents can't have the 'ChangesOften' flag".to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
array_element_prop = Some(prop);
|
array_element_prop = Some(prop);
|
||||||
} else if let Some(array_element) = array_element_prop {
|
} else if let Some(array_element) = array_element_prop {
|
||||||
if prop.prop_type != SendPropType::Array {
|
if prop.prop_type != SendPropType::Array {
|
||||||
return Err(ParseError::InvalidSendPropArray("Array contents can without array".to_owned()));
|
return Err(ParseError::InvalidSendPropArray(
|
||||||
|
"Array contents can without array".to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
array_element_prop = None;
|
array_element_prop = None;
|
||||||
props.push(prop.with_array_property(array_element));
|
props.push(prop.with_array_property(array_element));
|
||||||
|
|
@ -68,10 +77,10 @@ impl<'a> Parse<'a> for DataTablePacket {
|
||||||
|
|
||||||
// TODO linked tables?
|
// TODO linked tables?
|
||||||
|
|
||||||
let server_class_count = packet_data.read(16)?;
|
let server_class_count = packet_data.read_int(16)?;
|
||||||
let mut server_classes = Vec::with_capacity(server_class_count);
|
let mut server_classes = Vec::with_capacity(server_class_count);
|
||||||
for i in 0..server_class_count {
|
for i in 0..server_class_count {
|
||||||
let id = packet_data.read(16)?;
|
let id = packet_data.read_int(16)?;
|
||||||
let name = packet_data.read_string(None)?;
|
let name = packet_data.read_string(None)?;
|
||||||
let data_table = packet_data.read_string(None)?;
|
let data_table = packet_data.read_string(None)?;
|
||||||
server_classes.push(ServerClass {
|
server_classes.push(ServerClass {
|
||||||
|
|
@ -91,10 +100,4 @@ impl<'a> Parse<'a> for DataTablePacket {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip(stream: &mut Stream) -> Result<()> {
|
|
||||||
let _ = stream.skip(32)?;
|
|
||||||
let len = stream.read::<usize>(32)?;
|
|
||||||
stream.skip(len * 8).map_err(ParseError::from)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
|
||||||
use crate::demo::vector::Vector;
|
use crate::demo::vector::Vector;
|
||||||
|
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Message;
|
pub struct Message;
|
||||||
|
|
@ -16,10 +16,10 @@ pub struct MessagePacket {
|
||||||
flags: u32, // TODO
|
flags: u32, // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parse<'a> for MessagePacket {
|
impl Parse for MessagePacket {
|
||||||
fn parse(stream: &mut Stream<'a>, state: &ParserState<'a>) -> Result<Self> {
|
fn parse(stream: &mut Stream, state: &ParserState) -> Result<Self> {
|
||||||
let tick = stream.read(32)?;
|
let tick = stream.read_int(32)?;
|
||||||
let flags = stream.read(32)?;
|
let flags = stream.read_int(32)?;
|
||||||
|
|
||||||
let view_origin_1 = Vector::parse(stream, state)?;
|
let view_origin_1 = Vector::parse(stream, state)?;
|
||||||
let view_angle_1 = Vector::parse(stream, state)?;
|
let view_angle_1 = Vector::parse(stream, state)?;
|
||||||
|
|
@ -28,9 +28,9 @@ impl<'a> Parse<'a> for MessagePacket {
|
||||||
let view_angles = (Vector::parse(stream, state)?, view_angle_1);
|
let view_angles = (Vector::parse(stream, state)?, view_angle_1);
|
||||||
let local_view_angles = (Vector::parse(stream, state)?, local_view_angle_1);
|
let local_view_angles = (Vector::parse(stream, state)?, local_view_angle_1);
|
||||||
|
|
||||||
let sequence_in = stream.read(32)?;
|
let sequence_in = stream.read_int(32)?;
|
||||||
let sequence_out = stream.read(32)?;
|
let sequence_out = stream.read_int(32)?;
|
||||||
let length: usize = stream.read(32)?;
|
let length: usize = stream.read_int(32)?;
|
||||||
let mut packet_data = stream.read_bits(length * 8)?;
|
let mut packet_data = stream.read_bits(length * 8)?;
|
||||||
|
|
||||||
let messages = vec![];
|
let messages = vec![];
|
||||||
|
|
@ -56,7 +56,7 @@ impl<'a> Parse<'a> for MessagePacket {
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = stream.skip(32 * 2)?;
|
let _ = stream.skip(32 * 2)?;
|
||||||
let length: usize = stream.read::<usize>(32)?;
|
let length: usize = stream.read_int::<usize>(32)?;
|
||||||
stream.skip(length * 8).map_err(ParseError::from)
|
stream.skip(length * 8).map_err(ParseError::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use bitstream_reader::{BitRead, LittleEndian};
|
||||||
use enum_primitive_derive::Primitive;
|
use enum_primitive_derive::Primitive;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
|
|
||||||
|
|
@ -12,15 +13,15 @@ use self::synctick::SyncTickPacket;
|
||||||
use self::usercmd::UserCmdPacket;
|
use self::usercmd::UserCmdPacket;
|
||||||
|
|
||||||
pub mod consolecmd;
|
pub mod consolecmd;
|
||||||
|
pub mod datatable;
|
||||||
|
pub mod message;
|
||||||
pub mod stop;
|
pub mod stop;
|
||||||
pub mod stringtable;
|
pub mod stringtable;
|
||||||
pub mod synctick;
|
pub mod synctick;
|
||||||
pub mod usercmd;
|
pub mod usercmd;
|
||||||
pub mod datatable;
|
|
||||||
pub mod message;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Packet<'a> {
|
pub enum Packet {
|
||||||
Sigon(MessagePacket),
|
Sigon(MessagePacket),
|
||||||
Message(MessagePacket),
|
Message(MessagePacket),
|
||||||
SyncTick(SyncTickPacket),
|
SyncTick(SyncTickPacket),
|
||||||
|
|
@ -28,10 +29,11 @@ pub enum Packet<'a> {
|
||||||
UserCmd(UserCmdPacket),
|
UserCmd(UserCmdPacket),
|
||||||
DataTables(DataTablePacket),
|
DataTables(DataTablePacket),
|
||||||
Stop(StopPacket),
|
Stop(StopPacket),
|
||||||
StringTables(StringTablePacket<'a>),
|
StringTables(StringTablePacket),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Primitive, Debug)]
|
#[derive(BitRead, Primitive, Debug)]
|
||||||
|
#[discriminant_bits = 8]
|
||||||
pub enum PacketType {
|
pub enum PacketType {
|
||||||
Sigon = 1,
|
Sigon = 1,
|
||||||
Message = 2,
|
Message = 2,
|
||||||
|
|
@ -43,21 +45,9 @@ pub enum PacketType {
|
||||||
StringTables = 8,
|
StringTables = 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse<'_> for PacketType {
|
impl Parse for Packet {
|
||||||
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
fn parse(stream: &mut Stream, state: &ParserState) -> Result<Self> {
|
||||||
let raw = stream.read(8)?;
|
let packet_type = PacketType::read(stream)?;
|
||||||
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<'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 {
|
Ok(match packet_type {
|
||||||
PacketType::Sigon => Packet::Sigon(MessagePacket::parse(stream, state)?),
|
PacketType::Sigon => Packet::Sigon(MessagePacket::parse(stream, state)?),
|
||||||
PacketType::Message => Packet::Message(MessagePacket::parse(stream, state)?),
|
PacketType::Message => Packet::Message(MessagePacket::parse(stream, state)?),
|
||||||
|
|
@ -66,22 +56,9 @@ impl<'a> Parse<'a> for Packet<'a> {
|
||||||
PacketType::UserCmd => Packet::UserCmd(UserCmdPacket::parse(stream, state)?),
|
PacketType::UserCmd => Packet::UserCmd(UserCmdPacket::parse(stream, state)?),
|
||||||
PacketType::DataTables => Packet::DataTables(DataTablePacket::parse(stream, state)?),
|
PacketType::DataTables => Packet::DataTables(DataTablePacket::parse(stream, state)?),
|
||||||
PacketType::Stop => Packet::Stop(StopPacket::parse(stream, state)?),
|
PacketType::Stop => Packet::Stop(StopPacket::parse(stream, state)?),
|
||||||
PacketType::StringTables => Packet::StringTables(StringTablePacket::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))?;
|
|
||||||
dbg!(&packet_type);
|
|
||||||
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,14 +1,12 @@
|
||||||
use crate::{Parse, ParserState, Result, Stream};
|
use bitstream_reader::{BitRead, LittleEndian};
|
||||||
|
|
||||||
|
use crate::{Parse, ParserState, Result, Stream, ReadResult};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StopPacket;
|
pub struct StopPacket;
|
||||||
|
|
||||||
impl<'a> Parse<'a> for StopPacket {
|
impl BitRead<LittleEndian> for StopPacket {
|
||||||
fn parse(_stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
fn read(_stream: &mut Stream) -> ReadResult<Self> {
|
||||||
Ok(StopPacket)
|
Ok(StopPacket)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip(_stream: &mut Stream) -> Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,33 @@
|
||||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
use bitstream_reader::{BitRead, LittleEndian};
|
||||||
|
|
||||||
|
use crate::{Parse, ParseError, ParserState, Result, Stream, ReadResult};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StringTable<'a> {
|
pub struct StringTable {
|
||||||
name: String,
|
name: String,
|
||||||
entries: Vec<StringTableEntry<'a>>,
|
entries: Vec<StringTableEntry>,
|
||||||
max_entries: u32,
|
max_entries: u32,
|
||||||
fixed_userdata_size: Option<u32>,
|
fixed_userdata_size: Option<u32>,
|
||||||
fixed_userdata_size_bits: Option<u32>,
|
fixed_userdata_size_bits: Option<u32>,
|
||||||
client_entries: Option<Vec<StringTableEntry<'a>>>,
|
client_entries: Option<Vec<StringTableEntry>>,
|
||||||
compressed: bool,
|
compressed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StringTable<'a> {
|
impl BitRead<LittleEndian> for StringTable {
|
||||||
fn parse(stream: &mut Stream<'a>) -> Result<Self> {
|
fn read(stream: &mut Stream) -> ReadResult <Self> {
|
||||||
let name = stream.read_string(None)?;
|
let name = stream.read_string(None)?;
|
||||||
let entry_count: u32 = stream.read(16)?;
|
let entry_count: u32 = stream.read_int(16)?;
|
||||||
let mut entries = Vec::with_capacity(entry_count as usize);
|
let mut entries = Vec::with_capacity(entry_count as usize);
|
||||||
for _ in 0..entry_count {
|
for _ in 0..entry_count {
|
||||||
entries.push(StringTableEntry::parse(stream)?);
|
entries.push(StringTableEntry::read(stream)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let client_entries = if stream.read_bool()? {
|
let client_entries = if stream.read_bool()? {
|
||||||
let count = stream.read(16)?;
|
let count = stream.read_int(16)?;
|
||||||
let mut vec = Vec::with_capacity(count);
|
let mut vec = Vec::with_capacity(count);
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
vec.push(StringTableEntry::parse(stream)?);
|
vec.push(StringTableEntry::read(stream)?);
|
||||||
}
|
}
|
||||||
Some(vec)
|
Some(vec)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -44,16 +46,16 @@ impl<'a> StringTable<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StringTableEntry<'a> {
|
pub struct StringTableEntry {
|
||||||
text: String,
|
text: String,
|
||||||
extra_data: Option<Stream<'a>>,
|
extra_data: Option<Stream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StringTableEntry<'a> {
|
impl BitRead<LittleEndian> for StringTableEntry {
|
||||||
fn parse(stream: &mut Stream<'a>) -> Result<Self> {
|
fn read(stream: &mut Stream) -> ReadResult<Self> {
|
||||||
let text = stream.read_string(None)?;
|
let text = stream.read_string(None)?;
|
||||||
let extra_data = if stream.read_bool()? {
|
let extra_data = if stream.read_bool()? {
|
||||||
let byte_len: usize = stream.read(16)?;
|
let byte_len: usize = stream.read_int(16)?;
|
||||||
Some(stream.read_bits(byte_len * 8)?)
|
Some(stream.read_bits(byte_len * 8)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -62,31 +64,36 @@ impl<'a> StringTableEntry<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Debug for StringTableEntry<'a> {
|
impl fmt::Debug for StringTableEntry {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match &self.extra_data {
|
match &self.extra_data {
|
||||||
None => write!(f, "Table Entry: '{}'", self.text),
|
None => write!(f, "Table Entry: '{}'", self.text),
|
||||||
Some(extra_data) => write!(f, "Table Entry: '{}' with {} bits of extra data", self.text, extra_data.bit_len())
|
Some(extra_data) => write!(
|
||||||
|
f,
|
||||||
|
"Table Entry: '{}' with {} bits of extra data",
|
||||||
|
self.text,
|
||||||
|
extra_data.bit_len()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StringTablePacket<'a> {
|
pub struct StringTablePacket {
|
||||||
tick: u32,
|
tick: u32,
|
||||||
tables: Vec<StringTable<'a>>,
|
tables: Vec<StringTable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parse<'a> for StringTablePacket<'a> {
|
impl Parse for StringTablePacket {
|
||||||
fn parse(stream: &mut Stream<'a>, _state: &ParserState<'a>) -> Result<Self> {
|
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||||
let tick = stream.read(32)?;
|
let tick = stream.read_int(32)?;
|
||||||
let start = stream.pos();
|
let start = stream.pos();
|
||||||
let length: usize = stream.read(32)?;
|
let length: usize = stream.read_int(32)?;
|
||||||
let mut packet_data = stream.read_bits(length * 8)?;
|
let mut packet_data = stream.read_bits(length * 8)?;
|
||||||
let count: u32 = packet_data.read(8)?;
|
let count: u32 = packet_data.read_int(8)?;
|
||||||
let mut tables = Vec::with_capacity(count as usize);
|
let mut tables = Vec::with_capacity(count as usize);
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
tables.push(StringTable::parse(&mut packet_data)?);
|
tables.push(StringTable::read(&mut packet_data)?);
|
||||||
}
|
}
|
||||||
if packet_data.bits_left() > 7 {
|
if packet_data.bits_left() > 7 {
|
||||||
Err(ParseError::DataRemaining(packet_data.bits_left()))
|
Err(ParseError::DataRemaining(packet_data.bits_left()))
|
||||||
|
|
@ -94,10 +101,4 @@ impl<'a> Parse<'a> for StringTablePacket<'a> {
|
||||||
Ok(StringTablePacket { tick, tables })
|
Ok(StringTablePacket { tick, tables })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip(stream: &mut Stream) -> Result<()> {
|
|
||||||
let _ = stream.skip(32)?;
|
|
||||||
let length = stream.read::<usize>(32)?;
|
|
||||||
stream.skip(length).map_err(ParseError::from)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,8 @@
|
||||||
|
use bitstream_reader::{BitRead};
|
||||||
|
|
||||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(BitRead, Debug)]
|
||||||
pub struct SyncTickPacket {
|
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)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn skip(stream: &mut Stream) -> Result<()> {
|
|
||||||
stream.skip(32).map_err(ParseError::from)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
use bitstream_reader::{BitRead, LittleEndian};
|
||||||
|
|
||||||
|
use crate::{Parse, ParseError, ParserState, Result, Stream, ReadResult};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UserCmdPacket {
|
pub struct UserCmdPacket {
|
||||||
|
|
@ -6,22 +8,13 @@ pub struct UserCmdPacket {
|
||||||
sequence_out: u32,
|
sequence_out: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parse<'a> for UserCmdPacket {
|
impl BitRead<LittleEndian> for UserCmdPacket {
|
||||||
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
fn read(stream: &mut Stream) -> ReadResult<Self> {
|
||||||
let tick = stream.read(32)?;
|
let tick = stream.read_int(32)?;
|
||||||
let sequence_out = stream.read(32)?;
|
let sequence_out = stream.read_int(32)?;
|
||||||
let len = stream.read::<usize>(32)?;
|
let len = stream.read_int::<usize>(32)?;
|
||||||
let mut _packet_data = stream.read_bits(len * 8)?;
|
let mut _packet_data = stream.read_bits(len * 8)?;
|
||||||
// TODO parse the packet data
|
// TODO parse the packet data
|
||||||
Ok(UserCmdPacket {
|
Ok(UserCmdPacket { tick, sequence_out })
|
||||||
tick,
|
|
||||||
sequence_out
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn skip(stream: &mut Stream) -> Result<()> {
|
|
||||||
let _ = stream.skip(64)?;
|
|
||||||
let len = stream.read::<usize>(32)?;
|
|
||||||
stream.skip(len * 8).map_err(ParseError::from)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use bitstream_reader::ReadError;
|
use bitstream_reader::{ReadError, BitRead, LittleEndian};
|
||||||
|
|
||||||
use crate::demo::header::Header;
|
use crate::demo::header::Header;
|
||||||
use crate::demo::packet::Packet;
|
use crate::demo::packet::Packet;
|
||||||
|
|
@ -16,6 +16,8 @@ pub enum ParseError {
|
||||||
ReadError(ReadError),
|
ReadError(ReadError),
|
||||||
/// Packet identifier is invalid
|
/// Packet identifier is invalid
|
||||||
InvalidPacketType(u8),
|
InvalidPacketType(u8),
|
||||||
|
/// Message identifier is invalid
|
||||||
|
InvalidMessageType(u8),
|
||||||
/// SendProp type is invalid
|
/// SendProp type is invalid
|
||||||
InvalidSendPropType(u8),
|
InvalidSendPropType(u8),
|
||||||
/// Invalid structure found while creating array SendProp
|
/// Invalid structure found while creating array SendProp
|
||||||
|
|
@ -32,29 +34,43 @@ impl From<ReadError> for ParseError {
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, ParseError>;
|
pub type Result<T> = std::result::Result<T, ParseError>;
|
||||||
|
|
||||||
pub trait Parse<'a>: Sized {
|
pub trait Parse: Sized {
|
||||||
fn parse(stream: &mut Stream<'a>, state: &ParserState<'a>) -> Result<Self>;
|
fn parse(stream: &mut Stream, state: &ParserState) -> Result<Self>;
|
||||||
fn skip(stream: &mut Stream) -> Result<()>;
|
fn skip(stream: &mut Stream) -> Result<()> {
|
||||||
|
let _ = Self::parse(stream, &ParserState::new())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DemoParser<'a> {
|
impl<T: BitRead<LittleEndian>> Parse for T {
|
||||||
stream: Stream<'a>,
|
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||||
state: ParserState<'a>,
|
Self::read(stream).map_err(ParseError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DemoParser<'a> {
|
fn skip(stream: &mut Stream) -> Result<()> {
|
||||||
pub fn new(stream: Stream<'a>) -> Self {
|
let _ = Self::parse(stream, &ParserState::new())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DemoParser {
|
||||||
|
stream: Stream,
|
||||||
|
state: ParserState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DemoParser {
|
||||||
|
pub fn new(stream: Stream) -> Self {
|
||||||
DemoParser {
|
DemoParser {
|
||||||
state: ParserState::new(&stream),
|
state: ParserState::new(),
|
||||||
stream,
|
stream,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read<T: Parse<'a>>(&mut self) -> Result<T> {
|
pub fn read<T: Parse>(&mut self) -> Result<T> {
|
||||||
T::parse(&mut self.stream, &self.state)
|
T::parse(&mut self.stream, &self.state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skip<T: Parse<'a>>(&mut self) -> Result<()> {
|
pub fn skip<T: Parse>(&mut self) -> Result<()> {
|
||||||
T::skip(&mut self.stream)
|
T::skip(&mut self.stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,7 +83,7 @@ impl<'a> DemoParser<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_packets(mut self) -> Result<Vec<Stream<'a>>> {
|
pub fn split_packets(mut self) -> Result<Vec<Stream>> {
|
||||||
let _ = self.skip::<Header>()?;
|
let _ = self.skip::<Header>()?;
|
||||||
let mut streams = vec![];
|
let mut streams = vec![];
|
||||||
while self.stream.bits_left() > 7 {
|
while self.stream.bits_left() > 7 {
|
||||||
|
|
@ -80,14 +96,14 @@ impl<'a> DemoParser<'a> {
|
||||||
Ok(streams)
|
Ok(streams)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_demo(mut self) -> Result<(Header, Vec<Packet<'a>>)> {
|
pub fn parse_demo(mut self) -> Result<(Header, Vec<Packet>)> {
|
||||||
let header = self.read::<Header>()?;
|
let header = self.read::<Header>()?;
|
||||||
let mut packets = vec![];
|
let mut packets = vec![];
|
||||||
loop {
|
loop {
|
||||||
let packet = self.read::<Packet>()?;
|
let packet = self.read::<Packet>()?;
|
||||||
match packet {
|
match packet {
|
||||||
Packet::Stop(_) => break,
|
Packet::Stop(_) => break,
|
||||||
packet => packets.push(packet)
|
packet => packets.push(packet),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok((header, packets))
|
Ok((header, packets))
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,20 @@ use crate::demo::sendprop::SendProp;
|
||||||
use crate::Stream;
|
use crate::Stream;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct ParserState<'a> {
|
pub struct ParserState {
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
pub static_baselines: HashMap<u32, StaticBaseline<'a>>,
|
pub static_baselines: HashMap<u32, StaticBaseline>,
|
||||||
pub event_definitions: HashMap<u32, GameEventDefinition>,
|
pub event_definitions: HashMap<u32, GameEventDefinition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StaticBaseline<'a> {
|
pub struct StaticBaseline {
|
||||||
class_id: u32,
|
class_id: u32,
|
||||||
raw: Stream<'a>,
|
raw: Stream,
|
||||||
parsed: Option<Vec<SendProp>>,
|
parsed: Option<Vec<SendProp>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ParserState<'a> {
|
impl ParserState {
|
||||||
pub fn new(_stream: &Stream<'a>) -> Self {
|
pub fn new() -> Self {
|
||||||
ParserState {
|
ParserState {
|
||||||
version: 0,
|
version: 0,
|
||||||
static_baselines: HashMap::new(),
|
static_baselines: HashMap::new(),
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
|
use bitstream_reader::{BitRead, LittleEndian};
|
||||||
use enum_primitive_derive::Primitive;
|
use enum_primitive_derive::Primitive;
|
||||||
use enumflags2::BitFlags;
|
use enumflags2::BitFlags;
|
||||||
use enumflags2_derive::EnumFlags;
|
use enumflags2_derive::EnumFlags;
|
||||||
use num_traits::cast::FromPrimitive;
|
use num_traits::cast::FromPrimitive;
|
||||||
|
|
||||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
|
||||||
|
|
||||||
use super::packet::datatable::SendTable;
|
use super::packet::datatable::SendTable;
|
||||||
use super::vector::{Vector, VectorXY};
|
use super::vector::{Vector, VectorXY};
|
||||||
|
|
@ -12,7 +13,7 @@ use super::vector::{Vector, VectorXY};
|
||||||
pub struct SendPropDefinition {
|
pub struct SendPropDefinition {
|
||||||
pub prop_type: SendPropType,
|
pub prop_type: SendPropType,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub flags: BitFlags<SendPropFlag>,
|
pub flags: SendPropFlags,
|
||||||
pub exclude_dt_name: Option<String>,
|
pub exclude_dt_name: Option<String>,
|
||||||
pub low_value: Option<f32>,
|
pub low_value: Option<f32>,
|
||||||
pub high_value: Option<f32>,
|
pub high_value: Option<f32>,
|
||||||
|
|
@ -25,10 +26,13 @@ pub struct SendPropDefinition {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendPropDefinition {
|
impl SendPropDefinition {
|
||||||
pub fn parse<'a>(stream: &mut Stream<'a>, state: &ParserState<'a>, owner_table_name: String) -> Result<Self> {
|
pub fn read(
|
||||||
let prop_type = SendPropType::parse(stream, state)?;
|
stream: &mut Stream,
|
||||||
|
owner_table_name: String,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let prop_type = SendPropType::read(stream)?;
|
||||||
let name = stream.read_string(None)?;
|
let name = stream.read_string(None)?;
|
||||||
let flags = BitFlags::<SendPropFlag>::parse(stream, state)?;
|
let flags = SendPropFlags::read(stream)?;
|
||||||
let mut exclude_dt_name = None;
|
let mut exclude_dt_name = None;
|
||||||
let mut element_count = None;
|
let mut element_count = None;
|
||||||
let mut low_value = None;
|
let mut low_value = None;
|
||||||
|
|
@ -40,11 +44,11 @@ impl SendPropDefinition {
|
||||||
if flags.contains(SendPropFlag::Exclude) {
|
if flags.contains(SendPropFlag::Exclude) {
|
||||||
exclude_dt_name = Some(stream.read_string(None)?);
|
exclude_dt_name = Some(stream.read_string(None)?);
|
||||||
} else if prop_type == SendPropType::Array {
|
} else if prop_type == SendPropType::Array {
|
||||||
element_count = Some(stream.read(10)?);
|
element_count = Some(stream.read_int(10)?);
|
||||||
} else {
|
} else {
|
||||||
low_value = Some(stream.read_float()?);
|
low_value = Some(stream.read_float()?);
|
||||||
high_value = Some(stream.read_float()?);
|
high_value = Some(stream.read_float()?);
|
||||||
bit_count = Some(stream.read(7)?);
|
bit_count = Some(stream.read_int(7)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let original_bit_count = bit_count;
|
let original_bit_count = bit_count;
|
||||||
|
|
@ -52,7 +56,9 @@ impl SendPropDefinition {
|
||||||
if flags.contains(SendPropFlag::NoScale) {
|
if flags.contains(SendPropFlag::NoScale) {
|
||||||
if prop_type == SendPropType::Float {
|
if prop_type == SendPropType::Float {
|
||||||
bit_count = Some(32);
|
bit_count = Some(32);
|
||||||
} else if prop_type == SendPropType::Vector && !flags.contains(SendPropFlag::NormalVarInt) {
|
} else if prop_type == SendPropType::Vector
|
||||||
|
&& !flags.contains(SendPropFlag::NormalVarInt)
|
||||||
|
{
|
||||||
bit_count = Some(32 * 3);
|
bit_count = Some(32 * 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -91,7 +97,8 @@ impl SendPropDefinition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Primitive, Copy, Clone, PartialEq, Debug)]
|
#[derive(BitRead, Copy, Clone, PartialEq, Debug)]
|
||||||
|
#[discriminant_bits = 5]
|
||||||
pub enum SendPropType {
|
pub enum SendPropType {
|
||||||
Int = 0,
|
Int = 0,
|
||||||
Float = 1,
|
Float = 1,
|
||||||
|
|
@ -103,18 +110,6 @@ pub enum SendPropType {
|
||||||
NumSendPropTypes = 7,
|
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)]
|
#[derive(EnumFlags, Copy, Clone, PartialEq, Debug)]
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
pub enum SendPropFlag {
|
pub enum SendPropFlag {
|
||||||
|
|
@ -177,15 +172,20 @@ pub enum SendPropFlag {
|
||||||
NormalVarInt = 32, //(1 << 5)
|
NormalVarInt = 32, //(1 << 5)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse<'_> for BitFlags<SendPropFlag> {
|
#[derive(Debug, Copy, Clone)]
|
||||||
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
pub struct SendPropFlags(BitFlags<SendPropFlag>);
|
||||||
let raw = stream.read(16)?;
|
|
||||||
// since all 16 bits worth of flags are used there are no invalid flags
|
impl SendPropFlags {
|
||||||
Ok(BitFlags::from_bits_truncate(raw))
|
pub fn contains(self, other: SendPropFlag) -> bool {
|
||||||
|
self.0.contains(other)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip(stream: &mut Stream) -> Result<()> {
|
impl BitRead<LittleEndian> for SendPropFlags {
|
||||||
stream.skip(16).map_err(ParseError::from)
|
fn read(stream: &mut Stream) -> ReadResult<Self> {
|
||||||
|
let raw = stream.read_int(16)?;
|
||||||
|
// since all 16 bits worth of flags are used there are no invalid flags
|
||||||
|
Ok(SendPropFlags(BitFlags::from_bits_truncate(raw)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,16 @@
|
||||||
|
use bitstream_reader::BitRead;
|
||||||
|
|
||||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(BitRead, Debug)]
|
||||||
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 {
|
#[derive(BitRead, Debug)]
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
13
src/lib.rs
Normal file
13
src/lib.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
pub use crate::demo::{
|
||||||
|
parser::{DemoParser, Parse, ParseError, ParserState, Result},
|
||||||
|
Demo, Stream,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use bitstream_reader::Result as ReadResult;
|
||||||
|
|
||||||
|
mod demo;
|
||||||
|
mod state;
|
||||||
|
mod test;
|
||||||
|
|
@ -7,6 +7,11 @@
|
||||||
<sourceFolder url="file://$MODULE_DIR$/examples" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/examples" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/benches" isTestSource="true" />
|
<sourceFolder url="file://$MODULE_DIR$/benches" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/parse_gen/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/parse_gen/examples" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/parse_gen/tests" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/parse_gen/benches" isTestSource="true" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/parse_gen/target" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue