aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/event.rs140
-rw-r--r--src/gamedata.rs14
-rw-r--r--src/raw/types.rs73
3 files changed, 222 insertions, 5 deletions
diff --git a/src/event.rs b/src/event.rs
index 0a904bc..27ed2db 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -1,7 +1,7 @@
//! Event definitions.
//!
//! This module contains the different types of events in their high-level form.
-use super::raw;
+use super::{gamedata::Ruleset, raw};
use std::convert::TryFrom;
use std::fmt::Write;
@@ -22,10 +22,12 @@ pub enum FromRawEventError {
UnknownDamageEvent,
#[error("an unknown language byte was found")]
UnknownLanguage,
+ #[error("an unknown ruleset bit was found")]
+ UnknownRuleset,
#[error("the event contains invalid text")]
InvalidText,
- #[error("an unexpected REPLINFO was found")]
- UnexpectedReplInfo,
+ #[error("an unexpected internal event was found")]
+ UnexpectedInternalEvent,
}
/// A rusty enum for all possible combat events.
@@ -214,6 +216,69 @@ pub enum EventKind {
/// Note that the tag id is volatile and depends on the game build. Do not rely on the actual
/// value of this!
Tag { agent_addr: u64, tag_id: i32 },
+
+ /// The given agent has a new barrier percentage.
+ ///
+ /// The percentage is given multiplied by 100, so 95% is given as 9500.
+ BarrierUpdate {
+ agent_addr: u64,
+ percentage: u32,
+ },
+
+ /// The arcdps stats have been reset.
+ ///
+ /// The given ID is the species ID of the agent that triggered the reset.
+ StatReset { species_id: u64 },
+
+ /// When the map instance has been started.
+ ///
+ /// The instance age is given in milliseconds.
+ InstanceStart {
+ age: u64,
+ },
+
+ /// The log's boss agent changed.
+ LogNpcUpdate {
+ species_id: u64,
+ agent_address: u64,
+ timestamp: u32,
+ },
+
+ /// The fractal scale.
+ FractalScale { scale: u32 },
+
+ /// Which ruleset is active.
+ Ruleset { ruleset: Ruleset },
+
+ /// A squad ground marker has been placed.
+ ///
+ /// `x`/`y`/`z` give the coordinates. If they are zero or infinite, the marker has been
+ /// removed.
+ ///
+ /// `marker_index` gives the index of the marker (e.g. 0 is arrow).
+ SquadMarker {
+ x: f32,
+ y: f32,
+ z: f32,
+ marker_index: u8,
+ },
+
+ /// Version string of the arcdps build.
+ ArcBuild {
+ build: String,
+ },
+
+ /// Glider state of the given agent.
+ Glider {
+ agent_addr: u64,
+ deployed: bool,
+ },
+
+ /// A stun has been broken early.
+ Stunbreak {
+ agent_addr: u64,
+ remaining_duration: i32,
+ }
}
/// A higher-level representation of a combat event.
@@ -414,7 +479,10 @@ impl TryFrom<&raw::CbtEvent> for Event {
},
// The README says "internal use, won't see anywhere", so if we find one, we treat it
// as an error.
- CbtStateChange::ReplInfo => return Err(FromRawEventError::UnexpectedReplInfo),
+ CbtStateChange::ReplInfo
+ | CbtStateChange::IdleEvent => {
+ return Err(FromRawEventError::UnexpectedInternalEvent)
+ },
CbtStateChange::StackActive => EventKind::StackActive {
agent_addr: raw_event.src_agent,
stack_id: raw_event.dst_agent as u32,
@@ -424,6 +492,59 @@ impl TryFrom<&raw::CbtEvent> for Event {
stack_id: raw_event.padding_end,
duration: raw_event.value,
},
+ CbtStateChange::BarrierUpdate => EventKind::BarrierUpdate {
+ agent_addr: raw_event.src_agent,
+ percentage: raw_event.dst_agent as u32,
+ },
+ CbtStateChange::StatReset => EventKind::StatReset {
+ species_id: raw_event.src_agent
+ },
+ CbtStateChange::InstanceStart => EventKind::InstanceStart {
+ age: raw_event.src_agent,
+ },
+ CbtStateChange::LogNpcUpdate => EventKind::LogNpcUpdate {
+ species_id: raw_event.src_agent,
+ agent_address: raw_event.dst_agent,
+ timestamp: u32::from_le_bytes(raw_event.value.to_le_bytes()),
+ },
+ CbtStateChange::FractalScale => EventKind::FractalScale {
+ scale: raw_event.src_agent as u32,
+ },
+ CbtStateChange::Ruleset => EventKind::Ruleset {
+ ruleset: if raw_event.src_agent & 1 > 0 {
+ Ruleset::PvE
+ } else if raw_event.src_agent & 2 > 0 {
+ Ruleset::WvW
+ } else if raw_event.src_agent & 4 > 0 {
+ Ruleset::PvP
+ } else {
+ return Err(FromRawEventError::UnknownRuleset);
+ }
+ },
+ CbtStateChange::SquadMarker => EventKind::SquadMarker {
+ x: f32::from_bits((raw_event.src_agent >> 32) as u32),
+ y: f32::from_bits((raw_event.src_agent & 0xffff_ffff) as u32),
+ z: f32::from_bits((raw_event.dst_agent >> 32) as u32),
+ marker_index: raw_event.skillid as u8,
+ },
+ CbtStateChange::ArcBuild => {
+ // Skip 8 bytes because the text starts at src_agent, and not at time.
+ let data = &get_error_bytes(raw_event)[8..];
+ EventKind::ArcBuild {
+ build: raw::cstr_up_to_nul(data)
+ .ok_or(FromRawEventError::InvalidText)?
+ .to_string_lossy()
+ .into_owned(),
+ }
+ },
+ CbtStateChange::Glider => EventKind::Glider {
+ agent_addr: raw_event.src_agent,
+ deployed: raw_event.value > 0,
+ },
+ CbtStateChange::Stunbreak => EventKind::Stunbreak {
+ agent_addr: raw_event.src_agent,
+ remaining_duration: raw_event.value,
+ },
// XXX: implement proper handling of those events!
CbtStateChange::BuffInfo
| CbtStateChange::BuffFormula
@@ -431,7 +552,16 @@ impl TryFrom<&raw::CbtEvent> for Event {
| CbtStateChange::SkillTiming
| CbtStateChange::BreakbarState
| CbtStateChange::BreakbarPercent
- | CbtStateChange::BarrierUpdate => {
+ | CbtStateChange::RateHealth
+ | CbtStateChange::IdToGuid
+ | CbtStateChange::Effect2
+ // Probably not too useful for us:
+ | CbtStateChange::Extension
+ | CbtStateChange::ApiDelayed
+ | CbtStateChange::ExtensionCombat
+ // Retired, would need to find docs first:
+ | CbtStateChange::Last90BeforeDown
+ | CbtStateChange::Effect => {
return Err(FromRawEventError::UnknownStateChange(
raw_event.is_statechange,
))
diff --git a/src/gamedata.rs b/src/gamedata.rs
index c6f3040..8fcd45f 100644
--- a/src/gamedata.rs
+++ b/src/gamedata.rs
@@ -8,6 +8,20 @@ use std::{
};
use thiserror::Error;
+/// The different rulesets, affecting skill & trait balancing.
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub enum Ruleset {
+ /// Player-versus-Environment.
+ ///
+ /// Active in open world, raids, strikes, fractals, ...
+ PvE,
+ /// World-versus-World.
+ WvW,
+ /// (Structured) Player-versus-Player.
+ PvP,
+}
+
/// The game mode in which a log was produced.
///
/// Note that the distinction made here is relatively arbitrary, but hopefully still useful. In
diff --git a/src/raw/types.rs b/src/raw/types.rs
index 1bc3d08..b272c9b 100644
--- a/src/raw/types.rs
+++ b/src/raw/types.rs
@@ -191,12 +191,85 @@ pub enum CbtStateChange {
/// `src_agent` is agent, `value` is float with percent
BreakbarPercent,
/// `time` is the start of the error string.
+ ///
+ /// In modern arcdps, this is called `CBTS_INTEGRITY`, but we leave it for backward
+ /// compatibility.
Error,
/// `src_agent` is the agent, `value` is the tag id
+ ///
+ /// In modern arcdps, this is called `CBTS_MARKER`, but we leave it for backward compatibility.
Tag,
/// `src_agent` is at barrier percent, `dst_agent` is the percentage times 10000 (so 99.5%
/// will be 9950).
BarrierUpdate,
+ /// `src_agent` is the species id of the agent that triggered the reset.
+ StatReset,
+ /// For extension use, not managed by arcdps.
+ Extension,
+ /// For events that are deemed unsafe to report real-time.
+ ///
+ /// Should not appear in evtc files.
+ ApiDelayed,
+ /// Map instance start.
+ ///
+ /// `src_agent` are milliseconds since the instance was created.
+ InstanceStart,
+ /// Tick health.
+ ///
+ /// `src_agent` is 25 - tickrate, when tickrate <= 20
+ RateHealth,
+ /// No longer used.
+ Last90BeforeDown,
+ /// No longer used.
+ Effect,
+ /// content id to guid association for volatile types
+ ///
+ /// src_agent: (uint8_t*)&src_agent is uint8_t[16] guid of content
+ /// overstack_value: is of enum contentlocal
+ IdToGuid,
+ /// Log boss agent changed.
+ ///
+ /// src_agent: species id of agent
+ /// dst_agent: related to agent
+ /// value: as uint32_t, server unix timestamp
+ LogNpcUpdate,
+ /// Internal use.
+ IdleEvent,
+ /// For extension use.
+ ExtensionCombat,
+ /// Fractal scale.
+ ///
+ /// `src_agent` will be the fractal scale.
+ FractalScale,
+ /// Play graphical effect.
+ ///
+ /// src_agent: related to agent
+ /// dst_agent: effect at location of agent (if applicable)
+ /// value: (float*)&value is float[3], location x/y/z (if not at agent location)
+ /// iff: (uint32_t*)&iff is uint32_t[1], effect duration
+ /// buffremove: (uint32_t*)&buffremove is uint32_t[1], trackable id of effect. id dst_agent and location is 0/0/0, effect was stopped
+ /// is_shields: (int16_t*)&is_shields is int16_t[3], orientation x/y/z, values are original*1000
+ /// is_flanking: effect is on a non-static platform
+ Effect2,
+ /// Ruleset for self.
+ ///
+ /// `src_agent` has bit 0 if PvE, bit 1 if WvW and bit 2 if PvP.
+ Ruleset,
+ /// Squad ground markers.
+ ///
+ /// src_agent: (float*)&src_agent is float[3], x/y/z of marker location. if values are all zero or infinity, this marker is removed
+ /// skillid: index of marker eg. 0 is arrow
+ SquadMarker,
+ /// Arcdps build info.
+ ///
+ /// `src_agent` is a null-terminated string matching the full build string.
+ ArcBuild,
+ /// Glider status change.
+ ///
+ /// `src_agent` is the agent, `value` 1 is deployed and 0 is stowed.
+ Glider,
+ /// `src_agent` is the agent, `value` is the remaining duration.
+ Stunbreak,
}
/// Combat buff remove type