more edge case handling

This commit is contained in:
Robin Appelman 2023-03-17 21:11:08 +01:00
commit 2dcd691f66
9 changed files with 37 additions and 24 deletions

View file

@ -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"

View file

@ -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) {

View file

@ -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,

View file

@ -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) {

View file

@ -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>,
} }

View file

@ -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);

View file

@ -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;
} }
} }
_ => {} _ => {}

View file

@ -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

View file

@ -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, (name, "0", "", "")
&user_id[0..user_id.len() - 1], } else {
&steam_id[0..steam_id.len() - 1], (
&team[0..team.len() - 1], name,
) user_id
.get(0..user_id.len() - 1)
.or_else(|| {
println!("{}", input);
None
})
.expect("asd"),
&steam_id[0..steam_id.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""#)]