tf_demo_parser/demo/data/
mod.rs

1mod cond;
2pub mod game_state;
3pub mod userinfo;
4
5use bitbuffer::{BitRead, BitReadStream, BitWrite, BitWriteStream, Endianness};
6use parse_display::Display;
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use std::cmp::Ordering;
9use std::fmt::{Debug, Display, Formatter};
10use std::ops::{Add, Sub};
11
12pub use userinfo::UserInfo;
13
14#[derive(Eq, PartialEq, Clone)]
15pub enum MaybeUtf8String {
16    Valid(String),
17    Invalid(Vec<u8>),
18}
19
20impl From<&'_ str> for MaybeUtf8String {
21    fn from(str: &'_ str) -> Self {
22        MaybeUtf8String::Valid(str.into())
23    }
24}
25
26impl Default for MaybeUtf8String {
27    fn default() -> Self {
28        MaybeUtf8String::Valid(String::new())
29    }
30}
31
32impl AsRef<str> for MaybeUtf8String {
33    fn as_ref(&self) -> &str {
34        match self {
35            MaybeUtf8String::Valid(s) => s.as_str(),
36            MaybeUtf8String::Invalid(_) => "-- Malformed utf8 --",
37        }
38    }
39}
40
41impl Debug for MaybeUtf8String {
42    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
43        match self {
44            MaybeUtf8String::Valid(s) => Debug::fmt(s, f),
45            MaybeUtf8String::Invalid(b) => f
46                .debug_struct("MaybeUtf8String::Invalid")
47                .field("data", b)
48                .finish(),
49        }
50    }
51}
52
53impl Display for MaybeUtf8String {
54    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
55        match self {
56            MaybeUtf8String::Valid(s) => Display::fmt(s, f),
57            MaybeUtf8String::Invalid(_) => write!(f, "-- Malformed utf8 --"),
58        }
59    }
60}
61
62impl MaybeUtf8String {
63    pub fn as_bytes(&self) -> &[u8] {
64        match self {
65            MaybeUtf8String::Valid(s) => s.as_bytes(),
66            MaybeUtf8String::Invalid(b) => b.as_ref(),
67        }
68    }
69}
70
71impl<'a, E: Endianness> BitRead<'a, E> for MaybeUtf8String {
72    fn read(stream: &mut BitReadStream<'a, E>) -> bitbuffer::Result<Self> {
73        match String::read(stream) {
74            Ok(str) => Ok(MaybeUtf8String::Valid(str)),
75            Err(bitbuffer::BitError::Utf8Error(_, size)) => {
76                stream.set_pos(stream.pos().saturating_sub(size * 8))?;
77                let mut data: Vec<u8> = stream.read_sized(size)?;
78                while data.last() == Some(&0) {
79                    data.pop();
80                }
81                match String::from_utf8(data) {
82                    Ok(str) => Ok(MaybeUtf8String::Valid(str)),
83                    Err(e) => Ok(MaybeUtf8String::Invalid(e.into_bytes())),
84                }
85            }
86            Err(e) => Err(e),
87        }
88    }
89}
90
91impl<E: Endianness> BitWrite<E> for MaybeUtf8String {
92    fn write(&self, stream: &mut BitWriteStream<E>) -> bitbuffer::Result<()> {
93        stream.write_bytes(self.as_bytes())?;
94        stream.write(&0u8)
95    }
96}
97
98impl From<MaybeUtf8String> for String {
99    fn from(str: MaybeUtf8String) -> String {
100        match str {
101            MaybeUtf8String::Valid(s) => s,
102            MaybeUtf8String::Invalid(_) => "-- Malformed utf8 --".into(),
103        }
104    }
105}
106
107impl Serialize for MaybeUtf8String {
108    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
109    where
110        S: Serializer,
111    {
112        self.as_ref().serialize(serializer)
113    }
114}
115
116impl<'de> Deserialize<'de> for MaybeUtf8String {
117    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
118    where
119        D: Deserializer<'de>,
120    {
121        String::deserialize(deserializer).map(MaybeUtf8String::Valid)
122    }
123}
124
125#[cfg(feature = "schema")]
126impl schemars::JsonSchema for MaybeUtf8String {
127    fn schema_name() -> String {
128        String::schema_name()
129    }
130
131    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
132        String::json_schema(gen)
133    }
134}
135
136/// Tick relative to the start of the game on the server
137#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
138#[derive(
139    Debug,
140    Clone,
141    Copy,
142    Ord,
143    PartialOrd,
144    Eq,
145    PartialEq,
146    BitRead,
147    BitWrite,
148    Serialize,
149    Deserialize,
150    Default,
151    Display,
152)]
153pub struct ServerTick(u32);
154
155impl ServerTick {
156    pub fn range_inclusive(&self, till: Self) -> impl Iterator<Item = Self> {
157        (self.0..=till.0).map(Self::from)
158    }
159}
160
161impl PartialEq<u32> for ServerTick {
162    fn eq(&self, other: &u32) -> bool {
163        *other == self.0
164    }
165}
166
167impl PartialOrd<u32> for ServerTick {
168    fn partial_cmp(&self, other: &u32) -> Option<Ordering> {
169        self.0.partial_cmp(other)
170    }
171}
172
173impl PartialEq<ServerTick> for u32 {
174    fn eq(&self, other: &ServerTick) -> bool {
175        self.eq(&other.0)
176    }
177}
178
179impl PartialOrd<ServerTick> for u32 {
180    fn partial_cmp(&self, other: &ServerTick) -> Option<Ordering> {
181        self.partial_cmp(&other.0)
182    }
183}
184
185impl From<u32> for ServerTick {
186    fn from(tick: u32) -> Self {
187        ServerTick(tick)
188    }
189}
190
191impl From<ServerTick> for u32 {
192    fn from(tick: ServerTick) -> Self {
193        tick.0
194    }
195}
196
197impl Add<u32> for ServerTick {
198    type Output = ServerTick;
199
200    fn add(self, rhs: u32) -> Self::Output {
201        ServerTick(self.0 + rhs)
202    }
203}
204
205impl Add<ServerTick> for ServerTick {
206    type Output = ServerTick;
207
208    fn add(self, rhs: ServerTick) -> Self::Output {
209        ServerTick(self.0 + rhs.0)
210    }
211}
212
213impl Sub<u32> for ServerTick {
214    type Output = ServerTick;
215
216    fn sub(self, rhs: u32) -> Self::Output {
217        ServerTick(self.0 - rhs)
218    }
219}
220
221impl Sub<ServerTick> for ServerTick {
222    type Output = ServerTick;
223
224    fn sub(self, rhs: ServerTick) -> Self::Output {
225        ServerTick(self.0 - rhs.0)
226    }
227}
228
229/// Tick relative to the start of the demo
230#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
231#[derive(
232    Debug,
233    Clone,
234    Copy,
235    Ord,
236    PartialOrd,
237    Eq,
238    PartialEq,
239    BitRead,
240    BitWrite,
241    Serialize,
242    Deserialize,
243    Default,
244    Display,
245)]
246pub struct DemoTick(u32);
247
248impl DemoTick {
249    pub fn range_inclusive(&self, till: Self) -> impl Iterator<Item = Self> {
250        (self.0..=till.0).map(Self::from)
251    }
252}
253
254impl PartialEq<u32> for DemoTick {
255    fn eq(&self, other: &u32) -> bool {
256        *other == self.0
257    }
258}
259
260impl PartialOrd<u32> for DemoTick {
261    fn partial_cmp(&self, other: &u32) -> Option<Ordering> {
262        self.0.partial_cmp(other)
263    }
264}
265
266impl PartialEq<DemoTick> for u32 {
267    fn eq(&self, other: &DemoTick) -> bool {
268        self.eq(&other.0)
269    }
270}
271
272impl PartialOrd<DemoTick> for u32 {
273    fn partial_cmp(&self, other: &DemoTick) -> Option<Ordering> {
274        self.partial_cmp(&other.0)
275    }
276}
277
278impl From<u32> for DemoTick {
279    fn from(tick: u32) -> Self {
280        DemoTick(tick)
281    }
282}
283
284impl From<DemoTick> for u32 {
285    fn from(tick: DemoTick) -> Self {
286        tick.0
287    }
288}
289
290impl Add<u32> for DemoTick {
291    type Output = DemoTick;
292
293    fn add(self, rhs: u32) -> Self::Output {
294        DemoTick(self.0 + rhs)
295    }
296}
297
298impl Add<DemoTick> for DemoTick {
299    type Output = DemoTick;
300
301    fn add(self, rhs: DemoTick) -> Self::Output {
302        DemoTick(self.0 + rhs.0)
303    }
304}
305
306impl Sub<u32> for DemoTick {
307    type Output = DemoTick;
308
309    fn sub(self, rhs: u32) -> Self::Output {
310        DemoTick(self.0 - rhs)
311    }
312}
313
314impl Sub<DemoTick> for DemoTick {
315    type Output = DemoTick;
316
317    fn sub(self, rhs: DemoTick) -> Self::Output {
318        DemoTick(self.0 - rhs.0)
319    }
320}