use super::stringtable::read_var_int; use crate::demo::message::packetentities::PacketEntitiesMessage; #[cfg(feature = "write")] use crate::demo::message::stringtable::encode_var_int_fixed; use crate::demo::packet::datatable::ClassId; #[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}; #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub struct TempEntitiesMessage { pub events: Vec, } #[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, } impl Parse<'_> for TempEntitiesMessage { fn parse(stream: &mut Stream, state: &ParserState) -> Result { 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 = 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 = state.server_class_bits; (stream.read_sized::(bits)?.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(()) } } #[cfg(feature = "write")] impl Encode for TempEntitiesMessage { fn encode(&self, stream: &mut BitWriteStream, 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)?; // threshold and both widths are the ones used by the read side above let (length_bits, encode_length): (usize, fn(u32) -> u64) = if state.protocol_version > 23 { (40, encode_var_int_fixed) } else { (17, |length| length as u64) }; stream.reserve_int::(length_bits, |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 = state.server_class_bits; let id: u16 = event.class_id.into(); (id + 1).write_sized(stream, bits)?; } 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_length((end - start) as u32)) })?; Ok(()) } }