tf-demo-parser 0.6.4

parser for tf2 demo files
Documentation
use super::stringtable::read_var_int;
use crate::demo::message::packetentities::PacketEntitiesMessage;
use crate::demo::message::stringtable::{encode_var_int_fixed, log_base2};
use crate::demo::packet::datatable::ClassId;
use crate::demo::parser::{Encode, ParseBitSkip};
use crate::demo::sendprop::SendProp;
use crate::Result;
use crate::{Parse, ParseError, ParserState, Stream};
use bitbuffer::{BitWrite, BitWriteSized, BitWriteStream, LittleEndian};
use serde::{Deserialize, Serialize};

#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct TempEntitiesMessage {
    pub events: Vec<EventInfo>,
}

#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct EventInfo {
    pub class_id: ClassId,
    pub fire_delay: f32,
    pub reliable: bool,
    pub props: Vec<SendProp>,
}

impl Parse<'_> for TempEntitiesMessage {
    fn parse(stream: &mut Stream, state: &ParserState) -> Result<Self> {
        let count: u8 = stream.read()?;
        let length = if state.protocol_version > 23 {
            read_var_int(stream)?
        } else {
            stream.read_sized(17)?
        };
        let data = stream.read_bits(length as usize)?;
        let mut stream = data.clone();
        let stream = &mut stream;

        let (count, reliable) = if count == 0 {
            (1, true)
        } else {
            (count, false)
        };

        let mut events: Vec<EventInfo> = Vec::with_capacity(count as usize);

        for _ in 0..count {
            let delay = if stream.read()? {
                let raw: u8 = stream.read()?;
                raw as f32 / 100.0
            } else {
                0.0
            };

            let class_id = if stream.read()? {
                let bits = log_base2(state.server_classes.len()) + 1;
                (stream.read_sized::<u16>(bits as usize)?.saturating_sub(1)).into()
            } else {
                let last = events.last().ok_or(ParseError::InvalidDemo(
                    "temp entity update without previous",
                ))?;

                last.class_id
            };
            let send_table = state
                .send_tables
                .get(usize::from(class_id))
                .ok_or(ParseError::UnknownServerClass(class_id))?;

            let mut props = Vec::new();
            PacketEntitiesMessage::read_update(stream, send_table, &mut props, 0u32.into())?;

            events.push(EventInfo {
                class_id,
                fire_delay: delay,
                reliable,
                props,
            });
        }

        Ok(TempEntitiesMessage { events })
    }
}

impl ParseBitSkip<'_> for TempEntitiesMessage {
    fn parse_skip(stream: &mut Stream, state: &ParserState) -> Result<()> {
        let _: u8 = stream.read()?;
        let length = if state.protocol_version > 23 {
            read_var_int(stream)?
        } else {
            stream.read_sized(17)?
        };
        stream.skip_bits(length as usize)?;
        Ok(())
    }
}

impl Encode for TempEntitiesMessage {
    fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
        let count = match (self.events.len(), self.events.first()) {
            (1, Some(event)) if event.reliable => 0,
            (1, _) => 1,
            (len, _) => len as u8,
        };
        count.write(stream)?;

        stream.reserve_int::<ParseError, _>(40, |stream| {
            let start = stream.bit_len();
            let mut last_class_id = u16::MAX.into();

            for event in self.events.iter() {
                if event.fire_delay > 0.0 {
                    true.write(stream)?;
                    ((event.fire_delay * 100.0) as u8).write(stream)?;
                } else {
                    false.write(stream)?;
                }

                if event.class_id != last_class_id {
                    true.write(stream)?;
                    let bits = log_base2(state.server_classes.len()) + 1;
                    let id: u16 = event.class_id.into();
                    (id + 1).write_sized(stream, bits as usize)?;
                } else {
                    false.write(stream)?;
                }
                last_class_id = event.class_id;

                let send_table = state
                    .send_tables
                    .get(usize::from(event.class_id))
                    .ok_or(ParseError::UnknownServerClass(event.class_id))?;
                PacketEntitiesMessage::write_update(&event.props, stream, send_table, 0u32.into())?;
            }
            let end = stream.bit_len();
            Ok(encode_var_int_fixed((end - start) as u32))
        })?;
        Ok(())
    }
}