source_demo_tool/demo_file/
frame.rs

1use std::io::Read;
2
3use crate:: {
4    demo_file::packet::{
5        netmessage::{ NetMessage, SendTableData },
6        PacketData, PacketIndex,
7    },
8    event_data::EventData,
9    parse_tools::{ parse_cstr, parse_i32, parse_u8, parse_u16, parse_u32, },
10};
11
12use source_demo_tool_impl_proc_macros::event;
13
14use buf_redux::BufReader;
15
16#[derive(Debug, Clone)]
17pub struct Frame {
18    pub command: Command,
19    pub tick: i32,
20    pub player_slot: u8,
21}
22
23impl Frame {
24    pub fn from_frame_index(frame_index: FrameIndex) -> Result<Self, &'static str> {
25        let command = frame_index.command_index.try_into()?;
26        let tick = frame_index.tick;
27        let player_slot = frame_index.player_slot;
28
29        Ok(Self {
30            command,
31            tick,
32            player_slot,
33        })
34    }
35}
36
37pub struct FrameIndex {
38    pub command_index: CommandIndex,
39    pub tick: i32,
40    pub player_slot: u8,
41}
42
43impl FrameIndex {
44    pub fn from_readable(mut reader: impl Read) -> Result<Self, EventData> {
45        let command_num = match parse_u8(&mut reader) {
46            Ok(n) => n,
47            Err(_e) => return Err(event!{"couldn't parse command"})
48        };
49
50        let tick = match parse_i32(&mut reader) {
51            Ok(n) => n,
52            Err(_e) => return Err(event!{"couldn't parse tick"})
53        };
54
55        let player_slot = match parse_u8(&mut reader) {
56            Ok(n) => n,
57            Err(_e) => return Err(event!{"couldn't parse player slot"})
58        };
59
60        let command_index = match CommandIndex::from_u8_and_reader(command_num, &mut reader) {
61            Ok(ci) => ci,
62            Err(e) => return Err(e)
63        };
64
65        Ok( Self {
66            command_index,
67            tick,
68            player_slot,
69        })
70    }
71}
72
73#[derive(Debug, Clone)]
74pub enum Command {
75    SignOn(PacketData),
76    Packet(PacketData),
77    SyncTick,
78    //ConsoleCmd,
79    //UserCmd,
80    DataTables(DataTablesData),
81    Stop,
82    //StringTables
83}
84
85impl TryFrom<CommandIndex> for Command {
86    type Error = &'static str;
87    fn try_from(value: CommandIndex) -> Result<Self, Self::Error> {
88        match value {
89            CommandIndex::Packet(pi)      => Ok(Command::Packet(PacketData::from_packet_index(pi))),
90            CommandIndex::SignOn(pi)      => Ok(Command::SignOn(PacketData::from_packet_index(pi))),
91            CommandIndex::SyncTick        => Ok(Command::SyncTick),
92            CommandIndex::DataTables(dti) => Ok(Command::DataTables(DataTablesData::from_data_tables_index(dti)?)),
93            CommandIndex::Stop => Ok(Command::Stop),
94        }
95    }
96}
97
98impl Command {
99    pub fn as_u8(&self) -> u8 {
100        match self {
101            Command::SignOn(_)     => command_id::SIGN_ON,
102            Command::Packet(_)     => command_id::PACKET,
103            Command::SyncTick      => command_id::SYNC_TICK,
104            //Command::ConsoleCmd   => command_id::ConsoleCmd,
105            //Command::UserCmd      => command_id::UserCmd,
106            Command::DataTables(_) => command_id::DATA_TABLES,
107            Command::Stop          => command_id::STOP,
108            //Command::StringTables => command_id::StringTables,
109        }
110    }
111
112    pub fn get_command_str(&self) -> &str {
113        match self {
114            Command::SignOn(_)     =>     "SignOn",
115            Command::Packet(_)     =>     "Packet",
116            Command::SyncTick      =>   "SyncTick",
117            //Command::ConsoleCmd   => command_id::ConsoleCmd,
118            //Command::UserCmd      => command_id::UserCmd,
119            Command::DataTables(_) => "DataTables",
120            Command::Stop          =>       "Stop",
121        }
122    }
123}
124
125pub struct DataTablesIndex {
126    pub data: Vec<u8>
127}
128
129impl DataTablesIndex {
130    pub fn from_readable(mut reader: impl Read) -> Result<Self, String> {
131        let data_len = match parse_u32(&mut reader) {
132            Ok(n) => n,
133            Err(e) => return Err(format!{"parsing data_len: {}", e})
134        };
135
136        let mut data = Vec::new();
137        data.resize(data_len.try_into().unwrap(), 0);
138        reader.read_exact(data.as_mut_slice()).unwrap();
139
140        Ok(Self { data })
141    }
142}
143
144#[derive(Debug, Clone)]
145pub struct DataTablesData {
146    pub send_tables: Vec<SendTableData>,
147    pub class_descriptions: Vec<DataTablesClassDescription>,
148}
149
150#[derive(Debug, Clone)]
151pub struct DataTablesClassDescription {
152    pub     class_id: u16,
153    pub network_name: String,
154    pub   table_name: String,
155}
156
157impl DataTablesData {
158    pub fn from_data_tables_index(dti: DataTablesIndex) -> Result<Self, &'static str> {
159        let mut data_reader = BufReader::with_capacity
160            (dti.data.len(), dti.data.as_slice());
161
162        data_reader.read_into_buf().unwrap();
163
164        // parse SendTable's
165        let mut send_tables = Vec::new();
166        while data_reader.buf_len() > 0 {
167            let net_result = NetMessage::parse_from_bufredux_reader(&mut data_reader);
168
169            let mut message = None;
170            if let Ok((msg, _warn)) = net_result {
171                message = Some(msg);
172            }
173
174            if message.is_none() {
175                return Err("couldn't parse SendTable message")
176            }
177
178            let mut is_end = false;
179            if let NetMessage::SendTable(st) = message.unwrap() {
180                if st.is_end.is_some() {
181                    is_end = st.is_end.unwrap() > 0;
182                }
183                send_tables.push(st);
184            } else {
185                return Err("expected SendTable messages only")
186            }
187
188            if is_end { // breakout to read class descriptions
189                break;
190            }
191        }
192
193        // parse class descriptions
194        let mut class_descriptions = Vec::new();
195        {
196            let class_count = parse_u16(&mut data_reader)?;
197
198            while data_reader.buf_len() > 0 {
199                let class_id = parse_u16(&mut data_reader)?;
200                let network_name = parse_cstr(&mut data_reader)?;
201                let table_name = parse_cstr(&mut data_reader)?;
202
203                class_descriptions.push(DataTablesClassDescription { class_id, network_name, table_name });
204            }
205
206            if class_descriptions.len() != class_count as usize {
207                return Err("too little or too many class descriptions were received")
208            }
209        }
210
211        Ok(Self { send_tables, class_descriptions })
212    }
213}
214
215pub enum CommandIndex {
216    SignOn(PacketIndex),
217    Packet(PacketIndex),
218    SyncTick,
219    DataTables(DataTablesIndex),
220    Stop,
221}
222
223impl CommandIndex {
224    pub fn from_u8_and_reader(num: u8, mut reader: impl Read) -> Result<Self, EventData> {
225        match num {
226            command_id::SIGN_ON => Ok(
227                Self::SignOn(match PacketIndex::from_readable(&mut reader) {
228                    Ok(soi) => soi,
229                    Err(e) => {
230                        let mut ev = event!{""};
231                        ev.details = format!("SignOnIndex parse error: {}", e);
232                        return Err(ev)
233                    }
234                })
235            ),
236            command_id::PACKET => Ok(
237                Self::Packet(match PacketIndex::from_readable(&mut reader) {
238                    Ok(pi) => pi,
239                    Err(e) => {
240                        let mut ev = event!{""};
241                        ev.details = format!("PacketIndex parse error: {}", e);
242                        return Err(ev)
243                    }
244                })
245            ),
246            command_id::SYNC_TICK => Ok(Self::SyncTick),
247            command_id::DATA_TABLES => Ok(
248                Self::DataTables(match DataTablesIndex::from_readable(&mut reader) {
249                    Ok(dti) => dti,
250                    Err(e) => {
251                        let mut ev = event!{""};
252                        ev.details = format!("DataTablesIndex parse error: {}", e);
253                        return Err(ev)
254                    }
255                })
256            ),
257            command_id::STOP => Ok(Self::Stop),
258            _ => {
259                let mut ev = event!{""};
260                ev.details = format!{"unsupported command number: {}", num};
261                return Err(ev)
262            }
263        }
264    }
265}
266
267mod command_id {
268    pub const      SIGN_ON: u8 = 1;
269    pub const       PACKET: u8 = 2;
270    pub const    SYNC_TICK: u8 = 3;
271    //pub const  CONSOLE_CMD: u8 = 4;
272    //pub const     USER_CMD: u8 = 5;
273    pub const  DATA_TABLES: u8 = 6;
274    pub const         STOP: u8 = 7;
275    //pub const STRING_TABLE: u8 = 8;
276}