1
0
Fork 0
mirror of https://codeberg.org/demostf/parser.git synced 2026-06-03 10:14:06 +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

View file

@ -234,6 +234,7 @@ pub fn generate_game_events(demo: Demo) -> TokenStream {
use bitbuffer::{BitRead, LittleEndian, BitWrite, BitWriteStream};
use serde::{Deserialize, Serialize};
use crate::demo::data::MaybeUtf8String;
use std::mem::size_of;
);
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 raw_name = &entry.name;
let name_hash = entry.hash;
let name = get_entry_name(&entry.name);
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 name = Ident::new(&format!("{event_name}Event"), span);
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 = Ident::new(&name_str, span);
let ty = Ident::new(get_type_name(entry.kind), span);
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)]
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)]
match field {
match field.hash {
#(#field_getters,)*
_ => Err(ParseError::MissingGameEventValue {
ty: #event_name,
field: field.into(),
field: "todo".into(),
}),
}
}
@ -296,7 +297,7 @@ pub fn generate_game_events(demo: Demo) -> TokenStream {
#[allow(unused_variables)]
fn write(&self, stream: &mut BitWriteStream<LittleEndian>, definition: &GameEventDefinition) -> Result<()> {
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)?;
}
Ok(())
@ -383,7 +384,7 @@ pub fn generate_game_events(demo: Demo) -> TokenStream {
let struct_name = Ident::new(&format!("{name}Event"), span);
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::{GameEventError, Result, Stream};
use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian};
use const_fnv1a_hash::fnv1a_hash_str_64;
use parse_display::Display;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use const_fnv1a_hash::fnv1a_hash_str_64;
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -17,8 +17,7 @@ pub struct GameEventDefinition {
}
impl GameEventDefinition {
pub fn get_entry(&self, name: &str) -> Option<&GameEventEntry> {
let hash = fnv1a_hash_str_64(name);
pub fn get_entry(&self, hash: u64) -> Option<&GameEventEntry> {
self.entries.iter().find(|entry| entry.hash == hash)
}
}
@ -46,17 +45,20 @@ impl Ord for GameEventDefinition {
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct GameEventEntry {
#[cfg(any(feature = "codegen", feature = "write"))]
pub name: String,
pub hash: u64,
pub kind: GameEventValueType,
}
impl GameEventEntry {
pub fn new<S: Into<String>>(name: S, kind: GameEventValueType) -> Self {
let name = name.into();
pub fn new<S: AsRef<str>>(name: S, kind: GameEventValueType) -> Self {
let name = name.as_ref();
let hash = fnv1a_hash_str_64(name);
GameEventEntry {
hash: fnv1a_hash_str_64(&name),
#[cfg(any(feature = "codegen", feature = "write"))]
name: name.into(),
hash,
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::{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};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
@ -44,6 +48,7 @@ impl BitRead<'_, LittleEndian> for BSPDecalMessage {
}
}
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for BSPDecalMessage {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
let has_x = self.position.x != 0.0;
@ -75,6 +80,7 @@ impl BitWrite<LittleEndian> for BSPDecalMessage {
}
#[test]
#[cfg(feature = "write")]
fn test_decal_roundtrip() {
crate::test_roundtrip_write(BSPDecalMessage {
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 crate::demo::message::stringtable::log_base2;
@ -6,7 +8,8 @@ use crate::{ReadResult, Stream};
use std::cmp::min;
#[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 {
#[size = "input_size"]
class_id: u16,
@ -45,6 +48,7 @@ impl BitRead<'_, LittleEndian> for ClassInfoMessage {
}
}
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for ClassInfoMessage {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.count.write(stream)?;
@ -61,6 +65,7 @@ impl BitWrite<LittleEndian> for ClassInfoMessage {
}
#[test]
#[cfg(feature = "write")]
fn test_class_info_roundtrip() {
crate::test_roundtrip_write(ClassInfoMessage {
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 serde::{Deserialize, Serialize};
use std::borrow::Cow;
@ -7,7 +9,9 @@ use crate::demo::gameevent_gen::GameEventType;
use crate::demo::gamevent::{
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};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
@ -52,6 +56,7 @@ impl Parse<'_> for GameEventMessage {
}
}
#[cfg(feature = "write")]
impl Encode for GameEventMessage {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
let definition = state
@ -68,6 +73,7 @@ impl Encode for GameEventMessage {
}
}
#[cfg(feature = "write")]
#[test]
fn test_game_event_roundtrip() {
use crate::demo::gameevent_gen::{GameInitEvent, ServerShutdownEvent};
@ -125,7 +131,6 @@ impl ParseBitSkip<'_> for GameEventMessage {
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(
BitRead,
BitWrite,
Debug,
Clone,
Copy,
@ -138,6 +143,7 @@ impl ParseBitSkip<'_> for GameEventMessage {
Serialize,
Deserialize,
)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct GameEventTypeId(#[size = 9] u16);
impl From<GameEventTypeId> for usize {
@ -179,6 +185,7 @@ impl BitRead<'_, LittleEndian> for GameEventDefinition {
}
}
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for GameEventDefinition {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.id.write(stream)?;
@ -198,6 +205,7 @@ impl BitWrite<LittleEndian> for GameEventDefinition {
}
#[test]
#[cfg(feature = "write")]
fn test_event_definition_roundtrip() {
crate::test_roundtrip_write(GameEventDefinition {
id: GameEventTypeId(0),
@ -220,6 +228,7 @@ impl BitRead<'_, LittleEndian> for GameEventListMessage {
}
}
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for GameEventListMessage {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
(self.event_list.len() as u16).write_sized(stream, 9)?;
@ -233,13 +242,17 @@ impl BitWrite<LittleEndian> for GameEventListMessage {
}
#[test]
#[cfg(feature = "write")]
fn test_event_list_roundtrip() {
crate::test_roundtrip_write(GameEventListMessage { event_list: vec![] });
crate::test_roundtrip_write(GameEventListMessage {
event_list: vec![GameEventDefinition {
id: GameEventTypeId(0),
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 {

View file

@ -1,11 +1,14 @@
/// Messages that consists only of primitives and string and can be derived
use crate::demo::data::{MaybeUtf8String, ServerTick};
use crate::Stream;
use bitbuffer::{BitRead, BitWrite, LittleEndian};
#[cfg(feature = "write")]
use bitbuffer::BitWrite;
use bitbuffer::{BitRead, LittleEndian};
use serde::{Deserialize, Serialize};
#[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 transfer_id: u32,
pub file_name: String,
@ -13,7 +16,8 @@ pub struct FileMessage {
}
#[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 tick: ServerTick,
pub frame_time: u16,
@ -21,13 +25,15 @@ pub struct NetTickMessage {
}
#[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 command: String,
}
#[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]
pub enum SignOnState {
None = 0,
@ -41,33 +47,38 @@ pub enum SignOnState {
}
#[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 state: SignOnState,
pub count: u32,
}
#[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 value: MaybeUtf8String,
}
#[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 pause: bool,
}
#[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 {
#[size = 11]
pub index: u16,
}
#[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 relative: bool,
pub x: u16,
@ -76,7 +87,8 @@ pub struct FixAngleMessage {
}
#[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"]
#[serde(bound(deserialize = "'a: 'static"))]
pub struct EntityMessage<'a> {
@ -91,7 +103,8 @@ pub struct EntityMessage<'a> {
}
#[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"]
#[serde(bound(deserialize = "'a: 'static"))]
pub struct MenuMessage<'a> {
@ -102,14 +115,16 @@ pub struct MenuMessage<'a> {
}
#[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 cookie: u32,
pub value: String,
}
#[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"]
#[serde(bound(deserialize = "'a: 'static"))]
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::usermessage::*;
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 bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian};
use bitbuffer::BitRead;
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteStream, LittleEndian};
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
@ -31,9 +35,8 @@ pub mod usermessage;
pub mod voice;
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema_repr))]
#[derive(
BitRead, BitWrite, Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr,
)]
#[derive(BitRead, Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
#[cfg_attr(feature = "write", derive(BitWrite))]
#[repr(u8)]
#[discriminant_bits = 6]
pub enum MessageType {
@ -240,6 +243,7 @@ impl<'a> Message<'a> {
}
}
#[cfg(feature = "write")]
impl Encode for Message<'_> {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
match self {

View file

@ -1,13 +1,14 @@
use bitbuffer::{
BitRead, BitReadSized, BitReadStream, BitWrite, BitWriteSized, BitWriteStream, Endianness,
LittleEndian,
};
use bitbuffer::{BitRead, BitReadSized, BitReadStream, Endianness, LittleEndian};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteSized, BitWriteStream};
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use std::borrow::Cow;
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::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use parse_display::{Display, FromStr};
@ -75,9 +76,8 @@ impl PartialOrd<u32> for EntityId {
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema_repr))]
#[derive(
BitRead, BitWrite, Clone, Copy, Debug, PartialEq, Eq, Serialize_repr, Deserialize_repr,
)]
#[derive(BitRead, Clone, Copy, Debug, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
#[cfg_attr(feature = "write", derive(BitWrite))]
#[discriminant_bits = 2]
#[repr(u8)]
pub enum UpdateType {
@ -128,6 +128,7 @@ impl<E: Endianness> BitRead<'_, E> for BaselineIndex {
}
}
#[cfg(feature = "write")]
impl<E: Endianness> BitWrite<E> for BaselineIndex {
fn write(&self, stream: &mut BitWriteStream<E>) -> ReadResult<()> {
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)
}
#[cfg(feature = "write")]
fn write_bit_var(var: u32, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
let (ty, bits): (u8, usize) = if var >= 2u32.pow(12) {
(3, 32)
@ -272,6 +274,7 @@ fn write_bit_var(var: u32, stream: &mut BitWriteStream<LittleEndian>) -> ReadRes
}
#[test]
#[cfg(feature = "write")]
fn test_bit_var_roundtrip() {
use bitbuffer::{BitReadBuffer, BitReadStream};
@ -436,6 +439,7 @@ impl Parse<'_> for PacketEntitiesMessage {
}
}
#[cfg(feature = "write")]
impl Encode for PacketEntitiesMessage {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
self.max_entries.write_sized(stream, 11)?;
@ -520,6 +524,7 @@ impl PacketEntitiesMessage {
})
}
#[cfg(feature = "write")]
fn write_enter(
entity: &PacketEntity,
stream: &mut BitWriteStream<LittleEndian>,
@ -579,6 +584,7 @@ impl PacketEntitiesMessage {
Ok(())
}
#[cfg(feature = "write")]
pub fn write_update<'a, Props: IntoIterator<Item = &'a SendProp>>(
props: Props,
stream: &mut BitWriteStream<LittleEndian>,
@ -628,6 +634,7 @@ impl ParseBitSkip<'_> for PacketEntitiesMessage {
}
#[test]
#[cfg(feature = "write")]
fn test_packet_entity_message_roundtrip() {
use crate::demo::packet::datatable::{SendTable, SendTableName, ServerClass, ServerClassName};
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};
#[cfg(feature = "write")]
use bitbuffer::{BitWriteStream, LittleEndian};
use serde::{Deserialize, Serialize};
@ -28,6 +31,7 @@ impl<'a> Parse<'a> for PreFetchMessage {
}
}
#[cfg(feature = "write")]
impl Encode for PreFetchMessage {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
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 bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian};
use bitbuffer::{BitRead, LittleEndian};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteStream};
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
@ -78,6 +82,7 @@ impl<'a> ParseBitSkip<'a> for ServerInfoMessage {
}
}
#[cfg(feature = "write")]
impl Encode for ServerInfoMessage {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
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 version: u16,
pub server_count: u32,
@ -128,7 +134,8 @@ pub struct ServerInfoMessagePart1 {
pub max_classes: u16,
}
#[derive(BitRead, BitWrite)]
#[derive(BitRead)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct ServerInfoMessagePart2 {
pub player_slot: 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 crate::ReadResult;
#[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 key: String,
pub value: String,
@ -30,6 +33,7 @@ pub struct SetConVarMessage {
pub vars: Vec<ConVar>,
}
#[cfg(feature = "write")]
impl<E: Endianness> BitWrite<E> for SetConVarMessage {
fn write(&self, stream: &mut BitWriteStream<E>) -> ReadResult<()> {
self.length.write(stream)?;
@ -37,6 +41,7 @@ impl<E: Endianness> BitWrite<E> for SetConVarMessage {
}
}
#[test]
#[cfg(feature = "write")]
fn test_set_con_var_roundtrip() {
crate::test_roundtrip_write(SetConVarMessage {
length: 0,

View file

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

View file

@ -1,11 +1,15 @@
use super::stringtable::read_var_int;
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::parser::{Encode, ParseBitSkip};
#[cfg(feature = "write")]
use crate::demo::parser::Encode;
use crate::demo::parser::ParseBitSkip;
use crate::demo::sendprop::SendProp;
use crate::Result;
use crate::{Parse, ParseError, ParserState, Stream};
#[cfg(feature = "write")]
use bitbuffer::{BitWrite, BitWriteSized, BitWriteStream, LittleEndian};
use serde::{Deserialize, Serialize};
@ -95,6 +99,7 @@ impl ParseBitSkip<'_> for TempEntitiesMessage {
}
}
#[cfg(feature = "write")]
impl Encode for TempEntitiesMessage {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
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 crate::demo::data::MaybeUtf8String;
@ -6,7 +8,8 @@ use crate::demo::message::packetentities::EntityId;
use crate::{ReadResult, Stream};
#[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)]
#[discriminant_bits = 8]
pub enum UserMessageType {
@ -157,6 +160,7 @@ impl<'a> BitRead<'a, LittleEndian> for UserMessage<'a> {
}
}
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for UserMessage<'_> {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.message_type().write(stream)?;
@ -179,6 +183,7 @@ impl BitWrite<LittleEndian> for UserMessage<'_> {
}
#[test]
#[cfg(feature = "write")]
fn test_user_message_roundtrip() {
crate::test_roundtrip_write(UserMessage::Train(TrainMessage { data: 12 }));
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 {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
match self {
@ -321,6 +327,7 @@ impl BitRead<'_, LittleEndian> for SayText2Message {
}
}
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for SayText2Message {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
(u32::from(self.client) as u8).write(stream)?;
@ -340,6 +347,7 @@ impl BitWrite<LittleEndian> for SayText2Message {
}
#[test]
#[cfg(feature = "write")]
fn test_say_text2_roundtrip() {
crate::test_roundtrip_write(SayText2Message {
client: 3u32.into(),
@ -351,7 +359,8 @@ fn test_say_text2_roundtrip() {
}
#[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]
pub enum HudTextLocation {
PrintNotify = 1,
@ -361,7 +370,8 @@ pub enum HudTextLocation {
}
#[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 location: HudTextLocation,
pub text: MaybeUtf8String,
@ -375,19 +385,22 @@ impl TextMessage {
}
#[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 data: u8,
}
#[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 data: u8,
}
#[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 client: u8,
pub menu: u8,
@ -395,7 +408,8 @@ pub struct VoiceSubtitleMessage {
}
#[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 command: u8,
pub amplitude: f32,
@ -412,6 +426,7 @@ pub struct VGuiMenuMessage {
pub data: Vec<VGuiMenuMessageData>,
}
#[cfg(feature = "write")]
impl<E: Endianness> BitWrite<E> for VGuiMenuMessage {
fn write(&self, stream: &mut BitWriteStream<E>) -> ReadResult<()> {
self.name.write(stream)?;
@ -425,14 +440,16 @@ impl<E: Endianness> BitWrite<E> for VGuiMenuMessage {
}
#[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 key: MaybeUtf8String,
pub data: MaybeUtf8String,
}
#[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 waveform_index: u8,
pub rumble_data: u8,
@ -440,7 +457,8 @@ pub struct RumbleMessage {
}
#[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 duration: u16,
pub hold: u16,
@ -449,7 +467,8 @@ pub struct FadeMessage {
}
#[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 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 crate::{ReadResult, Stream};
@ -35,6 +37,7 @@ impl BitRead<'_, LittleEndian> for VoiceInitMessage {
}
}
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for VoiceInitMessage {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.codec.write(stream)?;
@ -49,6 +52,7 @@ impl BitWrite<LittleEndian> for VoiceInitMessage {
}
#[test]
#[cfg(feature = "write")]
fn test_voice_init_roundtrip() {
crate::test_roundtrip_write(VoiceInitMessage {
codec: "foo".into(),
@ -63,7 +67,8 @@ fn test_voice_init_roundtrip() {
}
#[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"]
#[serde(bound(deserialize = "'a: 'static"))]
pub struct VoiceDataMessage<'a> {
@ -104,6 +109,7 @@ impl<'a> BitRead<'a, LittleEndian> for ParseSoundsMessage<'a> {
}
}
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for ParseSoundsMessage<'_> {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.reliable.write(stream)?;
@ -124,6 +130,7 @@ impl BitWrite<LittleEndian> for ParseSoundsMessage<'_> {
}
#[test]
#[cfg(feature = "write")]
fn test_parse_sounds_roundtrip() {
use bitbuffer::BitReadBuffer;
let inner = BitReadBuffer::new(&[1, 2, 3, 4, 5, 6], LittleEndian);

View file

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

View file

@ -4,19 +4,21 @@ use crate::demo::sendprop::{
RawSendPropDefinition, SendPropDefinition, SendPropFlag, SendPropIdentifier, SendPropType,
};
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 serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::cmp::min;
use std::convert::TryFrom;
#[cfg(feature = "write")]
use std::iter::once;
use std::ops::Deref;
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(
BitRead,
BitWrite,
Debug,
Clone,
Copy,
@ -30,6 +32,7 @@ use std::ops::Deref;
Serialize,
Deserialize,
)]
#[cfg_attr(feature = "write", derive(BitWrite))]
pub struct ClassId(u16);
impl From<u16> for ClassId {
@ -57,7 +60,8 @@ impl PartialEq<u16> for ClassId {
}
#[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);
impl ServerClassName {
@ -99,7 +103,8 @@ impl Deref for ServerClassName {
}
#[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 id: ClassId,
pub name: ServerClassName,
@ -108,19 +113,9 @@ pub struct ServerClass {
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[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>);
impl SendTableName {
@ -210,6 +205,7 @@ impl Parse<'_> for ParseSendTable {
}
}
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for ParseSendTable {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> bitbuffer::Result<()> {
self.needs_decoder.write(stream)?;
@ -238,6 +234,7 @@ impl BitWrite<LittleEndian> for ParseSendTable {
}
#[test]
#[cfg(feature = "write")]
fn test_parse_send_table_roundtrip() {
use crate::demo::sendprop::SendPropFlags;
@ -469,6 +466,7 @@ impl Parse<'_> for DataTablePacket {
}
}
#[cfg(feature = "write")]
impl BitWrite<LittleEndian> for DataTablePacket {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> bitbuffer::Result<()> {
self.tick.write(stream)?;
@ -488,6 +486,7 @@ impl BitWrite<LittleEndian> for DataTablePacket {
}
#[test]
#[cfg(feature = "write")]
fn test_data_table_packet_roundtrip() {
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 crate::demo::data::DemoTick;
use crate::demo::message::{Message, MessageType};
#[cfg(feature = "write")]
use crate::demo::parser::Encode;
use crate::demo::vector::Vector;
use crate::{Parse, ParserState, Result, Stream};
@ -10,7 +13,8 @@ use crate::{Parse, ParserState, Result, Stream};
use tracing::{event, span, Level};
#[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 flags: u32, // TODO
pub view_angles: [ViewAngles; 2],
@ -28,7 +32,8 @@ pub struct MessagePacket<'a> {
}
#[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 origin: Vector,
pub angles: Vector,
@ -36,6 +41,7 @@ pub struct ViewAngles {
}
#[test]
#[cfg(feature = "write")]
fn test_view_angles_roundtrip() {
crate::test_roundtrip_write(ViewAngles::default());
crate::test_roundtrip_write(ViewAngles {
@ -94,6 +100,7 @@ impl<'a> Parse<'a> for MessagePacket<'a> {
}
}
#[cfg(feature = "write")]
impl Encode for MessagePacket<'_> {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
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};
@ -10,6 +12,7 @@ use self::stringtable::StringTablePacket;
use self::synctick::SyncTickPacket;
use self::usercmd::UserCmdPacket;
use crate::demo::data::DemoTick;
#[cfg(feature = "write")]
use crate::demo::parser::Encode;
use serde::{Deserialize, Serialize};
#[cfg(feature = "trace")]
@ -67,7 +70,8 @@ impl Packet<'_> {
}
#[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]
#[repr(u8)]
pub enum PacketType {
@ -123,6 +127,7 @@ impl<'a> Parse<'a> for Packet<'a> {
}
}
#[cfg(feature = "write")]
impl Encode for Packet<'_> {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
#[cfg(feature = "trace")]

View file

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

View file

@ -1,9 +1,12 @@
use crate::demo::data::DemoTick;
use bitbuffer::{BitRead, BitWrite};
use bitbuffer::BitRead;
#[cfg(feature = "write")]
use bitbuffer::BitWrite;
use serde::{Deserialize, Serialize};
#[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 tick: DemoTick,
}

View file

@ -1,5 +1,7 @@
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};
#[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 {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> bitbuffer::Result<()> {
self.tick.write(stream)?;
@ -34,7 +37,8 @@ impl BitWrite<LittleEndian> for UserCmdPacket {
}
#[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 command_number: Option<u32>,
pub tick_count: Option<u32>,
@ -48,7 +52,8 @@ pub struct UserCmd {
}
#[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 {
#[size = 11]
select: u16,

View file

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

View file

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

View file

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