mirror of
https://codeberg.org/icewind/tf-log-parser.git
synced 2026-06-03 18:24:09 +02:00
event rework wip
This commit is contained in:
parent
e83f7928aa
commit
b2d169601c
10 changed files with 240 additions and 63 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::raw_event::RawSubject;
|
use crate::raw_event::RawSubject;
|
||||||
use serde::Serialize;
|
use serde::{Serialize, Serializer};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
@ -135,3 +135,12 @@ impl TryFrom<&RawSubject<'_>> for SubjectData {
|
||||||
/// Steam id formatted as steamid3 when serialized
|
/// Steam id formatted as steamid3 when serialized
|
||||||
#[derive(Debug, Hash, Eq, PartialEq)]
|
#[derive(Debug, Hash, Eq, PartialEq)]
|
||||||
pub struct SteamId3(pub SteamID);
|
pub struct SteamId3(pub SteamID);
|
||||||
|
|
||||||
|
impl Serialize for SteamId3 {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
self.0.steam3().serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,43 @@
|
||||||
use crate::event::{param_parse_with, quoted, u_int};
|
use crate::event::{param_parse, param_parse_with, quoted, u_int};
|
||||||
use crate::raw_event::{subject_parser, RawSubject};
|
use crate::raw_event::{subject_parser, RawSubject};
|
||||||
|
use nom::combinator::opt;
|
||||||
|
use nom::number::complete::float;
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HealedEvent<'a> {
|
pub struct HealedEvent<'a> {
|
||||||
pub subject: RawSubject<'a>,
|
pub target: RawSubject<'a>,
|
||||||
pub amount: u32,
|
pub amount: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn healed_event_parser(input: &str) -> IResult<&str, HealedEvent> {
|
pub fn healed_event_parser(input: &str) -> IResult<&str, HealedEvent> {
|
||||||
let (input, subject) = param_parse_with("against", subject_parser)(input)?;
|
let (input, subject) = param_parse_with("against", subject_parser)(input)?;
|
||||||
let (input, amount) = param_parse_with("healing", quoted(u_int))(input)?;
|
let (input, amount) = param_parse_with("healing", quoted(u_int))(input)?;
|
||||||
Ok((input, HealedEvent { subject, amount }))
|
Ok((
|
||||||
|
input,
|
||||||
|
HealedEvent {
|
||||||
|
target: subject,
|
||||||
|
amount,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ChargeDeployedEvent<'a> {
|
||||||
|
pub medigun: Option<&'a str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn charge_deployed_event_parser(input: &str) -> IResult<&str, ChargeDeployedEvent> {
|
||||||
|
let (input, medigun) = opt(param_parse("healing"))(input)?;
|
||||||
|
Ok((input, ChargeDeployedEvent { medigun }))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ChargeEndedEvent {
|
||||||
|
pub duration: Option<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 }))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,75 @@
|
||||||
mod medic;
|
mod medic;
|
||||||
mod player;
|
mod player;
|
||||||
|
|
||||||
|
use crate::{RawEvent, RawEventType};
|
||||||
pub use medic::*;
|
pub use medic::*;
|
||||||
use nom::bytes::complete::{tag, take_while};
|
use nom::bytes::complete::{tag, take_while};
|
||||||
use nom::character::complete::{alpha1, digit1};
|
use nom::character::complete::{alpha1, digit1};
|
||||||
use nom::combinator::opt;
|
use nom::combinator::opt;
|
||||||
use nom::error::ErrorKind;
|
use nom::error::ErrorKind;
|
||||||
use nom::IResult;
|
use nom::{Err, IResult};
|
||||||
pub use player::*;
|
pub use player::*;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum GameEventError {
|
||||||
|
#[error("malformed game event({ty:?}): {err}")]
|
||||||
|
Error {
|
||||||
|
err: nom::error::Error<String>,
|
||||||
|
ty: RawEventType,
|
||||||
|
},
|
||||||
|
#[error("incomplete event body({0:?})")]
|
||||||
|
Incomplete(RawEventType),
|
||||||
|
}
|
||||||
|
|
||||||
|
trait GameEventErrTrait<T> {
|
||||||
|
fn with_type(self, ty: RawEventType) -> Result<T, GameEventError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> GameEventErrTrait<T> for IResult<&str, T> {
|
||||||
|
fn with_type(self, ty: RawEventType) -> Result<T, GameEventError> {
|
||||||
|
self.map_err(|err| match err {
|
||||||
|
nom::Err::Error(e) | nom::Err::Failure(e) => GameEventError::Error {
|
||||||
|
err: nom::error::Error {
|
||||||
|
input: e.input.to_string(),
|
||||||
|
code: e.code,
|
||||||
|
},
|
||||||
|
ty,
|
||||||
|
},
|
||||||
|
|
||||||
|
Err::Incomplete(_) => GameEventError::Incomplete(ty),
|
||||||
|
})
|
||||||
|
.map(|(rest, t)| t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum GameEvent<'a> {
|
||||||
|
ShotFired(ShotFiredEvent<'a>),
|
||||||
|
ShotHit(ShotHitEvent<'a>),
|
||||||
|
Damage(DamageEvent<'a>),
|
||||||
|
Kill(KillEvent<'a>),
|
||||||
|
Say(&'a str),
|
||||||
|
SayTeam(&'a str),
|
||||||
|
Healed(HealedEvent<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> GameEvent<'a> {
|
||||||
|
pub fn parse(raw: &RawEvent<'a>) -> Result<GameEvent<'a>, GameEventError> {
|
||||||
|
Ok(match raw.ty {
|
||||||
|
RawEventType::ShotFired => {
|
||||||
|
GameEvent::ShotFired(shot_fired_event_parser(raw.params).with_type(raw.ty)?)
|
||||||
|
}
|
||||||
|
RawEventType::SayTeam => GameEvent::SayTeam(raw.params.trim_matches('"')),
|
||||||
|
RawEventType::Say => GameEvent::Say(raw.params.trim_matches('"')),
|
||||||
|
RawEventType::Healed => {
|
||||||
|
GameEvent::Healed(healed_event_parser(raw.params).with_type(raw.ty)?)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
todo!("{:?} not parsed yet", raw.ty);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ParamIter<'a> {
|
struct ParamIter<'a> {
|
||||||
input: &'a str,
|
input: &'a str,
|
||||||
|
|
|
||||||
28
src/lib.rs
28
src/lib.rs
|
|
@ -1,5 +1,6 @@
|
||||||
pub use crate::common::{SteamId3, SubjectData, SubjectError, SubjectId};
|
pub use crate::common::{SteamId3, SubjectData, SubjectError, SubjectId};
|
||||||
use crate::module::{ChatHandler, ChatMessage, EventHandler, HealSpreadHandler, InvalidHealEvent};
|
use crate::event::{GameEvent, GameEventError};
|
||||||
|
use crate::module::{ChatHandler, ChatMessage, EventHandler, HealSpreadHandler};
|
||||||
use crate::raw_event::RawSubject;
|
use crate::raw_event::RawSubject;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
pub use raw_event::{RawEvent, RawEventType};
|
pub use raw_event::{RawEvent, RawEventType};
|
||||||
|
|
@ -20,6 +21,8 @@ pub enum Error<Handler: EventHandler> {
|
||||||
#[error("Malformed logfile: {0}")]
|
#[error("Malformed logfile: {0}")]
|
||||||
Malformed(String),
|
Malformed(String),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
|
MalformedEvent(#[from] GameEventError),
|
||||||
|
#[error("{0}")]
|
||||||
HandlerError(Handler::Error),
|
HandlerError(Handler::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,6 +30,7 @@ impl<Handler: EventHandler> Debug for Error<Handler> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Error::Malformed(e) => e.fmt(f),
|
Error::Malformed(e) => e.fmt(f),
|
||||||
|
Error::MalformedEvent(e) => e.fmt(f),
|
||||||
Error::HandlerError(e) => e.fmt(f),
|
Error::HandlerError(e) => e.fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -85,9 +89,10 @@ pub fn parse_with_handler<Handler: EventHandler>(
|
||||||
let mut subjects = SubjectMap::default();
|
let mut subjects = SubjectMap::default();
|
||||||
|
|
||||||
for event_res in events {
|
for event_res in events {
|
||||||
let event = event_res?;
|
let raw_event = event_res?;
|
||||||
if handler.does_handle(event.ty) || start_time.is_none() {
|
let should_handle = handler.does_handle(raw_event.ty);
|
||||||
let event_time: DateTime<Utc> = (&event.date).try_into().unwrap();
|
if should_handle || start_time.is_none() {
|
||||||
|
let event_time: DateTime<Utc> = (&raw_event.date).try_into().unwrap();
|
||||||
let match_time = match start_time {
|
let match_time = match start_time {
|
||||||
Some(start_time) => (event_time - start_time).num_seconds() as u32,
|
Some(start_time) => (event_time - start_time).num_seconds() as u32,
|
||||||
None => {
|
None => {
|
||||||
|
|
@ -95,9 +100,12 @@ pub fn parse_with_handler<Handler: EventHandler>(
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
handler
|
if should_handle {
|
||||||
.handle(match_time, subjects.insert(&event.subject)?, &event)
|
let event = GameEvent::parse(&raw_event)?;
|
||||||
.map_err(Error::HandlerError)?;
|
handler
|
||||||
|
.handle(match_time, subjects.insert(&raw_event.subject)?, &event)
|
||||||
|
.map_err(Error::HandlerError)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,7 +127,7 @@ pub struct LogOutput {
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum LogError {
|
pub enum LogError {
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
HealSpread(#[from] InvalidHealEvent),
|
MalformedEvent(#[from] GameEventError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventHandler for LogHandler {
|
impl EventHandler for LogHandler {
|
||||||
|
|
@ -134,10 +142,10 @@ impl EventHandler for LogHandler {
|
||||||
&mut self,
|
&mut self,
|
||||||
time: u32,
|
time: u32,
|
||||||
subject: SubjectId,
|
subject: SubjectId,
|
||||||
event: &RawEvent,
|
event: &GameEvent,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.chat.handle(time, subject, event).unwrap();
|
self.chat.handle(time, subject, event).unwrap();
|
||||||
self.heal_spread.handle(time, subject, event)?;
|
self.heal_spread.handle(time, subject, event).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,8 @@
|
||||||
use main_error::MainError;
|
use main_error::MainError;
|
||||||
use serde::Serialize;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::env::args;
|
use std::env::args;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::stdout;
|
use std::io::stdout;
|
||||||
use tf_log_parser::module::{
|
use tf_log_parser::parse;
|
||||||
ChatHandler, ChatMessage, EventHandler, HealSpreadHandler, InvalidHealEvent,
|
|
||||||
};
|
|
||||||
use tf_log_parser::{
|
|
||||||
parse, parse_with_handler, LogHandler, RawEvent, RawEventType, SteamId3, SubjectId, SubjectMap,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() -> Result<(), MainError> {
|
fn main() -> Result<(), MainError> {
|
||||||
let path = args().skip(1).next().expect("No path provided");
|
let path = args().skip(1).next().expect("No path provided");
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::common::{SubjectData, SubjectId};
|
use crate::common::{SubjectData, SubjectId};
|
||||||
|
use crate::event::GameEvent;
|
||||||
use crate::module::EventHandler;
|
use crate::module::EventHandler;
|
||||||
use crate::raw_event::{RawEvent, RawEventType};
|
use crate::raw_event::RawEventType;
|
||||||
use crate::SubjectMap;
|
use crate::SubjectMap;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
|
|
@ -61,22 +62,22 @@ impl EventHandler for ChatHandler {
|
||||||
&mut self,
|
&mut self,
|
||||||
time: u32,
|
time: u32,
|
||||||
subject: SubjectId,
|
subject: SubjectId,
|
||||||
event: &RawEvent,
|
event: &GameEvent,
|
||||||
) -> Result<(), Infallible> {
|
) -> Result<(), Infallible> {
|
||||||
if !matches!(subject, SubjectId::Player(_)) {
|
if !matches!(subject, SubjectId::Player(_)) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
match event.ty {
|
match event {
|
||||||
RawEventType::SayTeam => self.0.push(BareChatMessage {
|
GameEvent::SayTeam(message) => self.0.push(BareChatMessage {
|
||||||
time,
|
time,
|
||||||
subject,
|
subject,
|
||||||
message: event.params.trim_matches('"').into(),
|
message: message.to_string(),
|
||||||
chat_type: ChatType::Team,
|
chat_type: ChatType::Team,
|
||||||
}),
|
}),
|
||||||
RawEventType::Say => self.0.push(BareChatMessage {
|
GameEvent::Say(message) => self.0.push(BareChatMessage {
|
||||||
time,
|
time,
|
||||||
subject,
|
subject,
|
||||||
message: event.params.trim_matches('"').into(),
|
message: message.to_string(),
|
||||||
chat_type: ChatType::All,
|
chat_type: ChatType::All,
|
||||||
}),
|
}),
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,17 @@
|
||||||
use crate::common::{SteamId3, SubjectId};
|
use crate::common::{SteamId3, SubjectId};
|
||||||
use crate::event::healed_event_parser;
|
use crate::event::GameEvent;
|
||||||
use crate::module::EventHandler;
|
use crate::module::EventHandler;
|
||||||
use crate::raw_event::{RawEvent, RawEventType};
|
use crate::raw_event::RawEventType;
|
||||||
use crate::SubjectMap;
|
use crate::SubjectMap;
|
||||||
use serde::{Serialize, Serializer};
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::{Infallible, TryFrom};
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
impl Serialize for SteamId3 {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
self.0.steam3().serialize(serializer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct HealSpreadHandler(HashMap<SteamId3, HashMap<SteamId3, u32>>);
|
pub struct HealSpreadHandler(HashMap<SteamId3, HashMap<SteamId3, u32>>);
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
#[error("Invalid healed event: {0}")]
|
|
||||||
pub struct InvalidHealEvent(String);
|
|
||||||
|
|
||||||
impl EventHandler for HealSpreadHandler {
|
impl EventHandler for HealSpreadHandler {
|
||||||
type Output = HashMap<SteamId3, HashMap<SteamId3, u32>>;
|
type Output = HashMap<SteamId3, HashMap<SteamId3, u32>>;
|
||||||
type Error = InvalidHealEvent;
|
type Error = Infallible;
|
||||||
|
|
||||||
fn does_handle(&self, ty: RawEventType) -> bool {
|
fn does_handle(&self, ty: RawEventType) -> bool {
|
||||||
matches!(ty, RawEventType::Healed)
|
matches!(ty, RawEventType::Healed)
|
||||||
|
|
@ -36,17 +21,15 @@ impl EventHandler for HealSpreadHandler {
|
||||||
&mut self,
|
&mut self,
|
||||||
_time: u32,
|
_time: u32,
|
||||||
subject: SubjectId,
|
subject: SubjectId,
|
||||||
event: &RawEvent,
|
event: &GameEvent,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
let healer_steam_id = if let Some(steam_id) = subject.steam_id() {
|
let healer_steam_id = if let Some(steam_id) = subject.steam_id() {
|
||||||
steam_id
|
steam_id
|
||||||
} else {
|
} else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
if matches!(event.ty, RawEventType::Healed) {
|
if let GameEvent::Healed(heal_event) = event {
|
||||||
let (_, heal_event) = healed_event_parser(event.params)
|
if let Ok(target_subject) = SubjectId::try_from(&heal_event.target) {
|
||||||
.map_err(|_| InvalidHealEvent(event.params.into()))?;
|
|
||||||
if let Ok(target_subject) = SubjectId::try_from(&heal_event.subject) {
|
|
||||||
if let Some(target_steam_id) = target_subject.steam_id() {
|
if let Some(target_steam_id) = target_subject.steam_id() {
|
||||||
let healed = self
|
let healed = self
|
||||||
.0
|
.0
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::common::SubjectId;
|
use crate::common::SubjectId;
|
||||||
|
use crate::event::GameEvent;
|
||||||
use crate::module::EventHandler;
|
use crate::module::EventHandler;
|
||||||
use crate::raw_event::{RawEvent, RawEventType};
|
use crate::raw_event::RawEventType;
|
||||||
use crate::SubjectMap;
|
use crate::SubjectMap;
|
||||||
use chrono::{DateTime, FixedOffset, NaiveDateTime, TimeZone, Utc};
|
use chrono::{DateTime, FixedOffset, NaiveDateTime, TimeZone, Utc};
|
||||||
use std::str::{FromStr, ParseBoolError};
|
use std::str::{FromStr, ParseBoolError};
|
||||||
|
|
@ -138,13 +139,12 @@ impl EventHandler for LobbySettingsHandler {
|
||||||
&mut self,
|
&mut self,
|
||||||
_time: u32,
|
_time: u32,
|
||||||
subject: SubjectId,
|
subject: SubjectId,
|
||||||
event: &RawEvent,
|
event: &GameEvent,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
if !matches!(subject, SubjectId::Console) {
|
if !matches!(subject, SubjectId::Console) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if matches!(event.ty, RawEventType::Say) {
|
if let GameEvent::Say(msg) = event {
|
||||||
let msg = event.params.trim_matches('"');
|
|
||||||
if let Some((id, _)) = msg
|
if let Some((id, _)) = msg
|
||||||
.strip_prefix("TF2Center Lobby #")
|
.strip_prefix("TF2Center Lobby #")
|
||||||
.and_then(|s| str::split_once(s, " |"))
|
.and_then(|s| str::split_once(s, " |"))
|
||||||
|
|
|
||||||
91
src/module/medicstats.rs
Normal file
91
src/module/medicstats.rs
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
use crate::common::{SteamId3, SubjectId};
|
||||||
|
use crate::event::GameEvent;
|
||||||
|
use crate::module::EventHandler;
|
||||||
|
use crate::raw_event::RawEventType;
|
||||||
|
use crate::SubjectMap;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct MedicStatsBuilder {
|
||||||
|
advantages_lost: u32,
|
||||||
|
biggest_advantage_lost: u32,
|
||||||
|
near_full_charge_death: u32,
|
||||||
|
deaths_after_uber: u32,
|
||||||
|
total_time_before_healing: u32,
|
||||||
|
start_healing_count: u32,
|
||||||
|
total_time_to_build: u32,
|
||||||
|
uber_build_count: u32,
|
||||||
|
total_time_to_use: u32,
|
||||||
|
total_uber_length: u32,
|
||||||
|
charge_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MedicStats {
|
||||||
|
advantages_lost: u32,
|
||||||
|
biggest_advantage_lost: u32,
|
||||||
|
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,
|
||||||
|
charge_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MedicStatsBuilder> for MedicStats {
|
||||||
|
fn from(builder: MedicStatsBuilder) -> Self {
|
||||||
|
MedicStats {
|
||||||
|
advantages_lost: builder.advantages_lost,
|
||||||
|
biggest_advantage_lost: builder.biggest_advantage_lost,
|
||||||
|
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,
|
||||||
|
charge_count: builder.charge_count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
#[error("Invalid charge event: {0}")]
|
||||||
|
pub struct InvalidMedicEvent(String);
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct MedicStatsHandler(HashMap<SteamId3, MedicStatsBuilder>);
|
||||||
|
|
||||||
|
impl EventHandler for MedicStatsHandler {
|
||||||
|
type Output = HashMap<SteamId3, MedicStats>;
|
||||||
|
type Error = InvalidMedicEvent;
|
||||||
|
|
||||||
|
fn does_handle(&self, ty: RawEventType) -> bool {
|
||||||
|
matches!(
|
||||||
|
ty,
|
||||||
|
RawEventType::ChargeDeployed | RawEventType::ChargeEnd | RawEventType::ChargeReady
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle(
|
||||||
|
&mut self,
|
||||||
|
_time: u32,
|
||||||
|
subject: SubjectId,
|
||||||
|
event: &GameEvent,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
let healer_steam_id = if let Some(steam_id) = subject.steam_id() {
|
||||||
|
steam_id
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish(self, _subjects: &SubjectMap) -> Self::Output {
|
||||||
|
self.0
|
||||||
|
.into_iter()
|
||||||
|
.map(|(steam_id, builder)| (steam_id, builder.into()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
use crate::common::SubjectId;
|
use crate::common::SubjectId;
|
||||||
use crate::raw_event::{RawEvent, RawEventType};
|
use crate::event::GameEvent;
|
||||||
|
use crate::raw_event::RawEventType;
|
||||||
use crate::SubjectMap;
|
use crate::SubjectMap;
|
||||||
pub use chat::{ChatHandler, ChatMessage, ChatType};
|
pub use chat::{ChatHandler, ChatMessage, ChatType};
|
||||||
pub use healspread::{HealSpreadHandler, InvalidHealEvent};
|
pub use healspread::HealSpreadHandler;
|
||||||
pub use lobbysettings::{
|
pub use lobbysettings::{
|
||||||
LobbySettingsError, LobbySettingsHandler, Location, Settings as LobbySettings,
|
LobbySettingsError, LobbySettingsHandler, Location, Settings as LobbySettings,
|
||||||
};
|
};
|
||||||
|
|
@ -14,6 +15,7 @@ use thiserror::Error;
|
||||||
mod chat;
|
mod chat;
|
||||||
mod healspread;
|
mod healspread;
|
||||||
mod lobbysettings;
|
mod lobbysettings;
|
||||||
|
mod medicstats;
|
||||||
|
|
||||||
pub trait EventHandler: Default {
|
pub trait EventHandler: Default {
|
||||||
type Output;
|
type Output;
|
||||||
|
|
@ -25,7 +27,7 @@ pub trait EventHandler: Default {
|
||||||
&mut self,
|
&mut self,
|
||||||
time: u32,
|
time: u32,
|
||||||
subject: SubjectId,
|
subject: SubjectId,
|
||||||
event: &RawEvent,
|
event: &GameEvent,
|
||||||
) -> Result<(), Self::Error>;
|
) -> Result<(), Self::Error>;
|
||||||
|
|
||||||
fn finish(self, subjects: &SubjectMap) -> Self::Output;
|
fn finish(self, subjects: &SubjectMap) -> Self::Output;
|
||||||
|
|
@ -49,7 +51,7 @@ impl<Head: EventHandler, Tail: EventHandler> EventHandler for HandlerStack<Head,
|
||||||
&mut self,
|
&mut self,
|
||||||
time: u32,
|
time: u32,
|
||||||
subject: SubjectId,
|
subject: SubjectId,
|
||||||
event: &RawEvent,
|
event: &GameEvent,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.head
|
self.head
|
||||||
.handle(time, subject, event)
|
.handle(time, subject, event)
|
||||||
|
|
@ -100,7 +102,7 @@ impl<Handler: EventHandler> EventHandler for OptionalHandler<Handler> {
|
||||||
&mut self,
|
&mut self,
|
||||||
time: u32,
|
time: u32,
|
||||||
subject: SubjectId,
|
subject: SubjectId,
|
||||||
event: &RawEvent,
|
event: &GameEvent,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
let res = if let OptionalHandler::Active(handler) = self {
|
let res = if let OptionalHandler::Active(handler) = self {
|
||||||
handler.handle(time, subject, event)
|
handler.handle(time, subject, event)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue