mirror of
https://codeberg.org/icewind/tf-log-parser.git
synced 2026-06-03 18:24:09 +02:00
more edge case handling
This commit is contained in:
parent
9114397803
commit
2dcd691f66
9 changed files with 37 additions and 24 deletions
|
|
@ -31,6 +31,7 @@ miette = { version = "5.5.0", features = ["fancy"] }
|
||||||
insta = { version = "1.28.0", features = ["json"] }
|
insta = { version = "1.28.0", features = ["json"] }
|
||||||
test-case = "3.0.0"
|
test-case = "3.0.0"
|
||||||
rayon = "1.7.0"
|
rayon = "1.7.0"
|
||||||
|
indicatif = { version = "0.17.3", features = ["rayon"] }
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "bench"
|
name = "bench"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use indicatif::ParallelProgressIterator;
|
||||||
use main_error::MainError;
|
use main_error::MainError;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::env::args;
|
use std::env::args;
|
||||||
|
|
@ -21,6 +22,7 @@ fn main() -> Result<(), MainError> {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.par_bridge()
|
.par_bridge()
|
||||||
|
.progress_count(2_500_000)
|
||||||
.for_each(|entry| {
|
.for_each(|entry| {
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
if path.extension() == Some(OsStr::new("log")) {
|
if path.extension() == Some(OsStr::new("log")) {
|
||||||
|
|
@ -34,10 +36,6 @@ fn main() -> Result<(), MainError> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if count.load(Ordering::Relaxed) % 1_000 == 0 {
|
|
||||||
println!("{}", path.display());
|
|
||||||
}
|
|
||||||
|
|
||||||
read_time.fetch_add(read_start.elapsed().as_micros() as usize, Ordering::Relaxed);
|
read_time.fetch_add(read_start.elapsed().as_micros() as usize, Ordering::Relaxed);
|
||||||
let parse_start = Instant::now();
|
let parse_start = Instant::now();
|
||||||
let (output, _) = match parse(&input) {
|
let (output, _) = match parse(&input) {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::event::{param_parse_with, parse_field, ParamIter};
|
use crate::event::{parse_field, ParamIter};
|
||||||
use crate::raw_event::RawSubject;
|
use crate::raw_event::RawSubject;
|
||||||
use crate::{Event, Result};
|
use crate::{Event, Result};
|
||||||
|
|
||||||
#[derive(Debug, Event)]
|
#[derive(Debug, Event)]
|
||||||
pub struct HealedEvent<'a> {
|
pub struct HealedEvent<'a> {
|
||||||
#[event(name = "against")]
|
#[event(name = "against")]
|
||||||
pub target: RawSubject<'a>,
|
pub target: Option<RawSubject<'a>>,
|
||||||
#[event(name = "healing")]
|
#[event(name = "healing")]
|
||||||
#[event(default)]
|
#[event(default)]
|
||||||
pub amount: u32,
|
pub amount: u32,
|
||||||
|
|
|
||||||
|
|
@ -223,6 +223,7 @@ impl EventFieldFromStr for SocketAddr {}
|
||||||
impl EventFieldFromStr for u8 {}
|
impl EventFieldFromStr for u8 {}
|
||||||
impl EventFieldFromStr for u32 {}
|
impl EventFieldFromStr for u32 {}
|
||||||
impl EventFieldFromStr for i32 {}
|
impl EventFieldFromStr for i32 {}
|
||||||
|
impl EventFieldFromStr for i64 {}
|
||||||
impl EventFieldFromStr for f32 {}
|
impl EventFieldFromStr for f32 {}
|
||||||
|
|
||||||
impl<'a, T: EventField<'a>> EventField<'a> for (T, T, T) {
|
impl<'a, T: EventField<'a>> EventField<'a> for (T, T, T) {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ use crate::event::{param_parse_with, parse_field, quoted, ParamIter};
|
||||||
use crate::raw_event::{subject_parser, RawSubject};
|
use crate::raw_event::{subject_parser, RawSubject};
|
||||||
use crate::{Error, Event, Result};
|
use crate::{Error, Event, Result};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::num::NonZeroU32;
|
|
||||||
|
|
||||||
#[derive(Debug, Event)]
|
#[derive(Debug, Event)]
|
||||||
pub struct ShotFiredEvent<'a> {
|
pub struct ShotFiredEvent<'a> {
|
||||||
|
|
@ -20,9 +19,9 @@ pub struct DamageEvent<'a> {
|
||||||
#[event(name = "against")]
|
#[event(name = "against")]
|
||||||
#[event(default)]
|
#[event(default)]
|
||||||
pub target: RawSubject<'a>,
|
pub target: RawSubject<'a>,
|
||||||
pub damage: Option<NonZeroU32>,
|
pub damage: Option<i64>,
|
||||||
#[event(name = "realdamage")]
|
#[event(name = "realdamage")]
|
||||||
pub real_damage: Option<NonZeroU32>,
|
pub real_damage: Option<i64>,
|
||||||
pub weapon: Option<&'a str>,
|
pub weapon: Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,6 @@ pub enum Error {
|
||||||
Malformed,
|
Malformed,
|
||||||
#[error("Incomplete logfile")]
|
#[error("Incomplete logfile")]
|
||||||
Incomplete,
|
Incomplete,
|
||||||
#[error("Incomplete logfile")]
|
|
||||||
Truncated, // like incomplete, but when we're certain the log is at fault, and not the parser
|
|
||||||
#[error("Malformed subject: {0}")]
|
#[error("Malformed subject: {0}")]
|
||||||
Subject(#[from] SubjectError),
|
Subject(#[from] SubjectError),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
|
|
@ -83,7 +81,7 @@ pub fn parse_with_handler<Handler: EventHandler>(
|
||||||
while let Some(event_res) = events.next() {
|
while let Some(event_res) = events.next() {
|
||||||
let raw_event = match event_res {
|
let raw_event = match event_res {
|
||||||
Ok(raw_event) => raw_event,
|
Ok(raw_event) => raw_event,
|
||||||
Err(Error::Truncated) => break,
|
Err(Error::Incomplete) if events.next().is_none() => break,
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
let should_handle = Handler::does_handle(raw_event.ty);
|
let should_handle = Handler::does_handle(raw_event.ty);
|
||||||
|
|
|
||||||
|
|
@ -95,9 +95,9 @@ impl EventHandler for ClassStatsHandler {
|
||||||
damage: Some(damage),
|
damage: Some(damage),
|
||||||
target,
|
target,
|
||||||
..
|
..
|
||||||
}) if self.active => {
|
}) if self.active && damage > &0 && damage < &99999 => {
|
||||||
if let Some(target_class) = self.get_class(target) {
|
if let Some(target_class) = self.get_class(target) {
|
||||||
subject_data.damage[target_class] += damage.get() as u16;
|
subject_data.damage[target_class] += *damage as u16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,11 @@ impl PlayerSpecificData for HealSpread {
|
||||||
|
|
||||||
fn handle_event(&mut self, _meta: &EventMeta, _subject: SubjectId, event: &GameEvent) {
|
fn handle_event(&mut self, _meta: &EventMeta, _subject: SubjectId, event: &GameEvent) {
|
||||||
if let GameEvent::Healed(heal_event) = event {
|
if let GameEvent::Healed(heal_event) = event {
|
||||||
if let Ok(target_subject) = SubjectId::try_from(&heal_event.target) {
|
if let Some(Ok(target_subject)) = heal_event
|
||||||
|
.target
|
||||||
|
.as_ref()
|
||||||
|
.map(|target| SubjectId::try_from(target))
|
||||||
|
{
|
||||||
if let Some(target_steam_id) = target_subject.steam_id() {
|
if let Some(target_steam_id) = target_subject.steam_id() {
|
||||||
let healed = self.0.entry(SteamId3(target_steam_id)).or_default();
|
let healed = self.0.entry(SteamId3(target_steam_id)).or_default();
|
||||||
*healed += heal_event.amount
|
*healed += heal_event.amount
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ impl<'a> RawEvent<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event_parser(input: &str) -> Result<RawEvent> {
|
fn event_parser(input: &str) -> Result<RawEvent> {
|
||||||
if input.len() < 30 {
|
if input.len() < 24 {
|
||||||
return Err(Error::Truncated);
|
return Err(Error::Incomplete);
|
||||||
}
|
}
|
||||||
let date = RawDate(&input[0..21]);
|
let date = RawDate(&input[0..21]);
|
||||||
|
|
||||||
|
|
@ -33,7 +33,7 @@ fn event_parser(input: &str) -> Result<RawEvent> {
|
||||||
|
|
||||||
let (input, ty) = event_type_parser(input)?;
|
let (input, ty) = event_type_parser(input)?;
|
||||||
|
|
||||||
let params = &input[(!input.is_empty() as usize)..];
|
let params = &input[((!input.is_empty() && ty != RawEventType::Unknown) as usize)..];
|
||||||
|
|
||||||
Ok(RawEvent {
|
Ok(RawEvent {
|
||||||
date,
|
date,
|
||||||
|
|
@ -97,12 +97,22 @@ pub fn split_player_subject(input: &str) -> Result<(&str, &str, &str, &str)> {
|
||||||
if let (Some(team), Some(steam_id), Some(user_id), Some(name)) =
|
if let (Some(team), Some(steam_id), Some(user_id), Some(name)) =
|
||||||
(parts.next(), parts.next(), parts.next(), parts.next())
|
(parts.next(), parts.next(), parts.next(), parts.next())
|
||||||
{
|
{
|
||||||
|
if steam_id.is_empty() || user_id.is_empty() || team.is_empty() {
|
||||||
|
(name, "0", "", "")
|
||||||
|
} else {
|
||||||
(
|
(
|
||||||
name,
|
name,
|
||||||
&user_id[0..user_id.len() - 1],
|
user_id
|
||||||
|
.get(0..user_id.len() - 1)
|
||||||
|
.or_else(|| {
|
||||||
|
println!("{}", input);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.expect("asd"),
|
||||||
&steam_id[0..steam_id.len() - 1],
|
&steam_id[0..steam_id.len() - 1],
|
||||||
&team[0..team.len() - 1],
|
&team[0..team.len() - 1],
|
||||||
)
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::Incomplete);
|
return Err(Error::Incomplete);
|
||||||
};
|
};
|
||||||
|
|
@ -217,6 +227,8 @@ pub enum RawEventType {
|
||||||
CarryObject,
|
CarryObject,
|
||||||
#[token(r#"triggered "player_carryobject""#)]
|
#[token(r#"triggered "player_carryobject""#)]
|
||||||
DropObject,
|
DropObject,
|
||||||
|
#[token(r#"triggered "rocket_jump""#)]
|
||||||
|
RocketJump,
|
||||||
#[token(r#"triggered "killedobject""#)]
|
#[token(r#"triggered "killedobject""#)]
|
||||||
KilledObject,
|
KilledObject,
|
||||||
#[token(r#"triggered "object_detonated""#)]
|
#[token(r#"triggered "object_detonated""#)]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue