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