evtc\event/mod.rs
1//! Event bindings & utilities.
2
3mod category;
4mod common;
5mod event_kind;
6mod old;
7
8pub use self::{category::*, common::*, event_kind::*, old::*};
9
10#[allow(deprecated)]
11pub use crate::{
12 agent::{
13 AgentStatusEvent, AttackTargetEvent, BarrierUpdateEvent, BreakbarPercentEvent,
14 BreakbarStateEvent, DownContributionEvent, EnterCombatEvent, GliderEvent,
15 HealthUpdateEvent, MaxHealthEvent, StunbreakEvent, TargetableEvent, TeamChangeEvent,
16 },
17 buff::{
18 BuffApplyEvent, BuffDamageEvent, BuffFormula, BuffInfo, BuffInitialEvent, BuffRemoveEvent,
19 StackActiveEvent, StackResetEvent,
20 },
21 effect::{
22 AgentEffect, AgentEffectRemove, Effect45, Effect51, GroundEffect, GroundEffectRemove,
23 },
24 log::{ArcBuildEvent, ErrorEvent, LogEvent},
25 marker::{AgentMarkerEvent, SquadMarkerEvent},
26 missile::{MissileCreate, MissileLaunch, MissileRemove},
27 player::{GuildEvent, RewardEvent, TagEvent},
28 position::PositionEvent,
29 skill::{ActivationEvent, SkillInfo, SkillTiming},
30 strike::StrikeEvent,
31 weapon::WeaponSwapEvent,
32};
33
34use crate::{
35 buff::{BuffCycle, BuffRemove},
36 extract::Extract,
37 skill::Activation,
38 strike::Strike,
39 Affinity, StateChange, TryExtract,
40};
41
42#[cfg(feature = "serde")]
43use serde::{Deserialize, Serialize};
44
45/// ArcDPS event.
46#[derive(Debug, Clone)]
47#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
48#[repr(C)]
49pub struct Event {
50 /// `timeGetTime()` at time of registering the event.
51 pub time: u64,
52
53 /// Agent that caused the event.
54 pub src_agent: u64,
55
56 /// Agent the event happened to.
57 pub dst_agent: u64,
58
59 /// Value, if relevant to the event.
60 pub value: i32,
61
62 /// Buff damage, if relevant to the event.
63 pub buff_dmg: i32,
64
65 /// Overstack value, if relevant to the event.
66 pub overstack_value: u32,
67
68 /// Skill id of the relevant skill (can be zero).
69 pub skill_id: u32,
70
71 /// Instance id of source agent as appears in game at time of event.
72 pub src_instance_id: u16,
73
74 /// Instance id of destination agent as appears in game at time of event.
75 pub dst_instance_id: u16,
76
77 /// If `src_agent` has a master (e.g. is minion), will be equal to instance id of master, zero otherwise.
78 pub src_master_instance_id: u16,
79
80 /// If `dst_agent` has a master (e.g. is minion), will be equal to instance id of master, zero otherwise.
81 pub dst_master_instance_id: u16,
82
83 /// Current affinity of `src_agent` and `dst_agent`.
84 ///
85 /// Use [`Event::get_affinity`] to obtain the value as [`Affinity`].
86 ///
87 /// *Arc calls this "iff" for if friend/foe.*
88 pub affinity: u8,
89
90 /// Buff, if relevant to the event.
91 pub buff: u8,
92
93 /// Combat result.
94 ///
95 /// For strike (direct damage) events this contains the kind of strike.
96 ///
97 /// Use [`Event::get_strike`] to obtain the value as [`Strike`].
98 pub result: u8,
99
100 /// Whether event is a kind of activation event.
101 ///
102 /// Use [`Event::get_activation`] to obtain the value as [`Activation`].
103 ///
104 /// For [`Activation::CancelFire`] and [`Activation::CancelCancel`] `value` will be the ms duration of the time spent in animation.
105 /// `buff_dmg` will be the ms duration of the scaled (as if not affected) time spent.
106 ///
107 /// For Normal or Quickness, `value` will be the ms duration at which all significant effects have happened.
108 /// `buff_dmg` will be the ms duration at which control is expected to be returned to character.
109 ///
110 /// `dst_agent` will be x/y of target of skill effect.
111 /// `overstack_value` will be z of target of skill effect.
112 pub is_activation: u8,
113
114 /// Whether event is a kind of buff remove event.
115 ///
116 /// Use [`Event::get_buffremove`] to obtain the value as [`BuffRemove`].
117 ///
118 /// `src_agent` is agent that had buff removed, `dst_agent` is the agent that removed it.
119 /// `value` will be the remaining time removed calculated as duration.
120 /// `buff_dmg` will be the remaining time removed calculated as intensity.
121 ///
122 /// For [`BuffRemove::All`] `result` will be the number of stacks removed.
123 /// For [`BuffRemove::Single`] pad61-64 (uint32) will be buff instance id of buff removed.
124 pub is_buffremove: u8,
125
126 /// Whether `src_agent` is above 90% Health.
127 pub is_ninety: u8,
128
129 /// Whether `dst_agent` is below 50% Health.
130 pub is_fifty: u8,
131
132 /// Whether `src_agent` is moving at time of event.
133 pub is_moving: u8,
134
135 /// Whether event is a kind of state change event.
136 ///
137 /// Use [Event::get_statechange] to obtain the value as [`StateChange`].
138 pub is_statechange: u8,
139
140 /// Whether `src_agent` is flanking at time of event.
141 ///
142 /// The value lies in a range of `1` to `135` degrees where `135` is rear.
143 pub is_flanking: u8,
144
145 /// Shields, if relevant to the event.
146 pub is_shields: u8,
147
148 /// For relevant events this contains when the buff cycle happened.
149 ///
150 /// Use [`Event::get_buffcycle`] to obtain the value as [`BuffCycle`].
151 pub is_offcycle: u8,
152
153 /// Padding.
154 ///
155 /// May contain information depending on the kind of event.
156 pub pad61: u8,
157
158 /// Padding.
159 ///
160 /// May contain information depending on the kind of event.
161 pub pad62: u8,
162
163 /// Padding.
164 ///
165 /// May contain information depending on the kind of event.
166 pub pad63: u8,
167
168 /// Padding.
169 ///
170 /// May contain information depending on the kind of event.
171 pub pad64: u8,
172}
173
174impl Event {
175 /// Determines the [`EventCategory`] of the event.
176 #[inline]
177 pub fn categorize(&self) -> EventCategory {
178 self.into()
179 }
180
181 /// Converts the event into its [`EventKind`] representation.
182 #[inline]
183 pub fn into_kind(self) -> EventKind {
184 self.into()
185 }
186
187 /// Returns the event `is_statechange` as [`StateChange`].
188 #[inline]
189 pub fn get_statechange(&self) -> StateChange {
190 self.is_statechange.into()
191 }
192
193 /// Returns the event `affinity` as [`Affinity`].
194 ///
195 /// This will return [`Affinity::Unknown`] if the event has no valid data in `affinity`.
196 #[inline]
197 pub fn get_affinity(&self) -> Affinity {
198 self.affinity.into()
199 }
200
201 /// Returns the event `is_activation` as [`Activation`].
202 ///
203 /// This will return [`Activation::Unknown`] if the event has no valid data in `is_activation`.
204 #[inline]
205 pub fn get_activation(&self) -> Activation {
206 self.is_activation.into()
207 }
208
209 /// Returns the event `is_buffremove` as [`BuffRemove`].
210 ///
211 /// This will return [`BuffRemove::Unknown`] if the event has no valid data in `is_buffremove`.
212 #[inline]
213 pub fn get_buffremove(&self) -> BuffRemove {
214 self.is_buffremove.into()
215 }
216
217 /// Returns the event `result` as [`Strike`].
218 ///
219 /// This will return [`Strike::Unknown`] if the event has no valid data in `result`.
220 #[inline]
221 pub fn get_strike(&self) -> Strike {
222 self.result.into()
223 }
224
225 /// Returns the event `is_offcycle` as [`BuffCycle`].
226 ///
227 /// This will return [`BuffCycle::Unknown`] if the event has no valid data in `is_offcycle`.
228 #[inline]
229 pub fn get_buffcycle(&self) -> BuffCycle {
230 self.is_offcycle.into()
231 }
232
233 /// Returns the padding as [`u32`] id/signature.
234 #[inline]
235 pub fn get_pad_id(&self) -> u32 {
236 u32::from_le_bytes([self.pad61, self.pad62, self.pad63, self.pad64])
237 }
238
239 /// Checks whether the event has a timestamp.
240 #[inline]
241 pub fn has_time(&self) -> bool {
242 self.get_statechange().has_time()
243 }
244
245 /// Retrieves the event time, if present.
246 #[inline]
247 pub fn time(&self) -> Option<u64> {
248 self.has_time().then_some(self.time)
249 }
250
251 /// Forcefully extracts a type implementing [`Extract`] from the event.
252 ///
253 /// # Safety
254 /// This is safe when the given event is a valid event to extract the type from.
255 #[inline]
256 pub unsafe fn extract<T>(&self) -> T
257 where
258 T: Extract,
259 {
260 T::extract(self)
261 }
262
263 /// Attempts to extract a type implementing [`TryExtract`] from the event.
264 #[inline]
265 pub fn try_extract<T>(&self) -> Option<T>
266 where
267 T: TryExtract,
268 {
269 T::try_extract(self)
270 }
271
272 /// Attempts to extract an [`ActivationEvent`] from the event.
273 #[inline]
274 pub fn try_to_activation(&self) -> Option<ActivationEvent> {
275 self.try_extract()
276 }
277
278 /// Attempts to extract a [`BuffRemoveEvent`] from the event.
279 #[inline]
280 pub fn try_to_buff_remove(&self) -> Option<BuffRemoveEvent> {
281 self.try_extract()
282 }
283
284 /// Attempts to extract a [`BuffApplyEvent`] from the event.
285 #[inline]
286 pub fn try_to_buff_apply(&self) -> Option<BuffApplyEvent> {
287 self.try_extract()
288 }
289
290 /// Attempts to extract a [`BuffDamageEvent`] from the event.
291 #[inline]
292 pub fn try_to_buff_damage(&self) -> Option<BuffDamageEvent> {
293 self.try_extract()
294 }
295
296 /// Attempts to extract a [`StrikeEvent`] from the event.
297 #[inline]
298 pub fn try_to_strike(&self) -> Option<StrikeEvent> {
299 self.try_extract()
300 }
301
302 /// Checks whether the event is an initial buff event.
303 #[inline]
304 pub fn is_buffinitial(&self) -> bool {
305 self.get_statechange() == StateChange::BuffInitial && self.buff == 18
306 }
307}