mirror of
https://codeberg.org/demostf/parser.git
synced 2026-06-03 18:24:05 +02:00
track rounds
This commit is contained in:
parent
6a47c91636
commit
713ab0de42
12 changed files with 105 additions and 84 deletions
|
|
@ -13,7 +13,7 @@ fn main() -> std::result::Result<(), Box<ParseError>> {
|
|||
//dbg!(header);
|
||||
//dbg!(state.deaths);
|
||||
//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);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use num_traits::FromPrimitive;
|
|||
|
||||
pub use generated::*;
|
||||
|
||||
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
|
||||
use crate::demo::message::bspdecal::*;
|
||||
use crate::demo::message::classinfo::*;
|
||||
use crate::demo::message::gameevent::*;
|
||||
|
|
@ -16,6 +15,7 @@ use crate::demo::message::stringtable::*;
|
|||
use crate::demo::message::tempentities::*;
|
||||
use crate::demo::message::usermessage::*;
|
||||
use crate::demo::message::voice::*;
|
||||
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
|
||||
|
||||
pub mod bspdecal;
|
||||
pub mod classinfo;
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ use bitstream_reader::{BitBuffer, BitRead, BitReadSized, BitStream, LittleEndian
|
|||
use num_traits::{PrimInt, Unsigned};
|
||||
use snap::Decoder;
|
||||
|
||||
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
|
||||
use crate::demo::packet::stringtable::{
|
||||
ExtraData, FixedUserdataSize, StringTable, StringTableEntry,
|
||||
};
|
||||
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CreateStringTableMessage {
|
||||
|
|
@ -77,8 +77,7 @@ impl Parse for CreateStringTableMessage {
|
|||
fixed_userdata_size,
|
||||
};
|
||||
|
||||
let entries =
|
||||
parse_string_table_list(&mut table_data, &table_meta, entity_count)?;
|
||||
let entries = parse_string_table_list(&mut table_data, &table_meta, entity_count)?;
|
||||
|
||||
let table = StringTable {
|
||||
entries,
|
||||
|
|
@ -178,12 +177,7 @@ fn parse_string_table_list(
|
|||
panic!("there should be no holes when reading CreateStringTable message");
|
||||
};
|
||||
|
||||
let entry = read_table_entry(
|
||||
stream,
|
||||
table_meta,
|
||||
&history,
|
||||
None,
|
||||
)?;
|
||||
let entry = read_table_entry(stream, table_meta, &history, None)?;
|
||||
// optimize: any way to get rid of the clone here?
|
||||
// `entries` always outlives `history` without reallocation
|
||||
let text = entry.text.clone();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use bitstream_reader::{BitRead, LittleEndian, LazyBitReadSized};
|
||||
use bitstream_reader::{BitRead, LazyBitReadSized, LittleEndian};
|
||||
|
||||
use crate::{ReadResult, Stream};
|
||||
|
||||
|
|
|
|||
|
|
@ -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::vector::Vector;
|
||||
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MessagePacket {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ use std::fmt;
|
|||
|
||||
use bitstream_reader::{BitRead, LittleEndian};
|
||||
|
||||
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
|
||||
use crate::demo::message::stringtable::StringTableMeta;
|
||||
use crate::demo::sendprop::SendPropFlag::Exclude;
|
||||
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
|
||||
|
||||
#[derive(BitRead, Clone, Copy, Debug)]
|
||||
pub struct FixedUserdataSize {
|
||||
|
|
@ -68,10 +68,7 @@ pub struct ExtraData {
|
|||
impl ExtraData {
|
||||
pub fn new(data: Stream) -> Self {
|
||||
let byte_len = (data.bit_len() / 8) as u16;
|
||||
ExtraData {
|
||||
byte_len,
|
||||
data,
|
||||
}
|
||||
ExtraData { byte_len, data }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ impl BitRead<LittleEndian> for UserCmdPacket {
|
|||
fn read(stream: &mut Stream) -> ReadResult<Self> {
|
||||
let tick = 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)?;
|
||||
// TODO parse the packet data
|
||||
Ok(UserCmdPacket { tick, sequence_out })
|
||||
|
|
|
|||
|
|
@ -2,14 +2,16 @@ use std::collections::HashMap;
|
|||
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{ReadResult, Stream};
|
||||
use crate::demo::gameevent_gen::{GameEvent, PlayerDeathEvent, PlayerSpawnEvent};
|
||||
use crate::demo::message::{Message, MessageType};
|
||||
use crate::demo::gameevent_gen::{
|
||||
GameEvent, PlayerDeathEvent, PlayerSpawnEvent, TeamPlayRoundWinEvent,
|
||||
};
|
||||
use crate::demo::message::packetentities::EntityId;
|
||||
use crate::demo::message::usermessage::{ChatMessageKind, UserMessage};
|
||||
use crate::demo::message::{Message, MessageType};
|
||||
use crate::demo::packet::stringtable::StringTableEntry;
|
||||
use crate::demo::parser::dispatcher::{MessageHandler, StringTableEntryHandler};
|
||||
use crate::demo::vector::Vector;
|
||||
use crate::{ReadResult, Stream};
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct ChatMassage {
|
||||
|
|
@ -33,7 +35,7 @@ impl Team {
|
|||
1 => Team::Spectator,
|
||||
2 => Team::Red,
|
||||
3 => Team::Blue,
|
||||
_ => Team::Other
|
||||
_ => Team::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -64,7 +66,7 @@ impl Class {
|
|||
7 => Class::Pyro,
|
||||
8 => Class::Spy,
|
||||
9 => Class::Engineer,
|
||||
_ => Class::Other
|
||||
_ => Class::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -127,11 +129,21 @@ impl Death {
|
|||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct Round {
|
||||
winner: String,
|
||||
winner: Team,
|
||||
length: f32,
|
||||
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)]
|
||||
pub struct World {
|
||||
boundary_min: Vector,
|
||||
|
|
@ -151,9 +163,8 @@ pub struct Analyser {
|
|||
impl MessageHandler for Analyser {
|
||||
fn does_handle(&self, message_type: MessageType) -> bool {
|
||||
match message_type {
|
||||
MessageType::GameEvent |
|
||||
MessageType::UserMessage => true,
|
||||
_ => false
|
||||
MessageType::GameEvent | MessageType::UserMessage => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -191,17 +202,15 @@ impl Analyser {
|
|||
|
||||
fn handle_user_message(&mut self, message: UserMessage, tick: u32) {
|
||||
match message {
|
||||
UserMessage::SayText2(message) => {
|
||||
match message.kind {
|
||||
UserMessage::SayText2(message) => match message.kind {
|
||||
ChatMessageKind::NameChange => self.change_name(message.from, message.text),
|
||||
_ => self.chat.push(ChatMassage {
|
||||
tick,
|
||||
text: message.text,
|
||||
from: message.from,
|
||||
kind: message.kind,
|
||||
})
|
||||
}
|
||||
}
|
||||
}),
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -219,6 +228,12 @@ impl Analyser {
|
|||
match event {
|
||||
GameEvent::PlayerDeath(event) => self.deaths.push(Death::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))
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ use std::rc::Rc;
|
|||
|
||||
use crate::demo::message::{Message, MessageType};
|
||||
use crate::demo::packet::datatable::{SendTable, ServerClass};
|
||||
use crate::demo::packet::Packet;
|
||||
use crate::demo::packet::stringtable::{StringTable, StringTableEntry};
|
||||
use crate::demo::packet::Packet;
|
||||
use crate::ParserState;
|
||||
|
||||
pub trait MessageHandler {
|
||||
|
|
@ -24,7 +24,7 @@ pub struct Dispatcher {
|
|||
string_table_names: Vec<String>,
|
||||
on_message: Vec<Rc<RefCell<MessageHandler>>>,
|
||||
on_string_table_entry: Vec<Rc<RefCell<StringTableEntryHandler>>>,
|
||||
state_handler: Option<Rc<RefCell<ParserState>>>
|
||||
state_handler: Option<Rc<RefCell<ParserState>>>,
|
||||
}
|
||||
|
||||
impl Dispatcher {
|
||||
|
|
@ -36,7 +36,10 @@ impl Dispatcher {
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
@ -53,12 +56,14 @@ impl Dispatcher {
|
|||
Packet::Message(packet) | Packet::Sigon(packet) => {
|
||||
for message in packet.messages {
|
||||
match message {
|
||||
Message::NetTick(message) => {
|
||||
self.tick = message.tick
|
||||
Message::NetTick(message) => 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) => self.handle_table_update(message.table_id, message.entries),
|
||||
_ => self.handle_message(message)
|
||||
Message::UpdateStringTable(message) => {
|
||||
self.handle_table_update(message.table_id, message.entries)
|
||||
}
|
||||
_ => self.handle_message(message),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -93,13 +98,17 @@ impl Dispatcher {
|
|||
|
||||
fn handle_data_table(&mut self, send_tables: Vec<SendTable>, server_classes: Vec<ServerClass>) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ use bitstream_reader::{BitRead, LittleEndian, ReadError};
|
|||
use crate::demo::gamevent::GameEventValue;
|
||||
use crate::demo::header::Header;
|
||||
use crate::demo::message::{Message, MessageType};
|
||||
use crate::demo::packet::Packet;
|
||||
use crate::demo::packet::stringtable::StringTableEntry;
|
||||
use crate::demo::packet::Packet;
|
||||
use crate::demo::parser::analyser::Analyser;
|
||||
use crate::demo::parser::dispatcher::{Dispatcher, MessageHandler, StringTableEntryHandler};
|
||||
pub use crate::demo::parser::state::ParserState;
|
||||
|
|
@ -15,9 +15,9 @@ use crate::Stream;
|
|||
use std::cell::RefCell;
|
||||
use std::ops::Deref;
|
||||
|
||||
mod state;
|
||||
mod analyser;
|
||||
mod dispatcher;
|
||||
mod state;
|
||||
|
||||
/// Errors that can occur during parsing
|
||||
#[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(&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));
|
||||
|
||||
DemoParser {
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ use std::collections::HashMap;
|
|||
|
||||
use crate::demo::gameevent_gen::GameEventType;
|
||||
use crate::demo::gamevent::GameEventDefinition;
|
||||
use crate::demo::message::{Message, MessageType};
|
||||
use crate::demo::message::packetentities::EntityId;
|
||||
use crate::demo::message::stringtable::StringTableMeta;
|
||||
use crate::demo::message::{Message, MessageType};
|
||||
use crate::demo::packet::datatable::{SendTable, ServerClass};
|
||||
use crate::demo::packet::Packet;
|
||||
use crate::demo::packet::stringtable::{StringTable, StringTableEntry};
|
||||
use crate::demo::packet::Packet;
|
||||
use crate::demo::parser::dispatcher::{MessageHandler, StringTableEntryHandler};
|
||||
use crate::demo::sendprop::SendProp;
|
||||
use crate::Stream;
|
||||
|
|
@ -49,7 +49,11 @@ impl ParserState {
|
|||
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 {
|
||||
self.send_tables.insert(table.name.clone(), table);
|
||||
}
|
||||
|
|
@ -60,7 +64,11 @@ impl ParserState {
|
|||
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) {
|
||||
Some(table) => {
|
||||
for (index, entry) in entries {
|
||||
|
|
@ -72,8 +80,8 @@ impl ParserState {
|
|||
replace(table.entries.get_unchecked_mut(index), entry);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -81,11 +89,11 @@ impl ParserState {
|
|||
impl MessageHandler for ParserState {
|
||||
fn does_handle(&self, message_type: MessageType) -> bool {
|
||||
match message_type {
|
||||
MessageType::ServerInfo |
|
||||
MessageType::GameEventList |
|
||||
MessageType::CreateStringTable |
|
||||
MessageType::UpdateStringTable => true,
|
||||
_ => false
|
||||
MessageType::ServerInfo
|
||||
| MessageType::GameEventList
|
||||
| MessageType::CreateStringTable
|
||||
| MessageType::UpdateStringTable => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -106,21 +114,17 @@ impl MessageHandler for ParserState {
|
|||
impl StringTableEntryHandler for ParserState {
|
||||
fn handle_string_entry(&mut self, table: &String, index: usize, entry: &StringTableEntry) {
|
||||
match table.as_str() {
|
||||
"instancebaseline" => {
|
||||
match &entry.extra_data {
|
||||
Some(extra) => {
|
||||
match entry.text.parse::<u32>() {
|
||||
"instancebaseline" => match &entry.extra_data {
|
||||
Some(extra) => match entry.text.parse::<u32>() {
|
||||
Ok(class_id) => {
|
||||
let baseline = StaticBaseline::new(class_id, extra.data.clone());
|
||||
self.static_baselines.insert(class_id, baseline);
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
_ => unreachable!("missing baseline")
|
||||
}
|
||||
}
|
||||
_ => unreachable!()
|
||||
},
|
||||
_ => unreachable!("missing baseline"),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use bitstream_reader::{BitRead, LittleEndian, BitSize};
|
||||
use bitstream_reader::{BitRead, BitSize, LittleEndian};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{ReadResult, Stream};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue