libtw2_demo/ddnet/
reader.rs1use libtw2_gamenet_common::snap_obj::TypeId;
2use libtw2_gamenet_common::traits;
3use libtw2_gamenet_common::traits::MessageExt as _;
4use libtw2_gamenet_common::traits::Protocol;
5use libtw2_gamenet_common::traits::ProtocolStatic;
6use libtw2_packer::IntUnpacker;
7use libtw2_packer::Unpacker;
8use libtw2_snapshot::snap;
9use libtw2_snapshot::Delta;
10use libtw2_snapshot::Snap;
11use libtw2_snapshot::SnapReader;
12use std::collections::HashMap;
13use std::io;
14use std::marker::PhantomData;
15use std::mem;
16use std::slice;
17use thiserror::Error;
18use uuid::Uuid;
19use warn::wrap;
20use warn::Warn;
21
22use crate::format;
23use crate::reader;
24use crate::RawChunk;
25
26#[derive(Error, Debug)]
27pub enum ReadError {
28 #[error(transparent)]
29 Inner(#[from] reader::ReadError),
30 #[error("Snap parsing - {0:?}")]
31 Snap(snap::Error),
32 #[error("Uuid item has an incorrect size")]
33 UuidItemLength,
34 #[error("Uuid type id that is not registered")]
35 UnregisteredUuidTypeId,
36 #[error("Chunk types are not in the proper order")]
37 ChunkOrder,
38}
39
40pub struct DemoReader<P: for<'a> Protocol<'a>> {
41 raw: reader::Reader,
42 delta: Delta,
43 snap: Snap,
44 old_snap: Snap,
45 snap_reader: SnapReader,
46 snapshot: Snapshot<P::SnapObj>,
47 protocol: PhantomData<P>,
48}
49
50#[derive(Debug)]
51pub enum Warning {
52 Demo(format::Warning),
53 Snapshot(libtw2_snapshot::format::Warning),
54 Packer(libtw2_packer::Warning),
55 ExcessItemData,
56 Gamenet(libtw2_gamenet_common::error::Error),
57}
58
59impl From<format::Warning> for Warning {
60 fn from(w: format::Warning) -> Self {
61 Warning::Demo(w)
62 }
63}
64impl From<libtw2_snapshot::format::Warning> for Warning {
65 fn from(w: libtw2_snapshot::format::Warning) -> Self {
66 Warning::Snapshot(w)
67 }
68}
69impl From<libtw2_packer::Warning> for Warning {
70 fn from(w: libtw2_packer::Warning) -> Self {
71 Warning::Packer(w)
72 }
73}
74impl From<libtw2_packer::ExcessData> for Warning {
75 fn from(_: libtw2_packer::ExcessData) -> Self {
76 Warning::ExcessItemData
77 }
78}
79
80pub enum Chunk<'a, P: Protocol<'a>> {
81 Message(P::Game),
82 Snapshot(slice::Iter<'a, (P::SnapObj, u16)>),
83 Tick(i32),
84 Invalid,
85}
86
87impl<P: for<'a> Protocol<'a>> DemoReader<P> {
88 pub fn new<R, W>(data: R, warn: &mut W) -> Result<Self, ReadError>
89 where
90 R: io::Read + io::Seek + 'static,
91 W: Warn<Warning>,
92 {
93 let reader = reader::Reader::new(data, wrap(warn))?;
94 Ok(DemoReader {
95 raw: reader,
96 delta: Delta::new(),
97 snap: Snap::empty(),
98 old_snap: Snap::empty(),
99 snap_reader: SnapReader::new(),
100 snapshot: Snapshot::default(),
101 protocol: PhantomData,
102 })
103 }
104
105 pub fn next_chunk<W: Warn<Warning>>(
106 &mut self,
107 warn: &mut W,
108 ) -> Result<Option<Chunk<P>>, ReadError> {
109 match self.raw.read_chunk(wrap(warn))? {
110 None => return Ok(None),
111 Some(RawChunk::Unknown) => Ok(Some(Chunk::Invalid)),
112 Some(RawChunk::Tick { tick, .. }) => Ok(Some(Chunk::Tick(tick))),
113 Some(RawChunk::Message(msg)) => {
114 let mut unpacker = Unpacker::new_from_demo(msg);
115 match P::Game::decode(wrap(warn), &mut unpacker) {
116 Ok(msg) => Ok(Some(Chunk::Message(msg))),
117 Err(err) => {
118 warn.warn(Warning::Gamenet(err));
119 Ok(Some(Chunk::Invalid))
120 }
121 }
122 }
123 Some(RawChunk::Snapshot(snap)) => {
124 let mut unpacker = Unpacker::new(snap);
125 let mut swap = Snap::empty();
126 mem::swap(&mut self.snap, &mut swap);
127 self.snap = self
128 .snap_reader
129 .read(wrap(warn), swap, &mut unpacker)
130 .unwrap();
131 self.snapshot.build::<P, _>(warn, &self.snap)?;
132 Ok(Some(Chunk::Snapshot(self.snapshot.objects.iter())))
133 }
134 Some(RawChunk::SnapshotDelta(dt)) => {
135 let mut unpacker = Unpacker::new(dt);
136 self.delta
137 .read(wrap(warn), P::obj_size, &mut unpacker)
138 .map_err(ReadError::Snap)?;
139 self.old_snap
140 .read_with_delta(wrap(warn), &self.snap, &self.delta)
141 .map_err(ReadError::Snap)?;
142 mem::swap(&mut self.old_snap, &mut self.snap);
143 self.snapshot.build::<P, _>(warn, &self.snap)?;
144 Ok(Some(Chunk::Snapshot(self.snapshot.objects.iter())))
145 }
146 }
147 }
148
149 pub fn inner(&self) -> &reader::Reader {
150 &self.raw
151 }
152}
153
154struct Snapshot<T> {
155 uuid_index: HashMap<u16, Uuid>,
156 pub objects: Vec<(T, u16)>,
157}
158
159impl<T> Default for Snapshot<T> {
160 fn default() -> Snapshot<T> {
161 Snapshot {
162 uuid_index: Default::default(),
163 objects: Default::default(),
164 }
165 }
166}
167
168impl<T> Snapshot<T> {
169 fn build<P, W>(&mut self, warn: &mut W, snap: &Snap) -> Result<(), ReadError>
170 where
171 P: ProtocolStatic<SnapObj = T>,
172 T: traits::SnapObj,
173 W: Warn<Warning>,
174 {
175 self.uuid_index.clear();
176 self.objects.clear();
177
178 for item in snap.items().filter(|item| item.type_id == 0) {
180 let mut uuid_bytes = [0; 16];
181 if item.data.len() != 4 {
182 return Err(ReadError::UuidItemLength);
183 }
184 for (b, x) in uuid_bytes.chunks_mut(4).zip(item.data) {
185 b.copy_from_slice(&x.to_be_bytes());
186 }
187 let uuid = Uuid::from_bytes(uuid_bytes);
188 self.uuid_index.insert(item.id, uuid);
189 }
190
191 for item in snap.items().filter(|item| item.type_id != 0) {
192 let type_id = if item.type_id < u16::MAX / 4 {
193 TypeId::Ordinal(item.type_id)
194 } else {
195 let uuid = self
196 .uuid_index
197 .get(&item.type_id)
198 .ok_or(ReadError::UnregisteredUuidTypeId)?;
199 TypeId::Uuid(*uuid)
200 };
201 let mut int_unpacker = IntUnpacker::new(item.data);
202 match P::SnapObj::decode_obj(wrap(warn), type_id, &mut int_unpacker) {
203 Ok(obj) => self.objects.push((obj, item.id)),
204 Err(err) => warn.warn(Warning::Gamenet(err)),
205 }
206 }
207
208 Ok(())
209 }
210}