diff --git a/src/demo/parser/state.rs b/src/demo/parser/state.rs index c0a7fe9..e8e40d3 100644 --- a/src/demo/parser/state.rs +++ b/src/demo/parser/state.rs @@ -70,6 +70,26 @@ impl StaticBaseline { )?; Ok(props) } + + /// Re-encode the baseline from one send table to another. + /// + /// Baselines are packed against a specific table, so any edit that changes + /// how a prop encodes leaves them readable at the wrong offsets. + #[cfg(feature = "write")] + pub fn reencode(&self, from: &SendTable, to: &SendTable) -> Result> { + use bitbuffer::{BitReadBuffer, BitReadStream, BitWriteStream, LittleEndian}; + + let props = self.parse(from)?; + let mut bytes = Vec::new(); + { + let mut out = BitWriteStream::new(&mut bytes, LittleEndian); + PacketEntitiesMessage::write_update(&props, &mut out, to, 0u32.into())?; + } + Ok(BitReadStream::new(BitReadBuffer::new_owned( + bytes, + LittleEndian, + ))) + } } impl ParserState { @@ -424,3 +444,72 @@ impl From for PacketEntity { } } } + +#[test] +#[cfg(feature = "write")] +fn test_static_baseline_reencode() { + use crate::demo::packet::datatable::SendTable; + use crate::demo::sendprop::{SendPropDefinition, SendPropParseDefinition, SendPropValue}; + use bitbuffer::{BitReadBuffer, BitReadStream, BitWriteStream, LittleEndian}; + + fn table(first_prop_bits: u8) -> SendTable { + SendTable { + name: SendTableName::from("table"), + needs_decoder: false, + flattened_props: vec![ + SendPropDefinition { + identifier: SendPropIdentifier::new("table", "first"), + parse_definition: SendPropParseDefinition::UnsignedInt { + changes_often: false, + bit_count: first_prop_bits, + }, + }, + SendPropDefinition { + identifier: SendPropIdentifier::new("table", "second"), + parse_definition: SendPropParseDefinition::UnsignedInt { + changes_often: false, + bit_count: 8, + }, + }, + ], + } + } + + let from = table(8); + let to = table(16); + let props = vec![ + SendProp { + index: 0, + identifier: SendPropIdentifier::new("table", "first"), + value: SendPropValue::Integer(200), + }, + SendProp { + index: 1, + identifier: SendPropIdentifier::new("table", "second"), + value: SendPropValue::Integer(37), + }, + ]; + + let mut bytes = Vec::new(); + { + let mut out = BitWriteStream::new(&mut bytes, LittleEndian); + PacketEntitiesMessage::write_update(&props, &mut out, &from, 0u32.into()).unwrap(); + } + let baseline = StaticBaseline::new( + ClassId::from(0u16), + BitReadStream::new(BitReadBuffer::new_owned(bytes, LittleEndian)), + ); + + assert_eq!(baseline.parse(&from).unwrap(), props); + + // the old blob no longer decodes to the same values + if let Ok(misread) = baseline.parse(&to) { + assert_ne!(misread, props); + } + + let fixed = StaticBaseline::new( + ClassId::from(0u16), + baseline.reencode(&from, &to).unwrap(), + ); + assert_eq!(fixed.parse(&to).unwrap(), props); +}