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

entity write fixes

This commit is contained in:
Robin Appelman 2021-07-20 19:27:24 +02:00
commit 577a998baa
17 changed files with 129 additions and 35 deletions

44
src/bin/reencode.rs Normal file
View file

@ -0,0 +1,44 @@
use std::env;
use std::fs;
use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian};
use main_error::MainError;
use tf_demo_parser::demo::header::Header;
use tf_demo_parser::demo::parser::{DemoHandler, Encode, NullHandler, RawPacketStream};
use tf_demo_parser::Demo;
fn main() -> Result<(), MainError> {
#[cfg(feature = "better_panic")]
better_panic::install();
let args: Vec<_> = env::args().collect();
if args.len() < 3 {
println!("2 argument required");
return Ok(());
}
let path = args[1].clone();
let out_path = args[2].clone();
let file = fs::read(path)?;
let mut out_buffer = Vec::with_capacity(file.len());
{
let mut out_stream = BitWriteStream::new(&mut out_buffer, LittleEndian);
let demo = Demo::new(&file);
let mut stream = demo.get_stream();
let header = Header::read(&mut stream)?;
header.write(&mut out_stream)?;
let mut packets = RawPacketStream::new(stream);
let mut handler = DemoHandler::parse_all_with_analyser(NullHandler);
while let Some(packet) = packets.next(&handler.state_handler)? {
packet.encode(&mut out_stream, &handler.state_handler)?;
handler.handle_packet(packet)?;
}
}
fs::write(out_path, out_buffer)?;
Ok(())
}

View file

@ -2,37 +2,37 @@ use crate::Stream;
/// Messages that consists only of primitives and string and can be derived
use bitbuffer::{BitRead, BitWrite, LittleEndian};
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
pub struct FileMessage {
pub transfer_id: u32,
pub file_name: String,
pub requested: bool,
}
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
pub struct NetTickMessage {
pub tick: u32,
pub frame_time: u16,
pub std_dev: u16,
}
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
pub struct StringCmdMessage {
pub command: String,
}
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
pub struct SigOnStateMessage {
pub state: u8,
pub count: u32,
}
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
pub struct PrintMessage {
pub value: String,
}
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
pub struct ServerInfoMessage {
pub version: u16,
pub server_count: u32,
@ -53,18 +53,18 @@ pub struct ServerInfoMessage {
pub replay: bool,
}
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
pub struct SetPauseMessage {
pub pause: bool,
}
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
pub struct SetViewMessage {
#[size = 11]
pub index: u16,
}
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
pub struct FixAngleMessage {
pub relative: bool,
pub x: u16,
@ -72,7 +72,7 @@ pub struct FixAngleMessage {
pub z: u16,
}
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
#[endianness = "LittleEndian"]
pub struct EntityMessage<'a> {
#[size = 11]
@ -85,13 +85,13 @@ pub struct EntityMessage<'a> {
pub data: Stream<'a>,
}
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
pub struct PreFetchMessage {
#[size = 14]
pub index: u16,
}
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
#[endianness = "LittleEndian"]
pub struct MenuMessage<'a> {
pub kind: u16,
@ -100,13 +100,13 @@ pub struct MenuMessage<'a> {
pub index: Stream<'a>,
}
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
pub struct GetCvarValueMessage {
pub cookie: u32,
pub value: String,
}
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
#[endianness = "LittleEndian"]
pub struct CmdKeyValuesMessage<'a> {
pub length: u32,

View file

@ -73,7 +73,7 @@ pub enum MessageType {
CmdKeyValues = 32,
}
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum Message<'a> {
Empty,
File(FileMessage),

View file

@ -94,10 +94,10 @@ impl PacketEntity {
}
pub fn diff_from_baseline<'a>(
&self,
&'a self,
baseline: &'a [SendProp],
) -> impl Iterator<Item = &'a SendProp> + 'a {
baseline.iter().filter(move |prop| {
self.props.iter().filter(move |prop| {
!baseline
.iter()
.any(|base_prop| base_prop.index == prop.index && base_prop.value == prop.value)
@ -213,6 +213,7 @@ impl Parse<'_> for PacketEntitiesMessage {
let updated_entries: u16 = stream.read_sized(11)?;
let length: u32 = stream.read_sized(20)?;
let updated_base_line = stream.read()?;
let mut data = stream.read_bits(length as usize)?;
let mut entities = Vec::with_capacity(min(updated_entries, 128) as usize);
@ -319,7 +320,7 @@ impl Encode for PacketEntitiesMessage {
let length_end = stream.bit_len();
(length_end - length_start).write_sized(length_stream, 11)?;
(length_end - length_start).write_sized(length_stream, 20)?;
Ok(())
})
@ -558,6 +559,24 @@ fn test_packet_entitier_message_roundtrip() {
serial_number: 0,
delay: None,
},
PacketEntity {
server_class: ClassId::from(1),
entity_index: EntityId::from(5),
props: vec![
SendProp {
index: SendPropIdentifier::new("table2", "prop1"),
value: SendPropValue::Integer(4),
},
SendProp {
index: SendPropIdentifier::new("table2", "prop3"),
value: SendPropValue::Float(1.0),
},
],
in_pvs: true,
pvs: PVS::Enter,
serial_number: 0,
delay: None,
},
],
removed_entities: vec![],
max_entries: 4,

View file

@ -5,7 +5,7 @@ use super::stringtable::read_var_int;
use crate::demo::message::stringtable::write_var_int;
use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian};
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct TempEntitiesMessage<'a> {
pub count: u8,
pub data: Stream<'a>,

View file

@ -57,7 +57,7 @@ fn test_voice_init_roundtrip() {
});
}
#[derive(BitRead, BitWrite, Debug, Clone)]
#[derive(BitRead, BitWrite, Debug, Clone, PartialEq)]
#[endianness = "LittleEndian"]
pub struct VoiceDataMessage<'a> {
client: u8,

View file

@ -2,7 +2,7 @@ use bitbuffer::{BitRead, BitWrite, BitWriteSized, LittleEndian};
use crate::{ReadResult, Stream};
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct ConsoleCmdPacket {
tick: u32,
command: String,

View file

@ -7,7 +7,7 @@ use crate::demo::parser::Encode;
use crate::demo::vector::Vector;
use crate::{Parse, ParserState, ReadResult, Result, Stream};
#[derive(Debug, BitRead, BitWrite)]
#[derive(Debug, BitRead, BitWrite, PartialEq)]
pub struct MessagePacketMeta {
pub flags: u32, // TODO
pub view_angles: ViewAngles,
@ -15,11 +15,11 @@ pub struct MessagePacketMeta {
pub sequence_out: u32,
}
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct MessagePacket<'a> {
pub tick: u32,
pub messages: Vec<Message<'a>>,
pub meta: LazyBitRead<'a, MessagePacketMeta, LittleEndian>,
pub meta: MessagePacketMeta,
}
#[derive(Clone, Debug, PartialEq)]
@ -119,7 +119,7 @@ impl<'a> Parse<'a> for MessagePacket<'a> {
let mut messages = Vec::with_capacity(8);
while packet_data.bits_left() > 6 {
let message_type = MessageType::parse(&mut packet_data, state)?;
let message_type = MessageType::read(&mut packet_data)?;
if state.should_parse_message(message_type) {
messages.push(Message::from_type(message_type, &mut packet_data, state)?);
@ -140,7 +140,7 @@ impl<'a> Parse<'a> for MessagePacket<'a> {
impl Encode for MessagePacket<'_> {
fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
self.tick.write(stream)?;
self.meta.read()?.write(stream)?;
self.meta.write(stream)?;
stream.reserve_byte_length(32, |stream| {
for message in self.messages.iter() {
message.get_message_type().write(stream)?;

View file

@ -20,7 +20,7 @@ pub mod stringtable;
pub mod synctick;
pub mod usercmd;
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum Packet<'a> {
Sigon(MessagePacket<'a>),
Message(MessagePacket<'a>),
@ -32,7 +32,7 @@ pub enum Packet<'a> {
StringTables(StringTablePacket<'a>),
}
#[derive(BitRead, BitWrite, TryFromPrimitive, Debug, Clone, Copy)]
#[derive(BitRead, BitWrite, TryFromPrimitive, Debug, Clone, Copy, Eq, PartialEq)]
#[discriminant_bits = 8]
#[repr(u8)]
pub enum PacketType {

View file

@ -1,4 +1,4 @@
use bitbuffer::{BitRead, BitWrite};
#[derive(Debug, BitRead, BitWrite)]
#[derive(Debug, BitRead, BitWrite, PartialEq)]
pub struct StopPacket;

View file

@ -16,7 +16,7 @@ pub struct FixedUserDataSize {
pub bits: u8,
}
#[derive(Debug, PartialEq)]
#[derive(Debug)]
pub struct StringTable<'a> {
pub name: Cow<'a, str>,
pub entries: Vec<(u16, StringTableEntry<'a>)>,
@ -26,6 +26,17 @@ pub struct StringTable<'a> {
pub compressed: bool,
}
impl PartialEq for StringTable<'_> {
fn eq(&self, other: &Self) -> bool {
// ignore `compresses` until we encode compressed
self.name.eq(&other.name)
&& (self.entries.eq(&other.entries))
&& (self.max_entries.eq(&other.max_entries))
&& (self.fixed_user_data_size.eq(&other.fixed_user_data_size))
&& (self.client_entries.eq(&other.client_entries))
}
}
impl StringTable<'_> {
pub fn get_table_meta(&self) -> StringTableMeta {
StringTableMeta {

View file

@ -1,6 +1,6 @@
use bitbuffer::{BitRead, BitWrite};
#[derive(BitRead, BitWrite, Debug)]
#[derive(BitRead, BitWrite, Debug, PartialEq)]
pub struct SyncTickPacket {
pub tick: u32,
}

View file

@ -1,7 +1,7 @@
use crate::Stream;
use bitbuffer::{BitRead, BitWrite, LittleEndian};
#[derive(Debug, BitRead, BitWrite)]
#[derive(Debug, BitRead, BitWrite, PartialEq)]
#[endianness = "LittleEndian"]
pub struct UserCmdPacket<'a> {
tick: u32,

View file

@ -26,6 +26,20 @@ pub trait BorrowMessageHandler: MessageHandler {
fn borrow_output(&self, state: &ParserState) -> &Self::Output;
}
pub struct NullHandler;
impl MessageHandler for NullHandler {
type Output = ();
fn does_handle(_message_type: MessageType) -> bool {
false
}
fn into_output(self, _state: &ParserState) -> Self::Output {
()
}
}
#[derive(Clone)]
pub struct DemoHandler<'a, T: MessageHandler> {
pub tick: u32,

View file

@ -7,7 +7,7 @@ use crate::demo::header::Header;
use crate::demo::packet::Packet;
use crate::demo::parser::analyser::Analyser;
pub use crate::demo::parser::analyser::MatchState;
pub use crate::demo::parser::handler::{DemoHandler, MessageHandler};
pub use crate::demo::parser::handler::{DemoHandler, MessageHandler, NullHandler};
pub use crate::demo::parser::state::ParserState;
use crate::Stream;

View file

@ -1040,6 +1040,12 @@ impl SendPropIdentifier {
}
}
impl From<u64> for SendPropIdentifier {
fn from(raw: u64) -> Self {
SendPropIdentifier(raw)
}
}
#[derive(Debug, Clone, Display, PartialEq)]
#[display("{index} = {value}")]
pub struct SendProp {

View file

@ -65,12 +65,12 @@ fn test_roundtrip_encode<
};
let mut read = BitReadStream::new(BitReadBuffer::new_owned(data, LittleEndian));
assert_eq!(
pretty_assertions::assert_eq!(
val,
T::parse(&mut read, state).unwrap(),
"Failed to assert the parsed message is equal to the original"
);
assert_eq!(
pretty_assertions::assert_eq!(
pos,
read.pos(),
"Failed to assert that all encoded bits ({}) are used for decoding ({})",