diff options
author | Daniel Schadt <kingdread@gmx.de> | 2020-07-24 14:23:53 +0200 |
---|---|---|
committer | Daniel Schadt <kingdread@gmx.de> | 2020-07-24 14:23:53 +0200 |
commit | 71528905ed228750559a41144a2e0a95db3e6805 (patch) | |
tree | 4e46c6cbd3a3e83ab707e7156b345fbe7f3048ea /src/lib.rs | |
parent | 01354b0934409c355831bb4202f998fe5dbdc335 (diff) | |
parent | 9d27ec7034f9ad07d8a1d74ab30fdc470de4e02d (diff) | |
download | evtclib-71528905ed228750559a41144a2e0a95db3e6805.tar.gz evtclib-71528905ed228750559a41144a2e0a95db3e6805.tar.bz2 evtclib-71528905ed228750559a41144a2e0a95db3e6805.zip |
Merge branch 'analyzers'
This brings in proper fight outcome detection, which is nice and needed
for downstream applications (raidgrep/ezau).
Furthermore, this cleans up the CM detection a bit by moving away from
the "descriptive" trigger way to just having dynamically dispatched
methods for every log.
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 89 |
1 files changed, 15 insertions, 74 deletions
@@ -88,7 +88,6 @@ //! While there are legitimate use cases for writing/modification support, they are currently not //! implemented (but might be in a future version). -use std::collections::HashMap; use std::convert::TryFrom; use std::marker::PhantomData; @@ -105,9 +104,11 @@ mod processing; pub use processing::{process, process_file, process_stream, Compression}; pub mod gamedata; -use gamedata::CmTrigger; pub use gamedata::{Boss, EliteSpec, Profession}; +pub mod analyzers; +pub use analyzers::{Analyzer, Outcome}; + /// Any error that can occur during the processing of evtc files. #[derive(Error, Debug)] pub enum EvtcError { @@ -759,6 +760,8 @@ impl Log { pub fn boss_agents(&self) -> Vec<&Agent> { let boss_ids = if self.boss_id == Boss::Xera as u16 { vec![self.boss_id, gamedata::XERA_PHASE2_ID] + } else if self.boss_id == Boss::LargosTwins as u16 { + vec![gamedata::NIKARE_ID, gamedata::KENUT_ID] } else { vec![self.boss_id] }; @@ -789,6 +792,11 @@ impl Log { Boss::from_u16(self.boss_id) } + /// Return an analyzer suitable to analyze the given log. + pub fn analyzer<'s>(&'s self) -> Option<Box<dyn Analyzer + 's>> { + analyzers::for_log(&self) + } + /// Return all events present in this log. #[inline] pub fn events(&self) -> &[Event] { @@ -832,46 +840,7 @@ impl Log { /// * We cannot determine whether the CM was active /// * The boss is not known pub fn is_cm(&self) -> bool { - let trigger = self - .encounter() - .map(Boss::cm_trigger) - .unwrap_or(CmTrigger::Unknown); - match trigger { - CmTrigger::HpThreshold(hp_threshold) => { - for event in self.events() { - if let EventKind::MaxHealthUpdate { - agent_addr, - max_health, - } = *event.kind() - { - if self.is_boss(agent_addr) && max_health >= hp_threshold as u64 { - return true; - } - } - } - false - } - - CmTrigger::BuffPresent(wanted_buff_id) => { - for event in self.events() { - if let EventKind::BuffApplication { buff_id, .. } = *event.kind() { - if buff_id == wanted_buff_id { - return true; - } - } - } - false - } - - CmTrigger::TimeBetweenBuffs(buff_id, threshold) => { - let tbb = time_between_buffs(&self.events, buff_id); - tbb != 0 && tbb <= threshold - } - - CmTrigger::Always => true, - - CmTrigger::None | CmTrigger::Unknown => false, - } + self.analyzer().map(|a| a.is_cm()).unwrap_or(false) } /// Get the timestamp of when the log was started. @@ -915,6 +884,10 @@ impl Log { /// /// This can be used as an indication whether the fight was successful (`true`) or not /// (`false`). + /// + /// If you want to properly determine whether a fight was successful, check the + /// [`Analyzer::outcome`][Analyzer::outcome] method, which does more sophisticated checks + /// (dependent on the boss). pub fn was_rewarded(&self) -> bool { self.events().iter().any(|e| { if let EventKind::Reward { .. } = e.kind() { @@ -925,35 +898,3 @@ impl Log { }) } } - -fn time_between_buffs(events: &[Event], wanted_buff_id: u32) -> u64 { - let mut time_maps: HashMap<u64, Vec<u64>> = HashMap::new(); - for event in events { - if let EventKind::BuffApplication { - destination_agent_addr, - buff_id, - .. - } = event.kind() - { - if *buff_id == wanted_buff_id { - time_maps - .entry(*destination_agent_addr) - .or_default() - .push(event.time()); - } - } - } - let timestamps = if let Some(ts) = time_maps.values().max_by_key(|v| v.len()) { - ts - } else { - return 0; - }; - timestamps - .iter() - .zip(timestamps.iter().skip(1)) - .map(|(a, b)| b - a) - // Arbitrary limit to filter out duplicated buff application events - .filter(|x| *x > 50) - .min() - .unwrap_or(0) -} |