diff options
author | Daniel Schadt <kingdread@gmx.de> | 2018-07-07 03:23:25 +0200 |
---|---|---|
committer | Daniel Schadt <kingdread@gmx.de> | 2018-07-07 03:23:25 +0200 |
commit | 22051473844bddb60c8c062f511fd4b1f90d48bd (patch) | |
tree | 8001a9ff97ae7d065c2e6c56cf5fe5a98d44e6b4 | |
parent | 4ea1d4f3e5082925874a271d14cc143ebf80912f (diff) | |
download | evtclib-22051473844bddb60c8c062f511fd4b1f90d48bd.tar.gz evtclib-22051473844bddb60c8c062f511fd4b1f90d48bd.tar.bz2 evtclib-22051473844bddb60c8c062f511fd4b1f90d48bd.zip |
base for mechanic tracking
-rw-r--r-- | src/lib.rs | 27 | ||||
-rw-r--r-- | src/main.rs | 24 | ||||
-rw-r--r-- | src/statistics/gamedata.rs | 20 | ||||
-rw-r--r-- | src/statistics/mechanics.rs | 42 | ||||
-rw-r--r-- | src/statistics/mod.rs | 11 | ||||
-rw-r--r-- | src/statistics/trackers.rs | 38 |
6 files changed, 122 insertions, 40 deletions
@@ -95,27 +95,27 @@ pub enum AgentName { /// An agent. #[derive(Debug, Clone, Getters)] pub struct Agent { - #[get="pub"] + #[get = "pub"] addr: u64, - #[get="pub"] + #[get = "pub"] kind: AgentKind, - #[get="pub"] + #[get = "pub"] toughness: i16, - #[get="pub"] + #[get = "pub"] concentration: i16, - #[get="pub"] + #[get = "pub"] healing: i16, - #[get="pub"] + #[get = "pub"] condition: i16, - #[get="pub"] + #[get = "pub"] name: AgentName, - #[get="pub"] + #[get = "pub"] instance_id: u16, - #[get="pub"] + #[get = "pub"] first_aware: u64, - #[get="pub"] + #[get = "pub"] last_aware: u64, - #[get="pub"] + #[get = "pub"] master_agent: Option<u64>, } @@ -196,6 +196,11 @@ impl Log { self.boss_agents().into_iter().any(|a| *a.addr() == addr) } + /// Returns the boss/encounter id. + pub fn boss_id(&self) -> u16 { + self.boss_id + } + /// Return all events present in this log. pub fn events(&self) -> &[Event] { &self.events diff --git a/src/main.rs b/src/main.rs index c4f4e0a..81ab36c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -143,11 +143,16 @@ pub fn main() -> Result<(), evtclib::raw::parser::ParseError> { let my_addr = me(&processed); let mine = stats.agent_stats.get(&my_addr).expect("My stats not found"); - let my_damage = stats.damage_log.damage(|m| m.source == my_addr && processed.is_boss(m.target)); + let my_damage = stats + .damage_log + .damage(|m| m.source == my_addr && processed.is_boss(m.target)); - let combat_time = (mine.exit_combat - mine.enter_combat) as f32/ 1000.; + let combat_time = (mine.exit_combat - mine.enter_combat) as f32 / 1000.; println!("Damages: {:?}", stats.damage_log); - println!("Combat time: {} ({} till {})", combat_time, mine.enter_combat, mine.exit_combat); + println!( + "Combat time: {} ({} till {})", + combat_time, mine.enter_combat, mine.exit_combat + ); println!("My boss dps: {:?}", my_damage.0 as f32 / combat_time); for boon in evtclib::statistics::gamedata::BOONS { @@ -157,6 +162,19 @@ pub fn main() -> Result<(), evtclib::raw::parser::ParseError> { println!("{}: {}", boon.1, avg); } + for agent in processed.players() { + println!("{:?}", agent.name()); + for mechanic in evtclib::statistics::gamedata::get_mechanics(processed.boss_id()) { + println!( + "{}: {}", + mechanic.2, + stats + .mechanic_log + .count(|m, a| m == mechanic && a == *agent.addr()) + ); + } + } + //println!("NPCs: {:#?}", processed.npcs().collect::<Vec<_>>()); println!("Bosses: {:#?}", processed.boss_agents()); diff --git a/src/statistics/gamedata.rs b/src/statistics/gamedata.rs index 1b5fec6..3bd895e 100644 --- a/src/statistics/gamedata.rs +++ b/src/statistics/gamedata.rs @@ -13,6 +13,8 @@ pub enum Boss { /// second phase. This agent will have another ID, see /// [`XERA_PHASE2_ID`](constant.XERA_PHASE2_ID.html). Xera = 0x3F76, + + Samarog = 0x4324, } /// ID for Xera in the second phase. @@ -112,15 +114,23 @@ pub enum Trigger { pub struct Mechanic(pub u16, pub Trigger, pub &'static str); macro_rules! mechanics { - ($boss_id:expr => [ $($name:expr => $trigger:expr,)* ]) => { - $(Mechanic($boss_id as u16, $trigger, $name)),* + ( $( $boss_id:expr => [ $($name:expr => $trigger:expr,)* ], )* ) => { + &[ + $( $(Mechanic($boss_id as u16, $trigger, $name)),* ),* + ] } } /// A slice of all mechanics that we know about. -pub static MECHANICS: &[Mechanic] = &[mechanics! { Boss::ValeGuardian => [ - "Unstable Magic Spike" => Trigger::SkillOnPlayer(31860), -]}]; +pub static MECHANICS: &[Mechanic] = mechanics! { + Boss::ValeGuardian => [ + "Unstable Magic Spike" => Trigger::SkillOnPlayer(31860), + ], + Boss::Samarog => [ + "Prisoner Sweep" => Trigger::SkillOnPlayer(38168), + "Shockwave" => Trigger::SkillOnPlayer(37996), + ], +}; /// Get all mechanics that belong to the given boss. pub fn get_mechanics(boss_id: u16) -> Vec<&'static Mechanic> { diff --git a/src/statistics/mechanics.rs b/src/statistics/mechanics.rs new file mode 100644 index 0000000..5a16204 --- /dev/null +++ b/src/statistics/mechanics.rs @@ -0,0 +1,42 @@ +use super::gamedata::Mechanic; +use super::math::{Monoid, RecordFunc, Semigroup}; + +use std::fmt; + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Counter(u32); + +impl Semigroup for Counter { + #[inline] + fn combine(&self, other: &Counter) -> Counter { + Counter(self.0 + other.0) + } +} + +impl Monoid for Counter { + #[inline] + fn mempty() -> Counter { + Counter(0) + } +} + +#[derive(Clone, Default)] +pub struct MechanicLog { + inner: RecordFunc<u64, (&'static Mechanic, u64), Counter>, +} + +impl MechanicLog { + pub fn increase(&mut self, time: u64, mechanic: &'static Mechanic, agent: u64) { + self.inner.insert(time, (mechanic, agent), Counter(1)); + } + + pub fn count<F: FnMut(&'static Mechanic, u64) -> bool>(&self, mut filter: F) -> u32 { + self.inner.tally_only(|(a, b)| filter(a, *b)).0 + } +} + +impl fmt::Debug for MechanicLog { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "MechanicLog {{ ... }}") + } +} diff --git a/src/statistics/mod.rs b/src/statistics/mod.rs index a46fc27..f46f778 100644 --- a/src/statistics/mod.rs +++ b/src/statistics/mod.rs @@ -7,10 +7,12 @@ pub mod boon; pub mod damage; pub mod gamedata; pub mod math; +pub mod mechanics; pub mod trackers; use self::boon::BoonLog; use self::damage::DamageLog; +use self::mechanics::MechanicLog; use self::trackers::{RunnableTracker, Tracker}; pub type StatResult<T> = Result<T, StatError>; @@ -41,6 +43,8 @@ macro_rules! try_tracker { pub struct Statistics { /// The complete damage log. pub damage_log: DamageLog, + /// The complete mechanics log. + pub mechanic_log: MechanicLog, /// A map mapping agent addresses to their stats. pub agent_stats: HashMap<u64, AgentStats>, } @@ -90,6 +94,10 @@ pub fn calculate(log: &Log) -> StatResult<Statistics> { let mut combat_time_tracker = trackers::CombatTimeTracker::new(); let mut boon_tracker = trackers::BoonTracker::new(); + let mechanics = gamedata::get_mechanics(log.boss_id); + let boss_addr = log.boss_agents().into_iter().map(|x| *x.addr()).collect(); + let mut mechanic_tracker = trackers::MechanicTracker::new(boss_addr, mechanics); + run_trackers( log, &mut [ @@ -97,6 +105,7 @@ pub fn calculate(log: &Log) -> StatResult<Statistics> { &mut log_start_tracker, &mut combat_time_tracker, &mut boon_tracker, + &mut mechanic_tracker, ], )?; @@ -131,9 +140,11 @@ pub fn calculate(log: &Log) -> StatResult<Statistics> { } let damage_log = try_tracker!(damage_tracker.finalize()); + let mechanic_log = try_tracker!(mechanic_tracker.finalize()); Ok(Statistics { damage_log, + mechanic_log, agent_stats, }) } diff --git a/src/statistics/trackers.rs b/src/statistics/trackers.rs index d18e9c5..93c7f49 100644 --- a/src/statistics/trackers.rs +++ b/src/statistics/trackers.rs @@ -23,6 +23,7 @@ use super::super::{Event, EventKind, Log}; use super::boon::{BoonLog, BoonQueue}; use super::damage::{DamageLog, DamageType}; use super::gamedata::{self, Mechanic, Trigger}; +use super::mechanics::MechanicLog; use fnv::FnvHashMap; @@ -354,37 +355,33 @@ impl Tracker for BoonTracker { /// A tracker that tracks boss mechanics for each player. pub struct MechanicTracker { - mechanics: HashMap<&'static Mechanic, u32>, + log: MechanicLog, available_mechanics: Vec<&'static Mechanic>, - boss_address: u64, - agent_address: u64, + boss_addresses: Vec<u64>, } impl MechanicTracker { /// Create a new mechanic tracker that watches over the given mechanics. - pub fn new( - agent_address: u64, - boss_address: u64, - mechanics: Vec<&'static Mechanic>, - ) -> MechanicTracker { + pub fn new(boss_addresses: Vec<u64>, mechanics: Vec<&'static Mechanic>) -> MechanicTracker { MechanicTracker { - mechanics: HashMap::new(), + log: MechanicLog::default(), available_mechanics: mechanics, - boss_address, - agent_address, + boss_addresses, } } } +impl MechanicTracker { + fn is_boss(&self, addr: u64) -> bool { + self.boss_addresses.contains(&addr) + } +} + impl Tracker for MechanicTracker { - type Stat = HashMap<&'static Mechanic, u32>; + type Stat = MechanicLog; type Error = !; fn feed(&mut self, event: &Event) -> Result<(), Self::Error> { - fn increase(map: &mut HashMap<&'static Mechanic, u32>, entry: &'static Mechanic) { - *map.entry(entry).or_insert(0) += 1; - } - for mechanic in &self.available_mechanics { match (&event.kind, &mechanic.1) { ( @@ -395,11 +392,10 @@ impl Tracker for MechanicTracker { .. }, Trigger::SkillOnPlayer(trigger_id), - ) if skill_id == trigger_id - && *source_agent_addr == self.boss_address - && *destination_agent_addr == self.agent_address => + ) if skill_id == trigger_id && self.is_boss(*source_agent_addr) => { - increase(&mut self.mechanics, mechanic); + self.log + .increase(event.time, mechanic, *destination_agent_addr); } _ => (), } @@ -408,6 +404,6 @@ impl Tracker for MechanicTracker { } fn finalize(self) -> Result<Self::Stat, Self::Error> { - Ok(self.mechanics) + Ok(self.log) } } |