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

feature gate write support, use hash to compare game event definitions

This commit is contained in:
Robin Appelman 2025-07-14 16:05:30 +02:00
commit fbaca025b6
32 changed files with 6168 additions and 4363 deletions

3
.gitignore vendored
View file

@ -12,4 +12,5 @@ dhat.out.*
result result
.direnv .direnv
strings.txt strings.txt
models.txt models.txt
/out.rs

View file

@ -21,6 +21,7 @@ path = "src/bin/main.rs"
[[bin]] [[bin]]
name = "reencode_demo" name = "reencode_demo"
path = "src/bin/reencode.rs" path = "src/bin/reencode.rs"
required-features = ["write"]
[[bin]] [[bin]]
name = "gamestate" name = "gamestate"
@ -84,6 +85,7 @@ log = { version = "0.4.21", features = [] }
schema = ["schemars", "bitbuffer/schemars"] schema = ["schemars", "bitbuffer/schemars"]
trace = ["tracing", "tracing-subscriber"] trace = ["tracing", "tracing-subscriber"]
codegen = ["better-panic", "quote", "syn", "Inflector", "proc-macro2", "tempfile", "lazy_static", "prettyplease"] codegen = ["better-panic", "quote", "syn", "Inflector", "proc-macro2", "tempfile", "lazy_static", "prettyplease"]
write = []
[dev-dependencies] [dev-dependencies]
pretty_assertions = "1.4.0" pretty_assertions = "1.4.0"

View file

@ -234,6 +234,7 @@ pub fn generate_game_events(demo: Demo) -> TokenStream {
use bitbuffer::{BitRead, LittleEndian, BitWrite, BitWriteStream}; use bitbuffer::{BitRead, LittleEndian, BitWrite, BitWriteStream};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::demo::data::MaybeUtf8String; use crate::demo::data::MaybeUtf8String;
use std::mem::size_of;
); );
let event_definitions = events.iter().map(|event| { let event_definitions = events.iter().map(|event| {
@ -245,24 +246,24 @@ pub fn generate_game_events(demo: Demo) -> TokenStream {
}); });
let field_getters = event.entries.iter().map(|entry| { let field_getters = event.entries.iter().map(|entry| {
let raw_name = &entry.name; let name_hash = entry.hash;
let name = get_entry_name(&entry.name); let name = get_entry_name(&entry.name);
let ident = Ident::new(name.as_str(), span); let ident = Ident::new(name.as_str(), span);
quote!(#raw_name => Ok(self.#ident.clone().into())) quote!(#name_hash => Ok(self.#ident.clone().into()))
}); });
let event_name = get_event_name(event.event_type.as_str()); let event_name = get_event_name(event.event_type.as_str());
let name = Ident::new(&format!("{event_name}Event"), span); let name = Ident::new(&format!("{event_name}Event"), span);
let entry_readers = event.entries.iter().map(|entry| { let entry_readers = event.entries.iter().map(|entry| {
let raw_name = &entry.name; let name_hash = entry.hash;
let name_str = get_entry_name(&entry.name); let name_str = get_entry_name(&entry.name);
let name = Ident::new(&name_str, span); let name = Ident::new(&name_str, span);
let ty = Ident::new(get_type_name(entry.kind), span); let ty = Ident::new(get_type_name(entry.kind), span);
quote!( quote!(
#name: read_value::<#ty>(stream, definition.get_entry(#raw_name), #name_str)?, #name: read_value::<#ty>(stream, definition.get_entry(#name_hash), #name_str)?,
) )
}); });
@ -282,13 +283,13 @@ pub fn generate_game_events(demo: Demo) -> TokenStream {
} }
#[allow(unused_variables)] #[allow(unused_variables)]
fn get_field(&self, field: &str) -> Result<GameEventValue> { fn get_field(&self, field: &GameEventEntry) -> Result<GameEventValue> {
#[allow(clippy::clone_on_copy, clippy::match_single_binding)] #[allow(clippy::clone_on_copy, clippy::match_single_binding)]
match field { match field.hash {
#(#field_getters,)* #(#field_getters,)*
_ => Err(ParseError::MissingGameEventValue { _ => Err(ParseError::MissingGameEventValue {
ty: #event_name, ty: #event_name,
field: field.into(), field: "todo".into(),
}), }),
} }
} }
@ -296,7 +297,7 @@ pub fn generate_game_events(demo: Demo) -> TokenStream {
#[allow(unused_variables)] #[allow(unused_variables)]
fn write(&self, stream: &mut BitWriteStream<LittleEndian>, definition: &GameEventDefinition) -> Result<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>, definition: &GameEventDefinition) -> Result<()> {
for entry in &definition.entries { for entry in &definition.entries {
let value = self.get_field(&entry.name).unwrap_or_else(|_| entry.kind.default_value()); let value = self.get_field(&entry).unwrap_or_else(|_| entry.kind.default_value());
stream.write(&value)?; stream.write(&value)?;
} }
Ok(()) Ok(())
@ -383,7 +384,7 @@ pub fn generate_game_events(demo: Demo) -> TokenStream {
let struct_name = Ident::new(&format!("{name}Event"), span); let struct_name = Ident::new(&format!("{name}Event"), span);
quote!( quote!(
(#name, std::mem::size_of::<#struct_name>()) (#name, size_of::<#struct_name>())
) )
}); });

File diff suppressed because it is too large Load diff

View file

@ -3,10 +3,10 @@ use crate::demo::data::MaybeUtf8String;
use crate::demo::message::gameevent::GameEventTypeId; use crate::demo::message::gameevent::GameEventTypeId;
use crate::{GameEventError, Result, Stream}; use crate::{GameEventError, Result, Stream};
use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian}; use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian};
use const_fnv1a_hash::fnv1a_hash_str_64;
use parse_display::Display; use parse_display::Display;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::cmp::Ordering; use std::cmp::Ordering;
use const_fnv1a_hash::fnv1a_hash_str_64;
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -17,8 +17,7 @@ pub struct GameEventDefinition {
} }
impl GameEventDefinition { impl GameEventDefinition {
pub fn get_entry(&self, name: &str) -> Option<&GameEventEntry> { pub fn get_entry(&self, hash: u64) -> Option<&GameEventEntry> {
let hash = fnv1a_hash_str_64(name);
self.entries.iter().find(|entry| entry.hash == hash) self.entries.iter().find(|entry| entry.hash == hash)
} }
} }
@ -46,17 +45,20 @@ impl Ord for GameEventDefinition {
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct GameEventEntry { pub struct GameEventEntry {
#[cfg(any(feature = "codegen", feature = "write"))]
pub name: String, pub name: String,
pub hash: u64, pub hash: u64,
pub kind: GameEventValueType, pub kind: GameEventValueType,
} }
impl GameEventEntry { impl GameEventEntry {
pub fn new<S: Into<String>>(name: S, kind: GameEventValueType) -> Self { pub fn new<S: AsRef<str>>(name: S, kind: GameEventValueType) -> Self {
let name = name.into(); let name = name.as_ref();
let hash = fnv1a_hash_str_64(name);
GameEventEntry { GameEventEntry {
hash: fnv1a_hash_str_64(&name), #[cfg(any(feature = "codegen", feature = "write"))]
name: name.into(), name: name.into(),
hash,
kind, kind,
} }
} }

View file

@ -1,7 +1,11 @@
use crate::demo::sendprop::{read_bit_coord, write_bit_coord}; use crate::demo::sendprop::read_bit_coord;
#[cfg(feature = "write")]
use crate::demo::sendprop::write_bit_coord;
use crate::demo::vector::Vector; use crate::demo::vector::Vector;
use crate::{ReadResult, Stream}; use crate::{ReadResult, Stream};
use bitbuffer::{BitRead, BitWrite, BitWriteSized, BitWriteStream, LittleEndian}; use bitbuffer::{BitRead, LittleEndian};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteSized, BitWriteStream};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
@ -44,6 +48,7 @@ impl BitRead<'_, LittleEndian> for BSPDecalMessage {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for BSPDecalMessage { impl BitWrite<LittleEndian> for BSPDecalMessage {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
let has_x = self.position.x != 0.0; let has_x = self.position.x != 0.0;
@ -75,6 +80,7 @@ impl BitWrite<LittleEndian> for BSPDecalMessage {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_decal_roundtrip() { fn test_decal_roundtrip() {
crate::test_roundtrip_write(BSPDecalMessage { crate::test_roundtrip_write(BSPDecalMessage {
position: Vector::default(), position: Vector::default(),

View file

@ -1,4 +1,6 @@
use bitbuffer::{BitRead, BitReadSized, BitWrite, BitWriteSized, BitWriteStream, LittleEndian}; use bitbuffer::{BitRead, BitReadSized, LittleEndian};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteSized, BitWriteStream};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::demo::message::stringtable::log_base2; use crate::demo::message::stringtable::log_base2;
@ -6,7 +8,8 @@ use crate::{ReadResult, Stream};
use std::cmp::min; use std::cmp::min;
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitReadSized, BitWriteSized, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitReadSized, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWriteSized))]
pub struct ClassInfoEntry { pub struct ClassInfoEntry {
#[size = "input_size"] #[size = "input_size"]
class_id: u16, class_id: u16,
@ -45,6 +48,7 @@ impl BitRead<'_, LittleEndian> for ClassInfoMessage {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for ClassInfoMessage { impl BitWrite<LittleEndian> for ClassInfoMessage {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.count.write(stream)?; self.count.write(stream)?;
@ -61,6 +65,7 @@ impl BitWrite<LittleEndian> for ClassInfoMessage {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_class_info_roundtrip() { fn test_class_info_roundtrip() {
crate::test_roundtrip_write(ClassInfoMessage { crate::test_roundtrip_write(ClassInfoMessage {
count: 8, count: 8,

View file

@ -1,4 +1,6 @@
use bitbuffer::{BitRead, BitWrite, BitWriteSized, BitWriteStream, LittleEndian}; use bitbuffer::{BitRead, LittleEndian};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteSized, BitWriteStream};
use parse_display::Display; use parse_display::Display;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::borrow::Cow; use std::borrow::Cow;
@ -7,7 +9,9 @@ use crate::demo::gameevent_gen::GameEventType;
use crate::demo::gamevent::{ use crate::demo::gamevent::{
GameEvent, GameEventDefinition, GameEventEntry, GameEventValueType, RawGameEvent, GameEvent, GameEventDefinition, GameEventEntry, GameEventValueType, RawGameEvent,
}; };
use crate::demo::parser::{Encode, ParseBitSkip}; #[cfg(feature = "write")]
use crate::demo::parser::Encode;
use crate::demo::parser::ParseBitSkip;
use crate::{GameEventError, Parse, ParseError, ParserState, ReadResult, Result, Stream}; use crate::{GameEventError, Parse, ParseError, ParserState, ReadResult, Result, Stream};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
@ -52,6 +56,7 @@ impl Parse<'_> for GameEventMessage {
} }
} }
#[cfg(feature = "write")]
impl Encode for GameEventMessage { impl Encode for GameEventMessage {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> { fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
let definition = state let definition = state
@ -68,6 +73,7 @@ impl Encode for GameEventMessage {
} }
} }
#[cfg(feature = "write")]
#[test] #[test]
fn test_game_event_roundtrip() { fn test_game_event_roundtrip() {
use crate::demo::gameevent_gen::{GameInitEvent, ServerShutdownEvent}; use crate::demo::gameevent_gen::{GameInitEvent, ServerShutdownEvent};
@ -125,7 +131,6 @@ impl ParseBitSkip<'_> for GameEventMessage {
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive( #[derive(
BitRead, BitRead,
BitWrite,
Debug, Debug,
Clone, Clone,
Copy, Copy,
@ -138,6 +143,7 @@ impl ParseBitSkip<'_> for GameEventMessage {
Serialize, Serialize,
Deserialize, Deserialize,
)] )]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct GameEventTypeId(#[size = 9] u16); pub struct GameEventTypeId(#[size = 9] u16);
impl From<GameEventTypeId> for usize { impl From<GameEventTypeId> for usize {
@ -179,6 +185,7 @@ impl BitRead<'_, LittleEndian> for GameEventDefinition {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for GameEventDefinition { impl BitWrite<LittleEndian> for GameEventDefinition {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.id.write(stream)?; self.id.write(stream)?;
@ -198,6 +205,7 @@ impl BitWrite<LittleEndian> for GameEventDefinition {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_event_definition_roundtrip() { fn test_event_definition_roundtrip() {
crate::test_roundtrip_write(GameEventDefinition { crate::test_roundtrip_write(GameEventDefinition {
id: GameEventTypeId(0), id: GameEventTypeId(0),
@ -220,6 +228,7 @@ impl BitRead<'_, LittleEndian> for GameEventListMessage {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for GameEventListMessage { impl BitWrite<LittleEndian> for GameEventListMessage {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
(self.event_list.len() as u16).write_sized(stream, 9)?; (self.event_list.len() as u16).write_sized(stream, 9)?;
@ -233,13 +242,17 @@ impl BitWrite<LittleEndian> for GameEventListMessage {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_event_list_roundtrip() { fn test_event_list_roundtrip() {
crate::test_roundtrip_write(GameEventListMessage { event_list: vec![] }); crate::test_roundtrip_write(GameEventListMessage { event_list: vec![] });
crate::test_roundtrip_write(GameEventListMessage { crate::test_roundtrip_write(GameEventListMessage {
event_list: vec![GameEventDefinition { event_list: vec![GameEventDefinition {
id: GameEventTypeId(0), id: GameEventTypeId(0),
event_type: GameEventType::ServerChangeLevelFailed, event_type: GameEventType::ServerChangeLevelFailed,
entries: vec![GameEventEntry::new("level_name", GameEventValueType::String)], entries: vec![GameEventEntry::new(
"level_name",
GameEventValueType::String,
)],
}], }],
}); });
crate::test_roundtrip_write(GameEventListMessage { crate::test_roundtrip_write(GameEventListMessage {

View file

@ -1,11 +1,14 @@
/// Messages that consists only of primitives and string and can be derived /// Messages that consists only of primitives and string and can be derived
use crate::demo::data::{MaybeUtf8String, ServerTick}; use crate::demo::data::{MaybeUtf8String, ServerTick};
use crate::Stream; use crate::Stream;
use bitbuffer::{BitRead, BitWrite, LittleEndian}; #[cfg(feature = "write")]
use bitbuffer::BitWrite;
use bitbuffer::{BitRead, LittleEndian};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct FileMessage { pub struct FileMessage {
pub transfer_id: u32, pub transfer_id: u32,
pub file_name: String, pub file_name: String,
@ -13,7 +16,8 @@ pub struct FileMessage {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct NetTickMessage { pub struct NetTickMessage {
pub tick: ServerTick, pub tick: ServerTick,
pub frame_time: u16, pub frame_time: u16,
@ -21,13 +25,15 @@ pub struct NetTickMessage {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct StringCmdMessage { pub struct StringCmdMessage {
pub command: String, pub command: String,
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
#[discriminant_bits = 8] #[discriminant_bits = 8]
pub enum SignOnState { pub enum SignOnState {
None = 0, None = 0,
@ -41,33 +47,38 @@ pub enum SignOnState {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct SignOnStateMessage { pub struct SignOnStateMessage {
pub state: SignOnState, pub state: SignOnState,
pub count: u32, pub count: u32,
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct PrintMessage { pub struct PrintMessage {
pub value: MaybeUtf8String, pub value: MaybeUtf8String,
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct SetPauseMessage { pub struct SetPauseMessage {
pub pause: bool, pub pause: bool,
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct SetViewMessage { pub struct SetViewMessage {
#[size = 11] #[size = 11]
pub index: u16, pub index: u16,
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct FixAngleMessage { pub struct FixAngleMessage {
pub relative: bool, pub relative: bool,
pub x: u16, pub x: u16,
@ -76,7 +87,8 @@ pub struct FixAngleMessage {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
#[endianness = "LittleEndian"] #[endianness = "LittleEndian"]
#[serde(bound(deserialize = "'a: 'static"))] #[serde(bound(deserialize = "'a: 'static"))]
pub struct EntityMessage<'a> { pub struct EntityMessage<'a> {
@ -91,7 +103,8 @@ pub struct EntityMessage<'a> {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
#[endianness = "LittleEndian"] #[endianness = "LittleEndian"]
#[serde(bound(deserialize = "'a: 'static"))] #[serde(bound(deserialize = "'a: 'static"))]
pub struct MenuMessage<'a> { pub struct MenuMessage<'a> {
@ -102,14 +115,16 @@ pub struct MenuMessage<'a> {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct GetCvarValueMessage { pub struct GetCvarValueMessage {
pub cookie: u32, pub cookie: u32,
pub value: String, pub value: String,
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
#[endianness = "LittleEndian"] #[endianness = "LittleEndian"]
#[serde(bound(deserialize = "'a: 'static"))] #[serde(bound(deserialize = "'a: 'static"))]
pub struct CmdKeyValuesMessage<'a> { pub struct CmdKeyValuesMessage<'a> {

View file

@ -11,9 +11,13 @@ pub use crate::demo::message::stringtable::*;
pub use crate::demo::message::tempentities::*; pub use crate::demo::message::tempentities::*;
pub use crate::demo::message::usermessage::*; pub use crate::demo::message::usermessage::*;
pub use crate::demo::message::voice::*; pub use crate::demo::message::voice::*;
use crate::demo::parser::{Encode, ParseBitSkip}; #[cfg(feature = "write")]
use crate::demo::parser::Encode;
use crate::demo::parser::ParseBitSkip;
use crate::{Parse, ParserState, Result, Stream}; use crate::{Parse, ParserState, Result, Stream};
use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian}; use bitbuffer::BitRead;
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteStream, LittleEndian};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
@ -31,9 +35,8 @@ pub mod usermessage;
pub mod voice; pub mod voice;
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema_repr))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema_repr))]
#[derive( #[derive(BitRead, Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
BitRead, BitWrite, Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr, #[cfg_attr(feature = "write", derive(BitWrite))]
)]
#[repr(u8)] #[repr(u8)]
#[discriminant_bits = 6] #[discriminant_bits = 6]
pub enum MessageType { pub enum MessageType {
@ -240,6 +243,7 @@ impl<'a> Message<'a> {
} }
} }
#[cfg(feature = "write")]
impl Encode for Message<'_> { impl Encode for Message<'_> {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> { fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
match self { match self {

View file

@ -1,13 +1,14 @@
use bitbuffer::{ use bitbuffer::{BitRead, BitReadSized, BitReadStream, Endianness, LittleEndian};
BitRead, BitReadSized, BitReadStream, BitWrite, BitWriteSized, BitWriteStream, Endianness, #[cfg(feature = "write")]
LittleEndian, use bitbuffer::{BitWrite, BitWriteSized, BitWriteStream};
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
use std::borrow::Cow; use std::borrow::Cow;
use crate::demo::packet::datatable::{ClassId, SendTable}; use crate::demo::packet::datatable::{ClassId, SendTable};
use crate::demo::parser::{Encode, ParseBitSkip}; #[cfg(feature = "write")]
use crate::demo::parser::Encode;
use crate::demo::parser::ParseBitSkip;
use crate::demo::sendprop::{SendProp, SendPropIdentifier, SendPropValue}; use crate::demo::sendprop::{SendProp, SendPropIdentifier, SendPropValue};
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream}; use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use parse_display::{Display, FromStr}; use parse_display::{Display, FromStr};
@ -75,9 +76,8 @@ impl PartialOrd<u32> for EntityId {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema_repr))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema_repr))]
#[derive( #[derive(BitRead, Clone, Copy, Debug, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
BitRead, BitWrite, Clone, Copy, Debug, PartialEq, Eq, Serialize_repr, Deserialize_repr, #[cfg_attr(feature = "write", derive(BitWrite))]
)]
#[discriminant_bits = 2] #[discriminant_bits = 2]
#[repr(u8)] #[repr(u8)]
pub enum UpdateType { pub enum UpdateType {
@ -128,6 +128,7 @@ impl<E: Endianness> BitRead<'_, E> for BaselineIndex {
} }
} }
#[cfg(feature = "write")]
impl<E: Endianness> BitWrite<E> for BaselineIndex { impl<E: Endianness> BitWrite<E> for BaselineIndex {
fn write(&self, stream: &mut BitWriteStream<E>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<E>) -> ReadResult<()> {
let val = match self { let val = match self {
@ -256,6 +257,7 @@ fn read_bit_var<'a, T: BitReadSized<'a, LittleEndian>>(stream: &mut Stream<'a>)
stream.read_sized(bits) stream.read_sized(bits)
} }
#[cfg(feature = "write")]
fn write_bit_var(var: u32, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write_bit_var(var: u32, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
let (ty, bits): (u8, usize) = if var >= 2u32.pow(12) { let (ty, bits): (u8, usize) = if var >= 2u32.pow(12) {
(3, 32) (3, 32)
@ -272,6 +274,7 @@ fn write_bit_var(var: u32, stream: &mut BitWriteStream<LittleEndian>) -> ReadRes
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_bit_var_roundtrip() { fn test_bit_var_roundtrip() {
use bitbuffer::{BitReadBuffer, BitReadStream}; use bitbuffer::{BitReadBuffer, BitReadStream};
@ -436,6 +439,7 @@ impl Parse<'_> for PacketEntitiesMessage {
} }
} }
#[cfg(feature = "write")]
impl Encode for PacketEntitiesMessage { impl Encode for PacketEntitiesMessage {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> { fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
self.max_entries.write_sized(stream, 11)?; self.max_entries.write_sized(stream, 11)?;
@ -520,6 +524,7 @@ impl PacketEntitiesMessage {
}) })
} }
#[cfg(feature = "write")]
fn write_enter( fn write_enter(
entity: &PacketEntity, entity: &PacketEntity,
stream: &mut BitWriteStream<LittleEndian>, stream: &mut BitWriteStream<LittleEndian>,
@ -579,6 +584,7 @@ impl PacketEntitiesMessage {
Ok(()) Ok(())
} }
#[cfg(feature = "write")]
pub fn write_update<'a, Props: IntoIterator<Item = &'a SendProp>>( pub fn write_update<'a, Props: IntoIterator<Item = &'a SendProp>>(
props: Props, props: Props,
stream: &mut BitWriteStream<LittleEndian>, stream: &mut BitWriteStream<LittleEndian>,
@ -628,6 +634,7 @@ impl ParseBitSkip<'_> for PacketEntitiesMessage {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_packet_entity_message_roundtrip() { fn test_packet_entity_message_roundtrip() {
use crate::demo::packet::datatable::{SendTable, SendTableName, ServerClass, ServerClassName}; use crate::demo::packet::datatable::{SendTable, SendTableName, ServerClass, ServerClassName};
use crate::demo::sendprop::{FloatDefinition, SendPropDefinition, SendPropParseDefinition}; use crate::demo::sendprop::{FloatDefinition, SendPropDefinition, SendPropParseDefinition};

View file

@ -1,5 +1,8 @@
use crate::demo::parser::{Encode, ParseBitSkip}; #[cfg(feature = "write")]
use crate::demo::parser::Encode;
use crate::demo::parser::ParseBitSkip;
use crate::{Parse, ParserState, Result, Stream}; use crate::{Parse, ParserState, Result, Stream};
#[cfg(feature = "write")]
use bitbuffer::{BitWriteStream, LittleEndian}; use bitbuffer::{BitWriteStream, LittleEndian};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -28,6 +31,7 @@ impl<'a> Parse<'a> for PreFetchMessage {
} }
} }
#[cfg(feature = "write")]
impl Encode for PreFetchMessage { impl Encode for PreFetchMessage {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> { fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
let size = Self::bit_size(state.protocol_version); let size = Self::bit_size(state.protocol_version);

View file

@ -1,6 +1,10 @@
use crate::demo::parser::{Encode, ParseBitSkip}; #[cfg(feature = "write")]
use crate::demo::parser::Encode;
use crate::demo::parser::ParseBitSkip;
use crate::{Parse, ParserState, Result, Stream}; use crate::{Parse, ParserState, Result, Stream};
use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian}; use bitbuffer::{BitRead, LittleEndian};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteStream};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
@ -78,6 +82,7 @@ impl<'a> ParseBitSkip<'a> for ServerInfoMessage {
} }
} }
#[cfg(feature = "write")]
impl Encode for ServerInfoMessage { impl Encode for ServerInfoMessage {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> { fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
let part1 = ServerInfoMessagePart1 { let part1 = ServerInfoMessagePart1 {
@ -118,7 +123,8 @@ impl Encode for ServerInfoMessage {
} }
} }
#[derive(BitRead, BitWrite)] #[derive(BitRead)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct ServerInfoMessagePart1 { pub struct ServerInfoMessagePart1 {
pub version: u16, pub version: u16,
pub server_count: u32, pub server_count: u32,
@ -128,7 +134,8 @@ pub struct ServerInfoMessagePart1 {
pub max_classes: u16, pub max_classes: u16,
} }
#[derive(BitRead, BitWrite)] #[derive(BitRead)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct ServerInfoMessagePart2 { pub struct ServerInfoMessagePart2 {
pub player_slot: u8, pub player_slot: u8,
pub max_player_count: u8, pub max_player_count: u8,

View file

@ -1,10 +1,13 @@
use bitbuffer::{BitRead, BitReadStream, BitWrite, BitWriteStream, Endianness}; use bitbuffer::{BitRead, BitReadStream, Endianness};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteStream};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::ReadResult; use crate::ReadResult;
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, BitWrite, PartialEq, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct ConVar { pub struct ConVar {
pub key: String, pub key: String,
pub value: String, pub value: String,
@ -30,6 +33,7 @@ pub struct SetConVarMessage {
pub vars: Vec<ConVar>, pub vars: Vec<ConVar>,
} }
#[cfg(feature = "write")]
impl<E: Endianness> BitWrite<E> for SetConVarMessage { impl<E: Endianness> BitWrite<E> for SetConVarMessage {
fn write(&self, stream: &mut BitWriteStream<E>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<E>) -> ReadResult<()> {
self.length.write(stream)?; self.length.write(stream)?;
@ -37,6 +41,7 @@ impl<E: Endianness> BitWrite<E> for SetConVarMessage {
} }
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_set_con_var_roundtrip() { fn test_set_con_var_roundtrip() {
crate::test_roundtrip_write(SetConVarMessage { crate::test_roundtrip_write(SetConVarMessage {
length: 0, length: 0,

View file

@ -1,6 +1,6 @@
use bitbuffer::{ #[cfg(feature = "write")]
BitError, BitReadBuffer, BitReadStream, BitWrite, BitWriteSized, BitWriteStream, LittleEndian, use bitbuffer::{BitError, BitWrite, BitWriteSized, BitWriteStream};
}; use bitbuffer::{BitReadBuffer, BitReadStream, LittleEndian};
use num_traits::{PrimInt, Unsigned}; use num_traits::{PrimInt, Unsigned};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use snap::raw::{decompress_len, Decoder}; use snap::raw::{decompress_len, Decoder};
@ -9,7 +9,9 @@ use crate::demo::lzss::decompress;
use crate::demo::packet::stringtable::{ use crate::demo::packet::stringtable::{
ExtraData, FixedUserDataSize, StringTable, StringTableEntry, ExtraData, FixedUserDataSize, StringTable, StringTableEntry,
}; };
use crate::demo::parser::{Encode, ParseBitSkip}; #[cfg(feature = "write")]
use crate::demo::parser::Encode;
use crate::demo::parser::ParseBitSkip;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream}; use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use std::borrow::Cow; use std::borrow::Cow;
use std::cmp::min; use std::cmp::min;
@ -157,6 +159,7 @@ impl<'a> ParseBitSkip<'a> for CreateStringTableMessage<'a> {
} }
} }
#[cfg(feature = "write")]
impl Encode for CreateStringTableMessage<'_> { impl Encode for CreateStringTableMessage<'_> {
fn encode( fn encode(
&self, &self,
@ -193,6 +196,7 @@ impl Encode for CreateStringTableMessage<'_> {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_create_string_table_roundtrip() { fn test_create_string_table_roundtrip() {
let state = ParserState::new(24, |_| false, false); let state = ParserState::new(24, |_| false, false);
crate::test_roundtrip_encode( crate::test_roundtrip_encode(
@ -274,6 +278,7 @@ impl<'a> ParseBitSkip<'a> for UpdateStringTableMessage<'a> {
} }
} }
#[cfg(feature = "write")]
impl Encode for UpdateStringTableMessage<'_> { impl Encode for UpdateStringTableMessage<'_> {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> { fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
self.table_id.write_sized(stream, 5)?; self.table_id.write_sized(stream, 5)?;
@ -294,6 +299,7 @@ impl Encode for UpdateStringTableMessage<'_> {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_update_string_table_roundtrip() { fn test_update_string_table_roundtrip() {
let mut state = ParserState::new(24, |_| false, false); let mut state = ParserState::new(24, |_| false, false);
state.string_tables = vec![StringTableMeta { state.string_tables = vec![StringTableMeta {
@ -377,6 +383,7 @@ impl<'a> TableEntries<'a> {
self.entries self.entries
} }
#[cfg(feature = "write")]
pub fn find_best_history(&self, text: &str) -> Option<(usize, usize)> { pub fn find_best_history(&self, text: &str) -> Option<(usize, usize)> {
let mut best_index = None; let mut best_index = None;
let mut best_count = 0; let mut best_count = 0;
@ -394,6 +401,7 @@ impl<'a> TableEntries<'a> {
} }
} }
#[cfg(feature = "write")]
fn count_similar_characters(a: &str, b: &str) -> usize { fn count_similar_characters(a: &str, b: &str) -> usize {
for (i, (a, b)) in a.bytes().zip(b.bytes()).enumerate() { for (i, (a, b)) in a.bytes().zip(b.bytes()).enumerate() {
if a != b { if a != b {
@ -429,6 +437,7 @@ pub fn parse_string_table_update<'a>(
Ok(entries.into_entries()) Ok(entries.into_entries())
} }
#[cfg(feature = "write")]
pub fn write_string_table_update( pub fn write_string_table_update(
entries: &[(u16, StringTableEntry)], entries: &[(u16, StringTableEntry)],
stream: &mut BitWriteStream<LittleEndian>, stream: &mut BitWriteStream<LittleEndian>,
@ -457,6 +466,7 @@ pub fn write_string_table_update(
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_table_update_roundtrip() { fn test_table_update_roundtrip() {
fn entry_roundtrip( fn entry_roundtrip(
entries: Vec<(u16, StringTableEntry)>, entries: Vec<(u16, StringTableEntry)>,
@ -601,6 +611,7 @@ fn read_table_entry<'a>(
Ok(StringTableEntry { text, extra_data }) Ok(StringTableEntry { text, extra_data })
} }
#[cfg(feature = "write")]
fn write_table_entry( fn write_table_entry(
entry: &StringTableEntry, entry: &StringTableEntry,
stream: &mut BitWriteStream<LittleEndian>, stream: &mut BitWriteStream<LittleEndian>,
@ -647,6 +658,7 @@ fn write_table_entry(
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_table_entry_roundtrip() { fn test_table_entry_roundtrip() {
fn entry_roundtrip(entry: StringTableEntry, fixed_bits: Option<u8>) { fn entry_roundtrip(entry: StringTableEntry, fixed_bits: Option<u8>) {
let table_meta = StringTableMeta { let table_meta = StringTableMeta {
@ -723,6 +735,7 @@ pub fn read_var_int(stream: &mut Stream) -> ReadResult<u32> {
Ok(result) Ok(result)
} }
#[cfg(feature = "write")]
pub fn write_var_int(mut int: u32, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { pub fn write_var_int(mut int: u32, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
while int > 0x7F { while int > 0x7F {
let byte: u8 = int as u8 & 0x7F; let byte: u8 = int as u8 & 0x7F;
@ -734,6 +747,7 @@ pub fn write_var_int(mut int: u32, stream: &mut BitWriteStream<LittleEndian>) ->
// encode the int in such a way that it has a fixed size, but still decodes the same // encode the int in such a way that it has a fixed size, but still decodes the same
// result is the first 40 bits of the return value // result is the first 40 bits of the return value
#[cfg(feature = "write")]
pub fn encode_var_int_fixed(mut int: u32) -> u64 { pub fn encode_var_int_fixed(mut int: u32) -> u64 {
let mut out = 0; let mut out = 0;
for i in 0..4 { for i in 0..4 {
@ -746,6 +760,7 @@ pub fn encode_var_int_fixed(mut int: u32) -> u64 {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_var_int_roundtrip() { fn test_var_int_roundtrip() {
fn var_int_roundtrip(int: u32) { fn var_int_roundtrip(int: u32) {
let mut data = Vec::new(); let mut data = Vec::new();
@ -768,6 +783,7 @@ fn test_var_int_roundtrip() {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_var_int_fixed_roundtrip() { fn test_var_int_fixed_roundtrip() {
fn var_int_roundtrip(int: u32) { fn var_int_roundtrip(int: u32) {
let mut data = Vec::new(); let mut data = Vec::new();

View file

@ -1,11 +1,15 @@
use super::stringtable::read_var_int; use super::stringtable::read_var_int;
use crate::demo::message::packetentities::PacketEntitiesMessage; use crate::demo::message::packetentities::PacketEntitiesMessage;
use crate::demo::message::stringtable::{encode_var_int_fixed}; #[cfg(feature = "write")]
use crate::demo::message::stringtable::encode_var_int_fixed;
use crate::demo::packet::datatable::ClassId; use crate::demo::packet::datatable::ClassId;
use crate::demo::parser::{Encode, ParseBitSkip}; #[cfg(feature = "write")]
use crate::demo::parser::Encode;
use crate::demo::parser::ParseBitSkip;
use crate::demo::sendprop::SendProp; use crate::demo::sendprop::SendProp;
use crate::Result; use crate::Result;
use crate::{Parse, ParseError, ParserState, Stream}; use crate::{Parse, ParseError, ParserState, Stream};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteSized, BitWriteStream, LittleEndian}; use bitbuffer::{BitWrite, BitWriteSized, BitWriteStream, LittleEndian};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -95,6 +99,7 @@ impl ParseBitSkip<'_> for TempEntitiesMessage {
} }
} }
#[cfg(feature = "write")]
impl Encode for TempEntitiesMessage { impl Encode for TempEntitiesMessage {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> { fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
let count = match (self.events.len(), self.events.first()) { let count = match (self.events.len(), self.events.first()) {

View file

@ -1,4 +1,6 @@
use bitbuffer::{BitError, BitRead, BitWrite, BitWriteStream, Endianness, LittleEndian}; use bitbuffer::{BitError, BitRead, LittleEndian};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteStream, Endianness};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::demo::data::MaybeUtf8String; use crate::demo::data::MaybeUtf8String;
@ -6,7 +8,8 @@ use crate::demo::message::packetentities::EntityId;
use crate::{ReadResult, Stream}; use crate::{ReadResult, Stream};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(BitRead, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
#[repr(u8)] #[repr(u8)]
#[discriminant_bits = 8] #[discriminant_bits = 8]
pub enum UserMessageType { pub enum UserMessageType {
@ -157,6 +160,7 @@ impl<'a> BitRead<'a, LittleEndian> for UserMessage<'a> {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for UserMessage<'_> { impl BitWrite<LittleEndian> for UserMessage<'_> {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.message_type().write(stream)?; self.message_type().write(stream)?;
@ -179,6 +183,7 @@ impl BitWrite<LittleEndian> for UserMessage<'_> {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_user_message_roundtrip() { fn test_user_message_roundtrip() {
crate::test_roundtrip_write(UserMessage::Train(TrainMessage { data: 12 })); crate::test_roundtrip_write(UserMessage::Train(TrainMessage { data: 12 }));
crate::test_roundtrip_write(UserMessage::SayText2(Box::new(SayText2Message { crate::test_roundtrip_write(UserMessage::SayText2(Box::new(SayText2Message {
@ -222,6 +227,7 @@ impl BitRead<'_, LittleEndian> for ChatMessageKind {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for ChatMessageKind { impl BitWrite<LittleEndian> for ChatMessageKind {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
match self { match self {
@ -321,6 +327,7 @@ impl BitRead<'_, LittleEndian> for SayText2Message {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for SayText2Message { impl BitWrite<LittleEndian> for SayText2Message {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
(u32::from(self.client) as u8).write(stream)?; (u32::from(self.client) as u8).write(stream)?;
@ -340,6 +347,7 @@ impl BitWrite<LittleEndian> for SayText2Message {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_say_text2_roundtrip() { fn test_say_text2_roundtrip() {
crate::test_roundtrip_write(SayText2Message { crate::test_roundtrip_write(SayText2Message {
client: 3u32.into(), client: 3u32.into(),
@ -351,7 +359,8 @@ fn test_say_text2_roundtrip() {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
#[discriminant_bits = 8] #[discriminant_bits = 8]
pub enum HudTextLocation { pub enum HudTextLocation {
PrintNotify = 1, PrintNotify = 1,
@ -361,7 +370,8 @@ pub enum HudTextLocation {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct TextMessage { pub struct TextMessage {
pub location: HudTextLocation, pub location: HudTextLocation,
pub text: MaybeUtf8String, pub text: MaybeUtf8String,
@ -375,19 +385,22 @@ impl TextMessage {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct ResetHudMessage { pub struct ResetHudMessage {
pub data: u8, pub data: u8,
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct TrainMessage { pub struct TrainMessage {
pub data: u8, pub data: u8,
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct VoiceSubtitleMessage { pub struct VoiceSubtitleMessage {
pub client: u8, pub client: u8,
pub menu: u8, pub menu: u8,
@ -395,7 +408,8 @@ pub struct VoiceSubtitleMessage {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct ShakeMessage { pub struct ShakeMessage {
pub command: u8, pub command: u8,
pub amplitude: f32, pub amplitude: f32,
@ -412,6 +426,7 @@ pub struct VGuiMenuMessage {
pub data: Vec<VGuiMenuMessageData>, pub data: Vec<VGuiMenuMessageData>,
} }
#[cfg(feature = "write")]
impl<E: Endianness> BitWrite<E> for VGuiMenuMessage { impl<E: Endianness> BitWrite<E> for VGuiMenuMessage {
fn write(&self, stream: &mut BitWriteStream<E>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<E>) -> ReadResult<()> {
self.name.write(stream)?; self.name.write(stream)?;
@ -425,14 +440,16 @@ impl<E: Endianness> BitWrite<E> for VGuiMenuMessage {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct VGuiMenuMessageData { pub struct VGuiMenuMessageData {
pub key: MaybeUtf8String, pub key: MaybeUtf8String,
pub data: MaybeUtf8String, pub data: MaybeUtf8String,
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct RumbleMessage { pub struct RumbleMessage {
pub waveform_index: u8, pub waveform_index: u8,
pub rumble_data: u8, pub rumble_data: u8,
@ -440,7 +457,8 @@ pub struct RumbleMessage {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct FadeMessage { pub struct FadeMessage {
pub duration: u16, pub duration: u16,
pub hold: u16, pub hold: u16,
@ -449,7 +467,8 @@ pub struct FadeMessage {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct HapMeleeContactMessage { pub struct HapMeleeContactMessage {
pub data: u8, pub data: u8,
} }

View file

@ -1,4 +1,6 @@
use bitbuffer::{BitRead, BitWrite, BitWriteSized, BitWriteStream, LittleEndian}; use bitbuffer::{BitRead, LittleEndian};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteSized, BitWriteStream};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ReadResult, Stream}; use crate::{ReadResult, Stream};
@ -35,6 +37,7 @@ impl BitRead<'_, LittleEndian> for VoiceInitMessage {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for VoiceInitMessage { impl BitWrite<LittleEndian> for VoiceInitMessage {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.codec.write(stream)?; self.codec.write(stream)?;
@ -49,6 +52,7 @@ impl BitWrite<LittleEndian> for VoiceInitMessage {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_voice_init_roundtrip() { fn test_voice_init_roundtrip() {
crate::test_roundtrip_write(VoiceInitMessage { crate::test_roundtrip_write(VoiceInitMessage {
codec: "foo".into(), codec: "foo".into(),
@ -63,7 +67,8 @@ fn test_voice_init_roundtrip() {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
#[endianness = "LittleEndian"] #[endianness = "LittleEndian"]
#[serde(bound(deserialize = "'a: 'static"))] #[serde(bound(deserialize = "'a: 'static"))]
pub struct VoiceDataMessage<'a> { pub struct VoiceDataMessage<'a> {
@ -104,6 +109,7 @@ impl<'a> BitRead<'a, LittleEndian> for ParseSoundsMessage<'a> {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for ParseSoundsMessage<'_> { impl BitWrite<LittleEndian> for ParseSoundsMessage<'_> {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.reliable.write(stream)?; self.reliable.write(stream)?;
@ -124,6 +130,7 @@ impl BitWrite<LittleEndian> for ParseSoundsMessage<'_> {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_parse_sounds_roundtrip() { fn test_parse_sounds_roundtrip() {
use bitbuffer::BitReadBuffer; use bitbuffer::BitReadBuffer;
let inner = BitReadBuffer::new(&[1, 2, 3, 4, 5, 6], LittleEndian); let inner = BitReadBuffer::new(&[1, 2, 3, 4, 5, 6], LittleEndian);

View file

@ -1,6 +1,8 @@
use crate::demo::data::DemoTick; use crate::demo::data::DemoTick;
use crate::{ReadResult, Stream}; use crate::{ReadResult, Stream};
use bitbuffer::{BitRead, BitWrite, LittleEndian}; #[cfg(feature = "write")]
use bitbuffer::BitWrite;
use bitbuffer::{BitRead, LittleEndian};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
@ -20,6 +22,7 @@ impl BitRead<'_, LittleEndian> for ConsoleCmdPacket {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for ConsoleCmdPacket { impl BitWrite<LittleEndian> for ConsoleCmdPacket {
fn write(&self, stream: &mut bitbuffer::BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut bitbuffer::BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.tick.write(stream)?; self.tick.write(stream)?;

View file

@ -4,19 +4,21 @@ use crate::demo::sendprop::{
RawSendPropDefinition, SendPropDefinition, SendPropFlag, SendPropIdentifier, SendPropType, RawSendPropDefinition, SendPropDefinition, SendPropFlag, SendPropIdentifier, SendPropType,
}; };
use crate::{Parse, ParseError, ParserState, Result, Stream}; use crate::{Parse, ParseError, ParserState, Result, Stream};
use bitbuffer::{BitRead, BitReadStream, BitWrite, BitWriteSized, BitWriteStream, Endianness, LittleEndian}; use bitbuffer::{BitRead, BitReadStream, Endianness};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteSized, BitWriteStream, LittleEndian};
use parse_display::{Display, FromStr}; use parse_display::{Display, FromStr};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::borrow::Cow; use std::borrow::Cow;
use std::cmp::min; use std::cmp::min;
use std::convert::TryFrom; use std::convert::TryFrom;
#[cfg(feature = "write")]
use std::iter::once; use std::iter::once;
use std::ops::Deref; use std::ops::Deref;
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive( #[derive(
BitRead, BitRead,
BitWrite,
Debug, Debug,
Clone, Clone,
Copy, Copy,
@ -30,6 +32,7 @@ use std::ops::Deref;
Serialize, Serialize,
Deserialize, Deserialize,
)] )]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct ClassId(u16); pub struct ClassId(u16);
impl From<u16> for ClassId { impl From<u16> for ClassId {
@ -57,7 +60,8 @@ impl PartialEq<u16> for ClassId {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Clone, Display)] #[derive(BitRead, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Clone, Display)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct ServerClassName(String); pub struct ServerClassName(String);
impl ServerClassName { impl ServerClassName {
@ -99,7 +103,8 @@ impl Deref for ServerClassName {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct ServerClass { pub struct ServerClass {
pub id: ClassId, pub id: ClassId,
pub name: ServerClassName, pub name: ServerClassName,
@ -108,19 +113,9 @@ pub struct ServerClass {
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive( #[derive(
BitWrite, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Clone, Display, PartialOrd, Ord, Default,
PartialEq,
Eq,
Hash,
Debug,
Serialize,
Deserialize,
Clone,
Display,
PartialOrd,
Ord,
Default,
)] )]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct SendTableName(Cow<'static, str>); pub struct SendTableName(Cow<'static, str>);
impl SendTableName { impl SendTableName {
@ -210,6 +205,7 @@ impl Parse<'_> for ParseSendTable {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for ParseSendTable { impl BitWrite<LittleEndian> for ParseSendTable {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> bitbuffer::Result<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> bitbuffer::Result<()> {
self.needs_decoder.write(stream)?; self.needs_decoder.write(stream)?;
@ -238,6 +234,7 @@ impl BitWrite<LittleEndian> for ParseSendTable {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_parse_send_table_roundtrip() { fn test_parse_send_table_roundtrip() {
use crate::demo::sendprop::SendPropFlags; use crate::demo::sendprop::SendPropFlags;
@ -469,6 +466,7 @@ impl Parse<'_> for DataTablePacket {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for DataTablePacket { impl BitWrite<LittleEndian> for DataTablePacket {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> bitbuffer::Result<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> bitbuffer::Result<()> {
self.tick.write(stream)?; self.tick.write(stream)?;
@ -488,6 +486,7 @@ impl BitWrite<LittleEndian> for DataTablePacket {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_data_table_packet_roundtrip() { fn test_data_table_packet_roundtrip() {
use crate::demo::sendprop::SendPropFlags; use crate::demo::sendprop::SendPropFlags;

View file

@ -1,8 +1,11 @@
use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian}; use bitbuffer::BitRead;
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteStream, LittleEndian};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::demo::data::DemoTick; use crate::demo::data::DemoTick;
use crate::demo::message::{Message, MessageType}; use crate::demo::message::{Message, MessageType};
#[cfg(feature = "write")]
use crate::demo::parser::Encode; use crate::demo::parser::Encode;
use crate::demo::vector::Vector; use crate::demo::vector::Vector;
use crate::{Parse, ParserState, Result, Stream}; use crate::{Parse, ParserState, Result, Stream};
@ -10,7 +13,8 @@ use crate::{Parse, ParserState, Result, Stream};
use tracing::{event, span, Level}; use tracing::{event, span, Level};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, BitRead, BitWrite, PartialEq, Serialize, Deserialize, Clone, Default)] #[derive(Debug, BitRead, PartialEq, Serialize, Deserialize, Clone, Default)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct MessagePacketMeta { pub struct MessagePacketMeta {
pub flags: u32, // TODO pub flags: u32, // TODO
pub view_angles: [ViewAngles; 2], pub view_angles: [ViewAngles; 2],
@ -28,7 +32,8 @@ pub struct MessagePacket<'a> {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize, BitRead, BitWrite)] #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize, BitRead)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct ViewAngles { pub struct ViewAngles {
pub origin: Vector, pub origin: Vector,
pub angles: Vector, pub angles: Vector,
@ -36,6 +41,7 @@ pub struct ViewAngles {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_view_angles_roundtrip() { fn test_view_angles_roundtrip() {
crate::test_roundtrip_write(ViewAngles::default()); crate::test_roundtrip_write(ViewAngles::default());
crate::test_roundtrip_write(ViewAngles { crate::test_roundtrip_write(ViewAngles {
@ -94,6 +100,7 @@ impl<'a> Parse<'a> for MessagePacket<'a> {
} }
} }
#[cfg(feature = "write")]
impl Encode for MessagePacket<'_> { impl Encode for MessagePacket<'_> {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> { fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
self.tick.write(stream)?; self.tick.write(stream)?;

View file

@ -1,4 +1,6 @@
use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian}; use bitbuffer::BitRead;
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteStream, LittleEndian};
use crate::{Parse, ParserState, Result, Stream}; use crate::{Parse, ParserState, Result, Stream};
@ -10,6 +12,7 @@ use self::stringtable::StringTablePacket;
use self::synctick::SyncTickPacket; use self::synctick::SyncTickPacket;
use self::usercmd::UserCmdPacket; use self::usercmd::UserCmdPacket;
use crate::demo::data::DemoTick; use crate::demo::data::DemoTick;
#[cfg(feature = "write")]
use crate::demo::parser::Encode; use crate::demo::parser::Encode;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
@ -67,7 +70,8 @@ impl Packet<'_> {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, Clone, Copy, Eq, PartialEq)] #[derive(BitRead, Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "write", derive(BitWrite))]
#[discriminant_bits = 8] #[discriminant_bits = 8]
#[repr(u8)] #[repr(u8)]
pub enum PacketType { pub enum PacketType {
@ -123,6 +127,7 @@ impl<'a> Parse<'a> for Packet<'a> {
} }
} }
#[cfg(feature = "write")]
impl Encode for Packet<'_> { impl Encode for Packet<'_> {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> { fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
#[cfg(feature = "trace")] #[cfg(feature = "trace")]

View file

@ -1,5 +1,7 @@
use crate::demo::data::DemoTick; use crate::demo::data::DemoTick;
use bitbuffer::{BitRead, BitReadStream, BitWrite, BitWriteStream, Endianness}; use bitbuffer::{BitRead, BitReadStream, Endianness};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteStream};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
@ -16,6 +18,7 @@ impl<'a, E: Endianness> BitRead<'a, E> for StopPacket {
} }
} }
#[cfg(feature = "write")]
impl<E: Endianness> BitWrite<E> for StopPacket { impl<E: Endianness> BitWrite<E> for StopPacket {
fn write(&self, stream: &mut BitWriteStream<E>) -> bitbuffer::Result<()> { fn write(&self, stream: &mut BitWriteStream<E>) -> bitbuffer::Result<()> {
stream.write_int::<u32>(self.tick.into(), 24) stream.write_int::<u32>(self.tick.into(), 24)

View file

@ -1,16 +1,20 @@
use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian}; use bitbuffer::{BitRead, LittleEndian};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteStream};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt; use std::fmt;
use crate::demo::data::DemoTick; use crate::demo::data::DemoTick;
use crate::demo::message::stringtable::StringTableMeta; use crate::demo::message::stringtable::StringTableMeta;
#[cfg(feature = "write")]
use crate::demo::parser::Encode; use crate::demo::parser::Encode;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream}; use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use std::borrow::{Borrow, Cow}; use std::borrow::{Borrow, Cow};
use std::cmp::min; use std::cmp::min;
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct FixedUserDataSize { pub struct FixedUserDataSize {
#[size = 12] #[size = 12]
pub size: u16, pub size: u16,
@ -78,6 +82,7 @@ impl<'a> BitRead<'a, LittleEndian> for StringTable<'a> {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for StringTable<'_> { impl BitWrite<LittleEndian> for StringTable<'_> {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.name.as_ref().write(stream)?; self.name.as_ref().write(stream)?;
@ -97,6 +102,7 @@ impl BitWrite<LittleEndian> for StringTable<'_> {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_string_table_roundtrip() { fn test_string_table_roundtrip() {
crate::test_roundtrip_write(StringTable { crate::test_roundtrip_write(StringTable {
name: "foo".into(), name: "foo".into(),
@ -149,7 +155,8 @@ fn test_string_table_roundtrip() {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(BitRead, Clone, Debug, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
#[endianness = "LittleEndian"] #[endianness = "LittleEndian"]
#[serde(bound(deserialize = "'a: 'static"))] #[serde(bound(deserialize = "'a: 'static"))]
pub struct ExtraData<'a> { pub struct ExtraData<'a> {
@ -205,6 +212,7 @@ impl<'a> BitRead<'a, LittleEndian> for StringTableEntry<'a> {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for StringTableEntry<'_> { impl BitWrite<LittleEndian> for StringTableEntry<'_> {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.text.as_deref().unwrap_or_default().write(stream)?; self.text.as_deref().unwrap_or_default().write(stream)?;
@ -254,6 +262,7 @@ impl<'a> Parse<'a> for StringTablePacket<'a> {
} }
} }
#[cfg(feature = "write")]
impl Encode for StringTablePacket<'_> { impl Encode for StringTablePacket<'_> {
fn encode( fn encode(
&self, &self,
@ -271,6 +280,7 @@ impl Encode for StringTablePacket<'_> {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_string_table_packet_roundtrip() { fn test_string_table_packet_roundtrip() {
let state = ParserState::new(24, |_| false, false); let state = ParserState::new(24, |_| false, false);
crate::test_roundtrip_encode( crate::test_roundtrip_encode(

View file

@ -1,9 +1,12 @@
use crate::demo::data::DemoTick; use crate::demo::data::DemoTick;
use bitbuffer::{BitRead, BitWrite}; use bitbuffer::BitRead;
#[cfg(feature = "write")]
use bitbuffer::BitWrite;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(BitRead, Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct SyncTickPacket { pub struct SyncTickPacket {
pub tick: DemoTick, pub tick: DemoTick,
} }

View file

@ -1,5 +1,7 @@
use crate::demo::data::DemoTick; use crate::demo::data::DemoTick;
use bitbuffer::{BitRead, BitReadStream, BitWrite, BitWriteStream, LittleEndian}; use bitbuffer::{BitRead, BitReadStream, LittleEndian};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteStream};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
@ -25,6 +27,7 @@ impl<'a> BitRead<'a, LittleEndian> for UserCmdPacket {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for UserCmdPacket { impl BitWrite<LittleEndian> for UserCmdPacket {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> bitbuffer::Result<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> bitbuffer::Result<()> {
self.tick.write(stream)?; self.tick.write(stream)?;
@ -34,7 +37,8 @@ impl BitWrite<LittleEndian> for UserCmdPacket {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, PartialEq, BitRead, BitWrite, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, BitRead, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct UserCmd { pub struct UserCmd {
pub command_number: Option<u32>, pub command_number: Option<u32>,
pub tick_count: Option<u32>, pub tick_count: Option<u32>,
@ -48,7 +52,8 @@ pub struct UserCmd {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, PartialEq, BitRead, BitWrite, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, BitRead, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct WeaponSelect { pub struct WeaponSelect {
#[size = 11] #[size = 11]
select: u16, select: u16,

View file

@ -185,10 +185,8 @@ impl GameStateAnalyser {
} }
pub fn handle_world_entity(&mut self, entity: &PacketEntity, parser_state: &ParserState) { pub fn handle_world_entity(&mut self, entity: &PacketEntity, parser_state: &ParserState) {
const MINS: SendPropIdentifier = const MINS: SendPropIdentifier = SendPropIdentifier::new("DT_WORLD", "m_WorldMins");
SendPropIdentifier::new("DT_WORLD", "m_WorldMins"); const MAXS: SendPropIdentifier = SendPropIdentifier::new("DT_WORLD", "m_WorldMaxs");
const MAXS: SendPropIdentifier =
SendPropIdentifier::new("DT_WORLD", "m_WorldMaxs");
if let ( if let (
Some(SendProp { Some(SendProp {

View file

@ -6,10 +6,11 @@ use crate::demo::packet::datatable::SendTableName;
use crate::demo::parser::MalformedSendPropDefinitionError; use crate::demo::parser::MalformedSendPropDefinitionError;
use crate::demo::sendprop_gen::get_prop_names; use crate::demo::sendprop_gen::get_prop_names;
use crate::{ParseError, ReadResult, Result, Stream}; use crate::{ParseError, ReadResult, Result, Stream};
use bitbuffer::{ use bitbuffer::{BitRead, BitReadStream, Endianness, LittleEndian};
BitRead, BitReadStream, BitWrite, BitWriteSized, BitWriteStream, Endianness, LittleEndian, #[cfg(feature = "write")]
}; use bitbuffer::{BitWrite, BitWriteSized, BitWriteStream};
use enumflags2::{bitflags, BitFlags}; use enumflags2::{bitflags, BitFlags};
#[cfg(feature = "write")]
use num_traits::Signed; use num_traits::Signed;
use parse_display::Display; use parse_display::Display;
use serde::de::Error; use serde::de::Error;
@ -22,9 +23,8 @@ use std::hash::Hash;
use std::ops::{BitOr, Deref}; use std::ops::{BitOr, Deref};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive( #[derive(PartialEq, Eq, Hash, Debug, Display, Clone, Serialize, Deserialize, Ord, PartialOrd)]
BitWrite, PartialEq, Eq, Hash, Debug, Display, Clone, Serialize, Deserialize, Ord, PartialOrd, #[cfg_attr(feature = "write", derive(BitWrite))]
)]
pub struct SendPropName(Cow<'static, str>); pub struct SendPropName(Cow<'static, str>);
impl SendPropName { impl SendPropName {
@ -242,6 +242,7 @@ impl RawSendPropDefinition {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for RawSendPropDefinition { impl BitWrite<LittleEndian> for RawSendPropDefinition {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.prop_type.write(stream)?; self.prop_type.write(stream)?;
@ -267,7 +268,8 @@ impl BitWrite<LittleEndian> for RawSendPropDefinition {
} }
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitRead, BitWrite, Copy, Clone, PartialEq, Debug, Display, Serialize, Deserialize)] #[derive(BitRead, Copy, Clone, PartialEq, Debug, Display, Serialize, Deserialize)]
#[cfg_attr(feature = "write", derive(BitWrite))]
#[discriminant_bits = 5] #[discriminant_bits = 5]
pub enum SendPropType { pub enum SendPropType {
Int = 0, Int = 0,
@ -376,6 +378,7 @@ impl BitRead<'_, LittleEndian> for SendPropFlags {
} }
} }
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for SendPropFlags { impl BitWrite<LittleEndian> for SendPropFlags {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.0.bits().write(stream) self.0.bits().write(stream)
@ -705,6 +708,8 @@ impl SendPropValue {
} }
} }
} }
#[cfg(feature = "write")]
pub fn encode( pub fn encode(
&self, &self,
stream: &mut BitWriteStream<LittleEndian>, stream: &mut BitWriteStream<LittleEndian>,
@ -802,6 +807,7 @@ impl SendPropValue {
} }
} }
#[cfg(feature = "write")]
fn write_float( fn write_float(
val: f32, val: f32,
stream: &mut BitWriteStream<LittleEndian>, stream: &mut BitWriteStream<LittleEndian>,
@ -839,6 +845,7 @@ impl SendPropValue {
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_send_prop_value_roundtrip() { fn test_send_prop_value_roundtrip() {
use bitbuffer::{BitReadBuffer, BitReadStream}; use bitbuffer::{BitReadBuffer, BitReadStream};
@ -1243,6 +1250,7 @@ pub fn read_var_int(stream: &mut Stream, signed: bool) -> ReadResult<i32> {
} }
} }
#[cfg(feature = "write")]
pub fn write_var_int( pub fn write_var_int(
int: i32, int: i32,
stream: &mut BitWriteStream<LittleEndian>, stream: &mut BitWriteStream<LittleEndian>,
@ -1259,6 +1267,7 @@ pub fn write_var_int(
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_var_int_roundtrip() { fn test_var_int_roundtrip() {
use bitbuffer::{BitReadBuffer, BitReadStream}; use bitbuffer::{BitReadBuffer, BitReadStream};
@ -1316,6 +1325,7 @@ pub fn read_bit_coord(stream: &mut Stream) -> ReadResult<f32> {
}) })
} }
#[cfg(feature = "write")]
pub fn write_bit_coord(val: f32, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { pub fn write_bit_coord(val: f32, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
let has_int = val.abs() >= 1.0; let has_int = val.abs() >= 1.0;
has_int.write(stream)?; has_int.write(stream)?;
@ -1338,6 +1348,7 @@ pub fn write_bit_coord(val: f32, stream: &mut BitWriteStream<LittleEndian>) -> R
} }
#[test] #[test]
#[cfg(feature = "write")]
fn bit_coord_roundtrip() { fn bit_coord_roundtrip() {
use bitbuffer::BitReadBuffer; use bitbuffer::BitReadBuffer;
@ -1406,6 +1417,7 @@ pub fn read_bit_coord_mp(
Ok(value) Ok(value)
} }
#[cfg(feature = "write")]
pub fn write_bit_coord_mp( pub fn write_bit_coord_mp(
val: f32, val: f32,
stream: &mut BitWriteStream<LittleEndian>, stream: &mut BitWriteStream<LittleEndian>,
@ -1437,6 +1449,7 @@ pub fn write_bit_coord_mp(
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_bit_coord_mp_roundtrip() { fn test_bit_coord_mp_roundtrip() {
use bitbuffer::{BitReadBuffer, BitReadStream}; use bitbuffer::{BitReadBuffer, BitReadStream};
@ -1488,6 +1501,7 @@ pub fn read_bit_normal(stream: &mut Stream) -> ReadResult<f32> {
} }
} }
#[cfg(feature = "write")]
pub fn write_bit_normal(val: f32, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> { pub fn write_bit_normal(val: f32, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
val.is_sign_negative().write(stream)?; val.is_sign_negative().write(stream)?;
let frac_val = (val.abs().fract() / get_frac_factor(11)) as u16; let frac_val = (val.abs().fract() / get_frac_factor(11)) as u16;
@ -1495,6 +1509,7 @@ pub fn write_bit_normal(val: f32, stream: &mut BitWriteStream<LittleEndian>) ->
} }
#[test] #[test]
#[cfg(feature = "write")]
fn test_bit_normal_roundtrip() { fn test_bit_normal_roundtrip() {
use bitbuffer::{BitReadBuffer, BitReadStream}; use bitbuffer::{BitReadBuffer, BitReadStream};

View file

@ -20,7 +20,7 @@ pub(crate) mod consthash;
pub mod demo; pub mod demo;
pub(crate) mod nullhasher; pub(crate) mod nullhasher;
#[cfg(test)] #[cfg(all(test, feature = "write"))]
#[track_caller] #[track_caller]
fn test_roundtrip_write< fn test_roundtrip_write<
'a, 'a,
@ -54,7 +54,7 @@ fn test_roundtrip_write<
); );
} }
#[cfg(test)] #[cfg(all(test, feature = "write"))]
#[track_caller] #[track_caller]
fn test_roundtrip_encode< fn test_roundtrip_encode<
'a, 'a,

View file

@ -1,11 +1,19 @@
#[cfg(feature = "write")]
use bitbuffer::{BitReadBuffer, BitReadStream, BitWriteStream, LittleEndian}; use bitbuffer::{BitReadBuffer, BitReadStream, BitWriteStream, LittleEndian};
#[cfg(feature = "write")]
use std::fs; use std::fs;
#[cfg(feature = "write")]
use test_case::test_case; use test_case::test_case;
#[cfg(feature = "write")]
use tf_demo_parser::demo::message::Message; use tf_demo_parser::demo::message::Message;
#[cfg(feature = "write")]
use tf_demo_parser::demo::packet::Packet; use tf_demo_parser::demo::packet::Packet;
#[cfg(feature = "write")]
use tf_demo_parser::demo::parser::{DemoHandler, Encode, NullHandler}; use tf_demo_parser::demo::parser::{DemoHandler, Encode, NullHandler};
#[cfg(feature = "write")]
use tf_demo_parser::{MessageType, Parse}; use tf_demo_parser::{MessageType, Parse};
#[cfg(feature = "write")]
fn setup_packet(handler: &mut DemoHandler<NullHandler>, input: &str) { fn setup_packet(handler: &mut DemoHandler<NullHandler>, input: &str) {
let data = fs::read(input).unwrap(); let data = fs::read(input).unwrap();
let mut stream = BitReadStream::new(BitReadBuffer::new_owned(data, LittleEndian)); let mut stream = BitReadStream::new(BitReadBuffer::new_owned(data, LittleEndian));
@ -13,6 +21,7 @@ fn setup_packet(handler: &mut DemoHandler<NullHandler>, input: &str) {
handler.handle_packet(packet).unwrap(); handler.handle_packet(packet).unwrap();
} }
#[cfg(feature = "write")]
fn setup_message(handler: &mut DemoHandler<NullHandler>, input: &str) { fn setup_message(handler: &mut DemoHandler<NullHandler>, input: &str) {
let data = fs::read(input).unwrap(); let data = fs::read(input).unwrap();
let mut stream = BitReadStream::new(BitReadBuffer::new_owned(data, LittleEndian)); let mut stream = BitReadStream::new(BitReadBuffer::new_owned(data, LittleEndian));
@ -25,6 +34,7 @@ fn setup_message(handler: &mut DemoHandler<NullHandler>, input: &str) {
handler.handle_message(message, 0.into()); handler.handle_message(message, 0.into());
} }
#[cfg(feature = "write")]
#[test_case("game_event_list.bin", MessageType::GameEventList, &[], &[]; "game_event_list")] #[test_case("game_event_list.bin", MessageType::GameEventList, &[], &[]; "game_event_list")]
#[test_case("packet_entities.bin", MessageType::PacketEntities, &["setup_data_tables.bin", "setup_string_tables.bin"], &[]; "packet_entities")] #[test_case("packet_entities.bin", MessageType::PacketEntities, &["setup_data_tables.bin", "setup_string_tables.bin"], &[]; "packet_entities")]
#[test_case("packet_entities_pov1.bin", MessageType::PacketEntities, &["setup_data_tables_pov.bin", "setup_string_tables_pov.bin"], &[]; "packet_entities_pov1")] #[test_case("packet_entities_pov1.bin", MessageType::PacketEntities, &["setup_data_tables_pov.bin", "setup_string_tables_pov.bin"], &[]; "packet_entities_pov1")]

View file

@ -1,16 +1,28 @@
#[cfg(feature = "write")]
use std::fs; use std::fs;
#[cfg(feature = "write")]
use test_case::test_case; use test_case::test_case;
#[cfg(feature = "write")]
use bitbuffer::{BitRead, BitReadBuffer, BitReadStream, BitWrite, BitWriteStream, LittleEndian}; use bitbuffer::{BitRead, BitReadBuffer, BitReadStream, BitWrite, BitWriteStream, LittleEndian};
#[cfg(feature = "write")]
use std::collections::HashMap; use std::collections::HashMap;
#[cfg(feature = "write")]
use tf_demo_parser::demo::header::Header; use tf_demo_parser::demo::header::Header;
#[cfg(feature = "write")]
use tf_demo_parser::demo::message::Message; use tf_demo_parser::demo::message::Message;
#[cfg(feature = "write")]
use tf_demo_parser::demo::packet::datatable::SendTableName; use tf_demo_parser::demo::packet::datatable::SendTableName;
#[cfg(feature = "write")]
use tf_demo_parser::demo::packet::Packet; use tf_demo_parser::demo::packet::Packet;
#[cfg(feature = "write")]
use tf_demo_parser::demo::parser::{DemoHandler, Encode, NullHandler, RawPacketStream}; use tf_demo_parser::demo::parser::{DemoHandler, Encode, NullHandler, RawPacketStream};
#[cfg(feature = "write")]
use tf_demo_parser::demo::sendprop::{RawSendPropDefinition, SendPropIdentifier, SendPropName}; use tf_demo_parser::demo::sendprop::{RawSendPropDefinition, SendPropIdentifier, SendPropName};
#[cfg(feature = "write")]
use tf_demo_parser::{Demo, Parse}; use tf_demo_parser::{Demo, Parse};
#[cfg(feature = "write")]
#[test_case("test_data/small.dem"; "small.dem")] #[test_case("test_data/small.dem"; "small.dem")]
#[test_case("test_data/gully.dem"; "gully.dem")] #[test_case("test_data/gully.dem"; "gully.dem")]
#[test_case("test_data/comp.dem"; "comp.dem")] #[test_case("test_data/comp.dem"; "comp.dem")]

View file

@ -1,11 +1,19 @@
use bitbuffer::{BitReadBuffer, BitReadStream, BitWriteStream, LittleEndian}; #[cfg(feature = "write")]
use bitbuffer::BitWriteStream;
use bitbuffer::{BitReadBuffer, BitReadStream, LittleEndian};
use std::fs; use std::fs;
use test_case::test_case; use test_case::test_case;
#[cfg(feature = "write")]
use tf_demo_parser::demo::message::stringtable::StringTableMeta;
#[cfg(feature = "write")]
use tf_demo_parser::demo::message::stringtable::{ use tf_demo_parser::demo::message::stringtable::{
parse_string_table_update, write_string_table_update, StringTableMeta, parse_string_table_update, write_string_table_update,
}; };
use tf_demo_parser::demo::packet::stringtable::{FixedUserDataSize, StringTable}; #[cfg(feature = "write")]
use tf_demo_parser::demo::packet::stringtable::FixedUserDataSize;
use tf_demo_parser::demo::packet::stringtable::StringTable;
#[cfg(feature = "write")]
#[test_case("test_data/string_tables/decalprecache.bin", "test_data/string_tables/decalprecache_meta.json"; "decalprecache")] #[test_case("test_data/string_tables/decalprecache.bin", "test_data/string_tables/decalprecache_meta.json"; "decalprecache")]
#[test_case("test_data/string_tables/downloadables.bin", "test_data/string_tables/downloadables_meta.json"; "downloadables")] #[test_case("test_data/string_tables/downloadables.bin", "test_data/string_tables/downloadables_meta.json"; "downloadables")]
#[test_case("test_data/string_tables/DynamicModels.bin", "test_data/string_tables/DynamicModels_meta.json"; "DynamicModels")] #[test_case("test_data/string_tables/DynamicModels.bin", "test_data/string_tables/DynamicModels_meta.json"; "DynamicModels")]