1
0
Fork 0
mirror of https://codeberg.org/demostf/parser.git synced 2026-06-03 18:24:05 +02:00

track rounds

This commit is contained in:
Robin Appelman 2019-03-04 21:01:24 +01:00
commit 713ab0de42
12 changed files with 105 additions and 84 deletions

View file

@ -13,7 +13,7 @@ fn main() -> std::result::Result<(), Box<ParseError>> {
//dbg!(header); //dbg!(header);
//dbg!(state.deaths); //dbg!(state.deaths);
//std::thread::sleep(std::time::Duration::from_secs(5)); //std::thread::sleep(std::time::Duration::from_secs(5));
let json = serde_json::to_string(&state.borrow().user_spans).unwrap_or("err".to_string()); let json = serde_json::to_string(&state.borrow().rounds).unwrap_or("err".to_string());
println!("{}", json); println!("{}", json);
Ok(()) Ok(())
} }

View file

@ -6,7 +6,6 @@ use num_traits::FromPrimitive;
pub use generated::*; pub use generated::*;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::demo::message::bspdecal::*; use crate::demo::message::bspdecal::*;
use crate::demo::message::classinfo::*; use crate::demo::message::classinfo::*;
use crate::demo::message::gameevent::*; use crate::demo::message::gameevent::*;
@ -16,6 +15,7 @@ use crate::demo::message::stringtable::*;
use crate::demo::message::tempentities::*; use crate::demo::message::tempentities::*;
use crate::demo::message::usermessage::*; use crate::demo::message::usermessage::*;
use crate::demo::message::voice::*; use crate::demo::message::voice::*;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
pub mod bspdecal; pub mod bspdecal;
pub mod classinfo; pub mod classinfo;

View file

