mirror of
https://codeberg.org/icewind/tf-log-parser.git
synced 2026-06-03 10:14:10 +02:00
medic stats
This commit is contained in:
parent
b2d169601c
commit
a5040ec355
5 changed files with 147 additions and 20 deletions
|
|
@ -1,4 +1,4 @@
|
|||
use crate::event::{param_parse, param_parse_with, quoted, u_int};
|
||||
use crate::event::{param_parse, param_parse_with, quoted, u_int, ParamIter};
|
||||
use crate::raw_event::{subject_parser, RawSubject};
|
||||
use nom::combinator::opt;
|
||||
use nom::number::complete::float;
|
||||
|
|
@ -41,3 +41,39 @@ pub fn charge_ended_event_parser(input: &str) -> IResult<&str, ChargeEndedEvent>
|
|||
let (input, duration) = opt(param_parse_with("duration", quoted(float)))(input)?;
|
||||
Ok((input, ChargeEndedEvent { duration }))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AdvantageLostEvent {
|
||||
pub time: Option<f32>,
|
||||
}
|
||||
|
||||
pub fn advantage_lost_event_parser(input: &str) -> IResult<&str, AdvantageLostEvent> {
|
||||
let (input, time) = opt(param_parse_with("time", quoted(float)))(input)?;
|
||||
Ok((input, AdvantageLostEvent { time }))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FirstHealEvent {
|
||||
pub time: Option<f32>,
|
||||
}
|
||||
|
||||
pub fn first_heal_event_parser(input: &str) -> IResult<&str, FirstHealEvent> {
|
||||
let (input, time) = opt(param_parse_with("time", quoted(float)))(input)?;
|
||||
Ok((input, FirstHealEvent { time }))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MedicDeathEvent {
|
||||
pub charge: Option<u32>,
|
||||
}
|
||||
|
||||
pub fn medic_death_event_parser(input: &str) -> IResult<&str, MedicDeathEvent> {
|
||||
let mut charge = None;
|
||||
for (key, value) in ParamIter::new(input) {
|
||||
if key == "ubercharge" {
|
||||
charge = Some(quoted(u_int)(value)?.1);
|
||||
}
|
||||
}
|
||||
let (input, time) = opt(param_parse_with("time", quoted(float)))(input)?;
|
||||
Ok((input, MedicDeathEvent { charge }))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ impl<'a, T> GameEventErrTrait<T> for IResult<&str, T> {
|
|||
|
||||
Err::Incomplete(_) => GameEventError::Incomplete(ty),
|
||||
})
|
||||
.map(|(rest, t)| t)
|
||||
.map(|(_rest, t)| t)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +51,12 @@ pub enum GameEvent<'a> {
|
|||
Say(&'a str),
|
||||
SayTeam(&'a str),
|
||||
Healed(HealedEvent<'a>),
|
||||
ChargeDeployed(ChargeDeployedEvent<'a>),
|
||||
ChargeEnded(ChargeEndedEvent),
|
||||
AdvantageLost(AdvantageLostEvent),
|
||||
FirstHeal(FirstHealEvent),
|
||||
ChargeReady,
|
||||
MedicDeath(MedicDeathEvent),
|
||||
}
|
||||
|
||||
impl<'a> GameEvent<'a> {
|
||||
|
|
@ -64,6 +70,22 @@ impl<'a> GameEvent<'a> {
|
|||
RawEventType::Healed => {
|
||||
GameEvent::Healed(healed_event_parser(raw.params).with_type(raw.ty)?)
|
||||
}
|
||||
RawEventType::ChargeDeployed => GameEvent::ChargeDeployed(
|
||||
charge_deployed_event_parser(raw.params).with_type(raw.ty)?,
|
||||
),
|
||||
RawEventType::ChargeEnd => {
|
||||
GameEvent::ChargeEnded(charge_ended_event_parser(raw.params).with_type(raw.ty)?)
|
||||
}
|
||||
RawEventType::UberAdvantageLost => {
|
||||
GameEvent::AdvantageLost(advantage_lost_event_parser(raw.params).with_type(raw.ty)?)
|
||||
}
|
||||
RawEventType::FirstHealAfterSpawn => {
|
||||
GameEvent::FirstHeal(first_heal_event_parser(raw.params).with_type(raw.ty)?)
|
||||
}
|
||||
RawEventType::ChargeReady => GameEvent::ChargeReady,
|
||||
RawEventType::MedicDeath => {
|
||||
GameEvent::MedicDeath(medic_death_event_parser(raw.params).with_type(raw.ty)?)
|
||||
}
|
||||
_ => {
|
||||
todo!("{:?} not parsed yet", raw.ty);
|
||||
}
|
||||
|
|
|
|||
12
src/lib.rs
12
src/lib.rs
|
|
@ -1,6 +1,8 @@
|
|||
pub use crate::common::{SteamId3, SubjectData, SubjectError, SubjectId};
|
||||
use crate::event::{GameEvent, GameEventError};
|
||||
use crate::module::{ChatHandler, ChatMessage, EventHandler, HealSpreadHandler};
|
||||
use crate::module::{
|
||||
ChatHandler, ChatMessage, EventHandler, HealSpreadHandler, MedicStats, MedicStatsHandler,
|
||||
};
|
||||
use crate::raw_event::RawSubject;
|
||||
use chrono::{DateTime, Utc};
|
||||
pub use raw_event::{RawEvent, RawEventType};
|
||||
|
|
@ -116,12 +118,14 @@ pub fn parse_with_handler<Handler: EventHandler>(
|
|||
pub struct LogHandler {
|
||||
chat: ChatHandler,
|
||||
heal_spread: HealSpreadHandler,
|
||||
medic_stats: MedicStatsHandler,
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize)]
|
||||
pub struct LogOutput {
|
||||
chat: Vec<ChatMessage>,
|
||||
heal_spread: HashMap<SteamId3, HashMap<SteamId3, u32>>,
|
||||
medic_stats: HashMap<SteamId3, MedicStats>,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
|
@ -135,7 +139,9 @@ impl EventHandler for LogHandler {
|
|||
type Error = LogError;
|
||||
|
||||
fn does_handle(&self, ty: RawEventType) -> bool {
|
||||
self.chat.does_handle(ty) || self.heal_spread.does_handle(ty)
|
||||
self.chat.does_handle(ty)
|
||||
|| self.heal_spread.does_handle(ty)
|
||||
|| self.medic_stats.does_handle(ty)
|
||||
}
|
||||
|
||||
fn handle(
|
||||
|
|
@ -146,6 +152,7 @@ impl EventHandler for LogHandler {
|
|||
) -> Result<(), Self::Error> {
|
||||
self.chat.handle(time, subject, event).unwrap();
|
||||
self.heal_spread.handle(time, subject, event).unwrap();
|
||||
self.medic_stats.handle(time, subject, event).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -153,6 +160,7 @@ impl EventHandler for LogHandler {
|
|||
LogOutput {
|
||||
chat: self.chat.finish(subjects),
|
||||
heal_spread: self.heal_spread.finish(subjects),
|
||||
medic_stats: self.medic_stats.finish(subjects),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,34 +3,40 @@ use crate::event::GameEvent;
|
|||
use crate::module::EventHandler;
|
||||
use crate::raw_event::RawEventType;
|
||||
use crate::SubjectMap;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MedicStatsBuilder {
|
||||
struct MedicStatsBuilder {
|
||||
advantages_lost: u32,
|
||||
biggest_advantage_lost: u32,
|
||||
biggest_advantage_lost: f32,
|
||||
near_full_charge_death: u32,
|
||||
deaths_after_uber: u32,
|
||||
total_time_before_healing: u32,
|
||||
total_time_before_healing: f32,
|
||||
start_healing_count: u32,
|
||||
total_time_to_build: u32,
|
||||
uber_build_count: u32,
|
||||
total_time_to_use: u32,
|
||||
total_uber_length: u32,
|
||||
total_time_to_use: f32,
|
||||
total_uber_length: f32,
|
||||
charge_count: u32,
|
||||
last_build_start: u32,
|
||||
last_uber_end: u32,
|
||||
drops: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct MedicStats {
|
||||
advantages_lost: u32,
|
||||
biggest_advantage_lost: u32,
|
||||
biggest_advantage_lost: f32,
|
||||
near_full_charge_death: u32,
|
||||
deaths_after_uber: u32,
|
||||
avg_time_before_healing: u32,
|
||||
avg_time_to_build: u32,
|
||||
avg_time_to_use: u32,
|
||||
avg_uber_length: u32,
|
||||
avg_time_before_healing: f32,
|
||||
avg_time_to_build: f32,
|
||||
avg_time_to_use: f32,
|
||||
avg_uber_length: f32,
|
||||
charge_count: u32,
|
||||
drops: u32,
|
||||
}
|
||||
|
||||
impl From<MedicStatsBuilder> for MedicStats {
|
||||
|
|
@ -41,11 +47,12 @@ impl From<MedicStatsBuilder> for MedicStats {
|
|||
near_full_charge_death: builder.near_full_charge_death,
|
||||
deaths_after_uber: builder.deaths_after_uber,
|
||||
avg_time_before_healing: builder.total_time_before_healing
|
||||
/ builder.start_healing_count,
|
||||
avg_time_to_build: builder.total_time_to_build / builder.uber_build_count,
|
||||
avg_time_to_use: builder.total_time_to_use / builder.charge_count,
|
||||
avg_uber_length: builder.total_uber_length / builder.charge_count,
|
||||
/ builder.start_healing_count as f32,
|
||||
avg_time_to_build: builder.total_time_to_build as f32 / builder.uber_build_count as f32,
|
||||
avg_time_to_use: builder.total_time_to_use / builder.charge_count as f32,
|
||||
avg_uber_length: builder.total_uber_length / builder.charge_count as f32,
|
||||
charge_count: builder.charge_count,
|
||||
drops: builder.drops,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -64,13 +71,18 @@ impl EventHandler for MedicStatsHandler {
|
|||
fn does_handle(&self, ty: RawEventType) -> bool {
|
||||
matches!(
|
||||
ty,
|
||||
RawEventType::ChargeDeployed | RawEventType::ChargeEnd | RawEventType::ChargeReady
|
||||
RawEventType::ChargeDeployed
|
||||
| RawEventType::ChargeEnd
|
||||
| RawEventType::ChargeReady
|
||||
| RawEventType::UberAdvantageLost
|
||||
| RawEventType::MedicDeath
|
||||
| RawEventType::FirstHealAfterSpawn
|
||||
)
|
||||
}
|
||||
|
||||
fn handle(
|
||||
&mut self,
|
||||
_time: u32,
|
||||
time: u32,
|
||||
subject: SubjectId,
|
||||
event: &GameEvent,
|
||||
) -> Result<(), Self::Error> {
|
||||
|
|
@ -79,12 +91,60 @@ impl EventHandler for MedicStatsHandler {
|
|||
} else {
|
||||
return Ok(());
|
||||
};
|
||||
match event {
|
||||
GameEvent::ChargeEnded(end) => {
|
||||
let builder = self.0.entry(SteamId3(healer_steam_id)).or_default();
|
||||
builder.total_uber_length += end.duration.unwrap_or_default();
|
||||
builder.last_uber_end = time;
|
||||
}
|
||||
GameEvent::ChargeDeployed(_deployed) => {
|
||||
let builder = self.0.entry(SteamId3(healer_steam_id)).or_default();
|
||||
builder.charge_count += 1;
|
||||
}
|
||||
GameEvent::AdvantageLost(lost) => {
|
||||
let builder = self.0.entry(SteamId3(healer_steam_id)).or_default();
|
||||
builder.advantages_lost += 1;
|
||||
let time = lost.time.unwrap_or_default();
|
||||
if time > builder.biggest_advantage_lost {
|
||||
builder.biggest_advantage_lost = time;
|
||||
}
|
||||
}
|
||||
GameEvent::FirstHeal(first) => {
|
||||
let builder = self.0.entry(SteamId3(healer_steam_id)).or_default();
|
||||
builder.total_time_before_healing += first.time.unwrap_or_default();
|
||||
builder.start_healing_count += 1;
|
||||
builder.last_build_start = time;
|
||||
}
|
||||
GameEvent::ChargeReady => {
|
||||
let builder = self.0.entry(SteamId3(healer_steam_id)).or_default();
|
||||
if builder.last_build_start > 0 {
|
||||
let build_time = time - builder.last_build_start;
|
||||
builder.last_build_start = 0;
|
||||
builder.total_time_to_build += build_time;
|
||||
builder.uber_build_count += 1;
|
||||
}
|
||||
}
|
||||
GameEvent::MedicDeath(death) => {
|
||||
let builder = self.0.entry(SteamId3(healer_steam_id)).or_default();
|
||||
let charge = death.charge.unwrap_or_default();
|
||||
if charge > 95 && charge < 100 {
|
||||
builder.near_full_charge_death += 1;
|
||||
} else if charge >= 100 {
|
||||
builder.drops += 1;
|
||||
}
|
||||
if time - builder.last_uber_end <= 20 {
|
||||
builder.deaths_after_uber += 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn finish(self, _subjects: &SubjectMap) -> Self::Output {
|
||||
self.0
|
||||
.into_iter()
|
||||
.filter(|(_, builder)| builder.start_healing_count > 0)
|
||||
.map(|(steam_id, builder)| (steam_id, builder.into()))
|
||||
.collect()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ pub use healspread::HealSpreadHandler;
|
|||
pub use lobbysettings::{
|
||||
LobbySettingsError, LobbySettingsHandler, Location, Settings as LobbySettings,
|
||||
};
|
||||
pub use medicstats::{MedicStats, MedicStatsHandler};
|
||||
use std::convert::Infallible;
|
||||
use std::error::Error;
|
||||
use std::fmt::Debug;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue