tf_demo_parser/demo/packet/
mod.rs

1use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian};
2
3use crate::{Parse, ParserState, Result, Stream};
4
5use self::consolecmd::ConsoleCmdPacket;
6use self::datatable::DataTablePacket;
7use self::message::MessagePacket;
8use self::stop::StopPacket;
9use self::stringtable::StringTablePacket;
10use self::synctick::SyncTickPacket;
11use self::usercmd::UserCmdPacket;
12use crate::demo::data::DemoTick;
13use crate::demo::parser::Encode;
14use serde::{Deserialize, Serialize};
15#[cfg(feature = "trace")]
16use tracing::{event, span, Level};
17
18pub mod consolecmd;
19pub mod datatable;
20pub mod message;
21pub mod stop;
22pub mod stringtable;
23pub mod synctick;
24pub mod usercmd;
25
26#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
27#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
28#[serde(bound(deserialize = "'a: 'static"))]
29#[serde(tag = "type")]
30pub enum Packet<'a> {
31    Signon(MessagePacket<'a>),
32    Message(MessagePacket<'a>),
33    SyncTick(SyncTickPacket),
34    ConsoleCmd(ConsoleCmdPacket),
35    UserCmd(UserCmdPacket),
36    DataTables(DataTablePacket),
37    Stop(StopPacket),
38    StringTables(StringTablePacket<'a>),
39}
40
41impl Packet<'_> {
42    pub fn tick(&self) -> DemoTick {
43        match self {
44            Packet::Signon(msg) => msg.tick,
45            Packet::Message(msg) => msg.tick,
46            Packet::SyncTick(msg) => msg.tick,
47            Packet::ConsoleCmd(msg) => msg.tick,
48            Packet::UserCmd(msg) => msg.tick,
49            Packet::DataTables(msg) => msg.tick,
50            Packet::Stop(msg) => msg.tick,
51            Packet::StringTables(msg) => msg.tick,
52        }
53    }
54
55    pub fn set_tick(&mut self, tick: DemoTick) {
56        match self {
57            Packet::Signon(msg) => msg.tick = tick,
58            Packet::Message(msg) => msg.tick = tick,
59            Packet::SyncTick(msg) => msg.tick = tick,
60            Packet::ConsoleCmd(msg) => msg.tick = tick,
61            Packet::UserCmd(msg) => msg.tick = tick,
62            Packet::DataTables(msg) => msg.tick = tick,
63            Packet::Stop(msg) => msg.tick = tick,
64            Packet::StringTables(msg) => msg.tick = tick,
65        }
66    }
67}
68
69#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
70#[derive(BitRead, BitWrite, Debug, Clone, Copy, Eq, PartialEq)]
71#[discriminant_bits = 8]
72#[repr(u8)]
73pub enum PacketType {
74    Signon = 1,
75    Message = 2,
76    SyncTick = 3,
77    ConsoleCmd = 4,
78    UserCmd = 5,
79    DataTables = 6,
80    Stop = 7,
81    StringTables = 8,
82}
83
84impl Packet<'_> {
85    pub fn packet_type(&self) -> PacketType {
86        match self {
87            Packet::Signon(_) => PacketType::Signon,
88            Packet::Message(_) => PacketType::Message,
89            Packet::SyncTick(_) => PacketType::SyncTick,
90            Packet::ConsoleCmd(_) => PacketType::ConsoleCmd,
91            Packet::UserCmd(_) => PacketType::UserCmd,
92            Packet::DataTables(_) => PacketType::DataTables,
93            Packet::Stop(_) => PacketType::Stop,
94            Packet::StringTables(_) => PacketType::StringTables,
95        }
96    }
97}
98
99impl<'a> Parse<'a> for Packet<'a> {
100    fn parse(stream: &mut Stream<'a>, state: &ParserState) -> Result<Self> {
101        let packet_type = PacketType::read(stream)?;
102        #[cfg(feature = "trace")]
103        {
104            let tick: u32 = stream.read()?;
105            stream.set_pos(stream.pos() - 32)?;
106            let _span =
107                span!(Level::INFO, "reading packet", packet_type = ?packet_type, tick = tick)
108                    .entered();
109            event!(Level::DEBUG, "parsing packet");
110        }
111        Ok(match packet_type {
112            PacketType::Signon => Packet::Signon(MessagePacket::parse(stream, state)?),
113            PacketType::Message => Packet::Message(MessagePacket::parse(stream, state)?),
114            PacketType::SyncTick => Packet::SyncTick(SyncTickPacket::parse(stream, state)?),
115            PacketType::ConsoleCmd => Packet::ConsoleCmd(ConsoleCmdPacket::parse(stream, state)?),
116            PacketType::UserCmd => Packet::UserCmd(UserCmdPacket::parse(stream, state)?),
117            PacketType::DataTables => Packet::DataTables(DataTablePacket::parse(stream, state)?),
118            PacketType::Stop => Packet::Stop(StopPacket::parse(stream, state)?),
119            PacketType::StringTables => {
120                Packet::StringTables(StringTablePacket::parse(stream, state)?)
121            }
122        })
123    }
124}
125
126impl Encode for Packet<'_> {
127    fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
128        #[cfg(feature = "trace")]
129        let _span = span!(Level::INFO, "encoding packet", packet_type = ?self.packet_type(), tick = ?self.tick()).entered();
130        self.packet_type().write(stream)?;
131        match self {
132            Packet::Signon(inner) => inner.encode(stream, state),
133            Packet::Message(inner) => inner.encode(stream, state),
134            Packet::SyncTick(inner) => inner.encode(stream, state),
135            Packet::ConsoleCmd(inner) => inner.encode(stream, state),
136            Packet::UserCmd(inner) => inner.encode(stream, state),
137            Packet::DataTables(inner) => inner.encode(stream, state),
138            Packet::Stop(inner) => inner.encode(stream, state),
139            Packet::StringTables(inner) => inner.encode(stream, state),
140        }
141    }
142}
143
144impl PacketType {
145    pub fn as_str(&self) -> &'static str {
146        match self {
147            PacketType::Signon => "Signon",
148            PacketType::Message => "Message",
149            PacketType::SyncTick => "SyncTick",
150            PacketType::ConsoleCmd => "ConsoleCmd",
151            PacketType::UserCmd => "UserCmd",
152            PacketType::DataTables => "DataTables",
153            PacketType::Stop => "Stop",
154            PacketType::StringTables => "StringTables",
155        }
156    }
157
158    pub fn as_lowercase_str(&self) -> &'static str {
159        match self {
160            PacketType::Signon => "signon",
161            PacketType::Message => "message",
162            PacketType::SyncTick => "synctick",
163            PacketType::ConsoleCmd => "consolecmd",
164            PacketType::UserCmd => "usercmd",
165            PacketType::DataTables => "datatables",
166            PacketType::Stop => "stop",
167            PacketType::StringTables => "stringtables",
168        }
169    }
170}