Skip to main content

tf_demo_parser/demo/data/
mod.rs

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