@ -5,10 +5,10 @@ use bitstream_reader::{BitBuffer, BitRead, BitReadSized, BitStream, LittleEndian
use num_traits::{PrimInt, Unsigned}; use num_traits::{PrimInt, Unsigned};
use snap::Decoder; use snap::Decoder;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::demo::packet::stringtable::{ use crate::demo::packet::stringtable::{
ExtraData, FixedUserdataSize, StringTable, StringTableEntry, ExtraData, FixedUserdataSize, StringTable, StringTableEntry,
}; };
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
#[derive(Debug)] #[derive(Debug)]
pub struct CreateStringTableMessage { pub struct CreateStringTableMessage {
@ -77,8 +77,7 @@ impl Parse for CreateStringTableMessage {
fixed_userdata_size, fixed_userdata_size,
}; };
let entries = let entries = parse_string_table_list(&mut table_data, &table_meta, entity_count)?;
parse_string_table_list(&mut table_data, &table_meta, entity_count)?;
let table = StringTable { let table = StringTable {
entries, entries,
@ -178,12 +177,7 @@ fn parse_string_table_list(
panic!("there should be no holes when reading CreateStringTable message"); panic!("there should be no holes when reading CreateStringTable message");
}; };
let entry = read_table_entry( let entry = read_table_entry(stream, table_meta, &history, None)?;
stream,
table_meta,
&history,
None,
)?;
// optimize: any way to get rid of the clone here? // optimize: any way to get rid of the clone here?
// `entries` always outlives `history` without reallocation // `entries` always outlives `history` without reallocation
let text = entry.text.clone(); let text = entry.text.clone();
@ -240,7 +234,7 @@ fn read_table_entry(
} else { } else {
None None
} }
.map(ExtraData::new); .map(ExtraData::new);
Ok(match existing_entry { Ok(match existing_entry {
Some(existing_entry) => { Some(existing_entry) => {

View file

@ -1,4 +1,4 @@
use bitstream_reader::{BitRead, LittleEndian, LazyBitReadSized}; use bitstream_reader::{BitRead, LazyBitReadSized, LittleEndian};
use crate::{ReadResult, Stream}; use crate::{ReadResult, Stream};

View file

@ -1,8 +1,8 @@
use bitstream_reader::{BitRead, BitSize, LittleEndian, LazyBitRead}; use bitstream_reader::{BitRead, BitSize, LazyBitRead, LittleEndian};
use crate::{Parse, ParseError, ParserState, Result, Stream, ReadResult};
use crate::demo::message::Message; use crate::demo::message::Message;
use crate::demo::vector::Vector; use crate::demo::vector::Vector;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
#[derive(Debug)] #[derive(Debug)]
pub struct MessagePacket { pub struct MessagePacket {

View file

@ -2,9 +2,9 @@ use std::fmt;
use bitstream_reader::{BitRead, LittleEndian}; use bitstream_reader::{BitRead, LittleEndian};
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::demo::message::stringtable::StringTableMeta; use crate::demo::message::stringtable::StringTableMeta;
use crate::demo::sendprop::SendPropFlag::Exclude; use crate::demo::sendprop::SendPropFlag::Exclude;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
#[derive(BitRead, Clone, Copy, Debug)] #[derive(BitRead, Clone, Copy, Debug)]
pub struct FixedUserdataSize { pub struct FixedUserdataSize {
@ -68,10 +68,7 @@ pub struct ExtraData {
impl ExtraData { impl ExtraData {
pub fn new(data: Stream) -> Self { pub fn new(data: Stream) -> Self {
let byte_len = (data.bit_len() / 8) as u16; let byte_len = (data.bit_len() / 8) as u16;
ExtraData { ExtraData { byte_len, data }
byte_len,
data,
}
} }
} }

View file

@ -12,7 +12,7 @@ impl BitRead<LittleEndian> for UserCmdPacket {
fn read(stream: &mut Stream) -> ReadResult<Self> { fn read(stream: &mut Stream) -> ReadResult<Self> {
let tick = stream.read()?; let tick = stream.read()?;
let sequence_out = stream.read()?; let sequence_out = stream.read()?;
let len:u32 = stream.read()?; let len: u32 = stream.read()?;
let mut _packet_data = stream.read_bits(len as usize * 8)?; let mut _packet_data = stream.read_bits(len as usize * 8)?;
// TODO parse the packet data // TODO parse the packet data
Ok(UserCmdPacket { tick, sequence_out }) Ok(UserCmdPacket { tick, sequence_out })

View file

@ -2,14 +2,16 @@ use std::collections::HashMap;
use serde::Serialize; use serde::Serialize;
use crate::{ReadResult, Stream}; use crate::demo::gameevent_gen::{
use crate::demo::gameevent_gen::{GameEvent, PlayerDeathEvent, PlayerSpawnEvent}; GameEvent, PlayerDeathEvent, PlayerSpawnEvent, TeamPlayRoundWinEvent,
use crate::demo::message::{Message, MessageType}; };
use crate::demo::message::packetentities::EntityId; use crate::demo::message::packetentities::EntityId;
use crate::demo::message::usermessage::{ChatMessageKind, UserMessage}; use crate::demo::message::usermessage::{ChatMessageKind, UserMessage};
use crate::demo::message::{Message, MessageType};
use crate::demo::packet::stringtable::StringTableEntry; use crate::demo::packet::stringtable::StringTableEntry;
use crate::demo::parser::dispatcher::{MessageHandler, StringTableEntryHandler}; use crate::demo::parser::dispatcher::{MessageHandler, StringTableEntryHandler};
use crate::demo::vector::Vector; use crate::demo::vector::Vector;
use crate::{ReadResult, Stream};
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct ChatMassage { pub struct ChatMassage {
@ -33,7 +35,7 @@ impl Team {
1 => Team::Spectator, 1 => Team::Spectator,
2 => Team::Red, 2 => Team::Red,
3 => Team::Blue, 3 => Team::Blue,
_ => Team::Other _ => Team::Other,
} }
} }
} }
@ -64,7 +66,7 @@ impl Class {
7 => Class::Pyro, 7 => Class::Pyro,
8 => Class::Spy, 8 => Class::Spy,
9 => Class::Engineer, 9 => Class::Engineer,
_ => Class::Other _ => Class::Other,
} }
} }
} }
@ -127,11 +129,21 @@ impl Death {
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct Round { pub struct Round {
winner: String, winner: Team,
length: f32, length: f32,
end_tick: u32, end_tick: u32,
} }
impl Round {
pub fn from_event(event: TeamPlayRoundWinEvent, tick: u32) -> Self {
Round {
winner: Team::new(event.team as u16),
length: event.round_time,
end_tick: tick,
}
}
}
#[derive(Default, Debug, Serialize)] #[derive(Default, Debug, Serialize)]
pub struct World { pub struct World {
boundary_min: Vector, boundary_min: Vector,
@ -151,9 +163,8 @@ pub struct Analyser {
impl MessageHandler for Analyser { impl MessageHandler for Analyser {
fn does_handle(&self, message_type: MessageType) -> bool { fn does_handle(&self, message_type: MessageType) -> bool {
match message_type { match message_type {
MessageType::GameEvent | MessageType::GameEvent | MessageType::UserMessage => true,
MessageType::UserMessage => true, _ => false,
_ => false
} }
} }
@ -191,17 +202,15 @@ impl Analyser {
fn handle_user_message(&mut self, message: UserMessage, tick: u32) { fn handle_user_message(&mut self, message: UserMessage, tick: u32) {
match message { match message {
UserMessage::SayText2(message) => { UserMessage::SayText2(message) => match message.kind {
match message.kind { ChatMessageKind::NameChange => self.change_name(message.from, message.text),
ChatMessageKind::NameChange => self.change_name(message.from, message.text), _ => self.chat.push(ChatMassage {
_ => self.chat.push(ChatMassage { tick,
tick, text: message.text,
text: message.text, from: message.from,
from: message.from, kind: message.kind,
kind: message.kind, }),
}) },
}
}
_ => {} _ => {}
} }
} }
@ -219,6 +228,12 @@ impl Analyser {
match event { match event {
GameEvent::PlayerDeath(event) => self.deaths.push(Death::from_event(event, tick)), GameEvent::PlayerDeath(event) => self.deaths.push(Death::from_event(event, tick)),
GameEvent::PlayerSpawn(event) => self.user_spans.push(Spawn::from_event(event, tick)), GameEvent::PlayerSpawn(event) => self.user_spans.push(Spawn::from_event(event, tick)),
GameEvent::TeamPlayRoundWin(event) => {
// 6 = time limit
if event.win_reason != 6 {
self.rounds.push(Round::from_event(event, tick))
}
}
_ => {} _ => {}
} }
} }

View file

@ -4,8 +4,8 @@ use std::rc::Rc;
use crate::demo::message::{Message, MessageType}; use crate::demo::message::{Message, MessageType};
use crate::demo::packet::datatable::{SendTable, ServerClass}; use crate::demo::packet::datatable::{SendTable, ServerClass};
use crate::demo::packet::Packet;
use crate::demo::packet::stringtable::{StringTable, StringTableEntry}; use crate::demo::packet::stringtable::{StringTable, StringTableEntry};
use crate::demo::packet::Packet;
use crate::ParserState; use crate::ParserState;
pub trait MessageHandler { pub trait MessageHandler {
@ -24,7 +24,7 @@ pub struct Dispatcher {
string_table_names: Vec<String>, string_table_names: Vec<String>,
on_message: Vec<Rc<RefCell<MessageHandler>>>, on_message: Vec<Rc<RefCell<MessageHandler>>>,
on_string_table_entry: Vec<Rc<RefCell<StringTableEntryHandler>>>, on_string_table_entry: Vec<Rc<RefCell<StringTableEntryHandler>>>,
state_handler: Option<Rc<RefCell<ParserState>>> state_handler: Option<Rc<RefCell<ParserState>>>,
} }
impl Dispatcher { impl Dispatcher {
@ -36,7 +36,10 @@ impl Dispatcher {
self.state_handler = Some(handler); self.state_handler = Some(handler);
} }
pub fn register_string_table_entry_handler(&mut self, handler: Rc<RefCell<StringTableEntryHandler>>) { pub fn register_string_table_entry_handler(
&mut self,
handler: Rc<RefCell<StringTableEntryHandler>>,
) {
self.on_string_table_entry.push(handler); self.on_string_table_entry.push(handler);
} }
@ -53,12 +56,14 @@ impl Dispatcher {
Packet::Message(packet) | Packet::Sigon(packet) => { Packet::Message(packet) | Packet::Sigon(packet) => {
for message in packet.messages { for message in packet.messages {
match message { match message {
Message::NetTick(message) => { Message::NetTick(message) => self.tick = message.tick,
self.tick = message.tick Message::CreateStringTable(message) => {
self.handle_string_table(message.table)
} }
Message::CreateStringTable(message) => self.handle_string_table(message.table), Message::UpdateStringTable(message) => {
Message::UpdateStringTable(message) => self.handle_table_update(message.table_id, message.entries), self.handle_table_update(message.table_id, message.entries)
_ => self.handle_message(message) }
_ => self.handle_message(message),
} }
} }
} }
@ -93,13 +98,17 @@ impl Dispatcher {
fn handle_data_table(&mut self, send_tables: Vec<SendTable>, server_classes: Vec<ServerClass>) { fn handle_data_table(&mut self, send_tables: Vec<SendTable>, server_classes: Vec<ServerClass>) {
if let Some(handler) = &self.state_handler { if let Some(handler) = &self.state_handler {
handler.borrow_mut().handle_data_table(send_tables, server_classes); handler
.borrow_mut()
.handle_data_table(send_tables, server_classes);
} }
} }
fn handle_string_entry(&mut self, table: &String, index: usize, entries: &StringTableEntry) { fn handle_string_entry(&mut self, table: &String, index: usize, entries: &StringTableEntry) {
for handler in self.on_string_table_entry.iter() { for handler in self.on_string_table_entry.iter() {
handler.borrow_mut().handle_string_entry(table, index, entries); handler
.borrow_mut()
.handle_string_entry(table, index, entries);
} }
} }

View file

@ -6,8 +6,8 @@ use bitstream_reader::{BitRead, LittleEndian, ReadError};
use crate::demo::gamevent::GameEventValue; use crate::demo::gamevent::GameEventValue;
use crate::demo::header::Header; use crate::demo::header::Header;
use crate::demo::message::{Message, MessageType}; use crate::demo::message::{Message, MessageType};
use crate::demo::packet::Packet;
use crate::demo::packet::stringtable::StringTableEntry; use crate::demo::packet::stringtable::StringTableEntry;
use crate::demo::packet::Packet;
use crate::demo::parser::analyser::Analyser; use crate::demo::parser::analyser::Analyser;
use crate::demo::parser::dispatcher::{Dispatcher, MessageHandler, StringTableEntryHandler}; use crate::demo::parser::dispatcher::{Dispatcher, MessageHandler, StringTableEntryHandler};
pub use crate::demo::parser::state::ParserState; pub use crate::demo::parser::state::ParserState;
@ -15,9 +15,9 @@ use crate::Stream;
use std::cell::RefCell; use std::cell::RefCell;
use std::ops::Deref; use std::ops::Deref;
mod state;
mod analyser; mod analyser;
mod dispatcher; mod dispatcher;
mod state;
/// Errors that can occur during parsing /// Errors that can occur during parsing
#[derive(Debug)] #[derive(Debug)]
@ -92,7 +92,9 @@ impl DemoParser {
dispatcher.register_message_handler(Rc::clone(&state) as Rc<RefCell<MessageHandler>>); dispatcher.register_message_handler(Rc::clone(&state) as Rc<RefCell<MessageHandler>>);
dispatcher.register_message_handler(Rc::clone(&analyser) as Rc<RefCell<MessageHandler>>); dispatcher.register_message_handler(Rc::clone(&analyser) as Rc<RefCell<MessageHandler>>);
dispatcher.register_string_table_entry_handler(Rc::clone(&analyser) as Rc<RefCell<StringTableEntryHandler>>); dispatcher.register_string_table_entry_handler(
Rc::clone(&analyser) as Rc<RefCell<StringTableEntryHandler>>
);
dispatcher.set_state_handler(Rc::clone(&state)); dispatcher.set_state_handler(Rc::clone(&state));
DemoParser { DemoParser {

View file

@ -2,12 +2,12 @@ use std::collections::HashMap;
use crate::demo::gameevent_gen::GameEventType; use crate::demo::gameevent_gen::GameEventType;
use crate::demo::gamevent::GameEventDefinition; use crate::demo::gamevent::GameEventDefinition;
use crate::demo::message::{Message, MessageType};
use crate::demo::message::packetentities::EntityId; use crate::demo::message::packetentities::EntityId;
use crate::demo::message::stringtable::StringTableMeta; use crate::demo::message::stringtable::StringTableMeta;
use crate::demo::message::{Message, MessageType};
use crate::demo::packet::datatable::{SendTable, ServerClass}; use crate::demo::packet::datatable::{SendTable, ServerClass};
use crate::demo::packet::Packet;
use crate::demo::packet::stringtable::{StringTable, StringTableEntry}; use crate::demo::packet::stringtable::{StringTable, StringTableEntry};
use crate::demo::packet::Packet;
use crate::demo::parser::dispatcher::{MessageHandler, StringTableEntryHandler}; use crate::demo::parser::dispatcher::{MessageHandler, StringTableEntryHandler};
use crate::demo::sendprop::SendProp; use crate::demo::sendprop::SendProp;
use crate::Stream; use crate::Stream;
@ -49,7 +49,11 @@ impl ParserState {
ParserState::default() ParserState::default()
} }
pub fn handle_data_table(&mut self, send_tables: Vec<SendTable>, server_classes: Vec<ServerClass>) { pub fn handle_data_table(
&mut self,
send_tables: Vec<SendTable>,
server_classes: Vec<ServerClass>,
) {
for table in send_tables { for table in send_tables {
self.send_tables.insert(table.name.clone(), table); self.send_tables.insert(table.name.clone(), table);
} }
@ -60,7 +64,11 @@ impl ParserState {
self.string_tables.push(table); self.string_tables.push(table);
} }
pub fn handle_string_table_update(&mut self, table_id: u8, entries: HashMap<u16, StringTableEntry>) { pub fn handle_string_table_update(
&mut self,
table_id: u8,
entries: HashMap<u16, StringTableEntry>,
) {
match self.string_tables.get_mut(table_id as usize) { match self.string_tables.get_mut(table_id as usize) {
Some(table) => { Some(table) => {
for (index, entry) in entries { for (index, entry) in entries {
@ -72,8 +80,8 @@ impl ParserState {
replace(table.entries.get_unchecked_mut(index), entry); replace(table.entries.get_unchecked_mut(index), entry);
} }
} }
}, }
_ => unreachable!() _ => unreachable!(),
} }
} }
} }
@ -81,11 +89,11 @@ impl ParserState {
impl MessageHandler for ParserState { impl MessageHandler for ParserState {
fn does_handle(&self, message_type: MessageType) -> bool { fn does_handle(&self, message_type: MessageType) -> bool {
match message_type { match message_type {
MessageType::ServerInfo | MessageType::ServerInfo
MessageType::GameEventList | | MessageType::GameEventList
MessageType::CreateStringTable | | MessageType::CreateStringTable
MessageType::UpdateStringTable => true, | MessageType::UpdateStringTable => true,
_ => false _ => false,
} }
} }
@ -106,21 +114,17 @@ impl MessageHandler for ParserState {
impl StringTableEntryHandler for ParserState { impl StringTableEntryHandler for ParserState {
fn handle_string_entry(&mut self, table: &String, index: usize, entry: &StringTableEntry) { fn handle_string_entry(&mut self, table: &String, index: usize, entry: &StringTableEntry) {
match table.as_str() { match table.as_str() {
"instancebaseline" => { "instancebaseline" => match &entry.extra_data {
match &entry.extra_data { Some(extra) => match entry.text.parse::<u32>() {
Some(extra) => { Ok(class_id) => {
match entry.text.parse::<u32>() { let baseline = StaticBaseline::new(class_id, extra.data.clone());
Ok(class_id) => { self.static_baselines.insert(class_id, baseline);
let baseline = StaticBaseline::new(class_id, extra.data.clone());
self.static_baselines.insert(class_id, baseline);
}
Err(_) => {}
}
} }
_ => unreachable!("missing baseline") Err(_) => {}
} },
} _ => unreachable!("missing baseline"),
_ => unreachable!() },
_ => unreachable!(),
} }
} }
} }

View file

@ -1,4 +1,4 @@
use bitstream_reader::{BitRead, LittleEndian, BitSize}; use bitstream_reader::{BitRead, BitSize, LittleEndian};
use serde::Serialize; use serde::Serialize;
use crate::{ReadResult, Stream}; use crate::{ReadResult, Stream};