Skip to content

cbtevent

cbtevent is the struct arcdps passes as the ev parameter of the combat / combat_local callbacks (see the combat callback reference).

It is not defined in the API README. The README’s only statement about it is:

ev parameter is cbtevent as in evtc documentation.

The authoritative layout lives in the separate EVTC combat-log format documentation (https://www.deltaconnected.com/arcdps/evtc/README.txt), which this page is sourced from. That document also states the struct is revision 1 (matching the revision parameter of the combat callbacks, “will most likely be 1”):

combat event logging (revision 1, when header[12] == 1). all fields except time are event-specific, refer to descriptions of events above

That last sentence is the key fact for reading this page: time is the only field the notes call out as generally stable across events — with three documented exceptions where it is reinterpreted as an inline data buffer rather than a timestamp:

State-change typetime is reinterpreted as
CBTS_BUFFFORMULA(float*)&timefloat[9]: type, attribute1, attribute2, parameter1, parameter2, parameter3, trait_condition_source, trait_condition_self, content_reference
CBTS_SKILLINFO(float*)&timefloat[4]: cost, range0, range1, tooltiptime
CBTS_INTEGRITY(char*)&timechar[32]: a short null-terminated message with the reason

Treat time as a timestamp only after ruling those three out. Every other field’s meaning depends on the value of is_statechange (which state-change type the event is) — the same byte offset carries different data for, say, CBTS_COMBAT versus CBTS_POSITION versus CBTS_BUFFINFO. The full per-event-type field mapping is on the statechange payloads page; this page documents the struct’s fixed C layout and the fields’ generic/most-common (CBTS_COMBAT) roles.

C declaration

typedef struct cbtevent {
uint64_t time; /* timegettime() at time of event */
uint64_t src_agent;
uint64_t dst_agent;
int32_t value;
int32_t buff_dmg;
uint32_t overstack_value;
uint32_t skillid;
uint16_t src_instid;
uint16_t dst_instid;
uint16_t src_master_instid;
uint16_t dst_master_instid;
uint8_t iff;
uint8_t buff;
uint8_t result;
uint8_t is_activation;
uint8_t is_buffremove;
uint8_t is_ninety;
uint8_t is_fifty;
uint8_t is_moving;
uint8_t is_statechange;
uint8_t is_flanking;
uint8_t is_shields;
uint8_t is_offcycle;
uint8_t pad61;
uint8_t pad62;
uint8_t pad63;
uint8_t pad64;
} cbtevent;

Total size is 64 bytes with standard x64 struct alignment (no explicit #pragma pack is documented, and none is needed — the field widths sum to 64 bytes with every member already naturally aligned). The trailing pad61pad64 byte names correspond to 1-indexed byte offsets 61–64 of the struct, which is consistent with that natural-alignment layout — a useful sanity check when porting the struct, but the offset column below is derived from the field widths and standard C alignment rules, not stated explicitly by the source docs.

Field reference

OffsetC typeNameMeaning
0uint64_ttimetimeGetTime() at time of registering the event — except for CBTS_BUFFFORMULA, CBTS_SKILLINFO and CBTS_INTEGRITY, which reinterpret these 8 bytes as an inline data buffer (see the table above).
8uint64_tsrc_agentEvent-specific (see cbtstatechange mapping). For CBTS_COMBAT: source agent.
16uint64_tdst_agentEvent-specific. For CBTS_COMBAT: target agent.
24int32_tvalueEvent-specific. For CBTS_COMBAT: combined shield+health strike damage.
28int32_tbuff_dmgEvent-specific. For CBTS_COMBAT: combined shield+health buff damage.
32uint32_toverstack_valueEvent-specific. For CBTS_COMBAT: shield damage.
36uint32_tskillidEvent-specific. For CBTS_COMBAT: the damage skill id.
40uint16_tsrc_instidId of the source agent as it appears in-game at the time of the event. Out-of-range agents may still have this set even when src_agent is zero.
42uint16_tdst_instidId of the target agent as it appears in-game at the time of the event. Out-of-range agents may still have this set even when dst_agent is zero.
44uint16_tsrc_master_instidIf src_agent has a master (e.g. is a minion), equals the instance id of the master; zero otherwise.
46uint16_tdst_master_instidIf dst_agent has a master (e.g. is a minion), equals the instance id of the master; zero otherwise.
48uint8_tiffEvent-specific. For CBTS_COMBAT: friend/foe relationship, of enum iff. See enum reference.
49uint8_tbuffEvent-specific. For CBTS_COMBAT: whether the skill is a buff (as opposed to a direct strike).
50uint8_tresultEvent-specific. For CBTS_COMBAT: combat result, of enum cbtresult. See enum reference.
51uint8_tis_activationEvent-specific. Skill-activation state, of enum cbtanimation — used by CBTS_ANIMATIONSTOP.
52uint8_tis_buffremoveEvent-specific. Buff-remove kind, of enum cbtbuffremove — used by buff-remove events.
53uint8_tis_ninetyEvent-specific. For CBTS_COMBAT/buff-apply/-remove events: source is above 90% health.
54uint8_tis_fiftyEvent-specific. For CBTS_COMBAT/buff-apply/-remove events: target is below 50% health.
55uint8_tis_movingEvent-specific. For CBTS_COMBAT/buff-apply/-remove events: bit 0 set if source is moving, bit 1 set if target is moving.
56uint8_tis_statechangeWhich cbtstatechange enum value this event is — the discriminant that determines how every other field (except time) is interpreted. See enum reference.
57uint8_tis_flankingEvent-specific. For CBTS_COMBAT/buff-apply/-remove events: source is flanking target.
58uint8_tis_shieldsEvent-specific. For CBTS_COMBAT: damage was partially or wholly absorbed by barrier.
59uint8_tis_offcycleEvent-specific. For CBTS_COMBAT: target was downed at the time of the event.
60uint8_tpad61Padding for most event types; repurposed as event-specific data by several state-change types (e.g. a uint32_t “trackable id” spanning pad61pad64 for several CBTS_* events). See enum reference for which.
61uint8_tpad62Padding for most event types; repurposed by some state-change types. Undocumented outside those specific mappings.
62uint8_tpad63Padding for most event types; repurposed by some state-change types. Undocumented outside those specific mappings.
63uint8_tpad64Padding for most event types; repurposed by some state-change types. Undocumented outside those specific mappings.

FFI mappings

These mirror the C declaration’s field order, widths, and (default, no explicit packing documented) alignment.

Rust

#[repr(C)]
pub struct CbtEvent {
pub time: u64,
pub src_agent: u64,
pub dst_agent: u64,
pub value: i32,
pub buff_dmg: i32,
pub overstack_value: u32,
pub skillid: u32,
pub src_instid: u16,
pub dst_instid: u16,
pub src_master_instid: u16,
pub dst_master_instid: u16,
pub iff: u8,
pub buff: u8,
pub result: u8,
pub is_activation: u8,
pub is_buffremove: u8,
pub is_ninety: u8,
pub is_fifty: u8,
pub is_moving: u8,
pub is_statechange: u8,
pub is_flanking: u8,
pub is_shields: u8,
pub is_offcycle: u8,
pub pad61: u8,
pub pad62: u8,
pub pad63: u8,
pub pad64: u8,
}

Python (ctypes)

import ctypes
class CbtEvent(ctypes.Structure):
_fields_ = [
("time", ctypes.c_uint64),
("src_agent", ctypes.c_uint64),
("dst_agent", ctypes.c_uint64),
("value", ctypes.c_int32),
("buff_dmg", ctypes.c_int32),
("overstack_value", ctypes.c_uint32),
("skillid", ctypes.c_uint32),
("src_instid", ctypes.c_uint16),
("dst_instid", ctypes.c_uint16),
("src_master_instid", ctypes.c_uint16),
("dst_master_instid", ctypes.c_uint16),
("iff", ctypes.c_uint8),
("buff", ctypes.c_uint8),
("result", ctypes.c_uint8),
("is_activation", ctypes.c_uint8),
("is_buffremove", ctypes.c_uint8),
("is_ninety", ctypes.c_uint8),
("is_fifty", ctypes.c_uint8),
("is_moving", ctypes.c_uint8),
("is_statechange", ctypes.c_uint8),
("is_flanking", ctypes.c_uint8),
("is_shields", ctypes.c_uint8),
("is_offcycle", ctypes.c_uint8),
("pad61", ctypes.c_uint8),
("pad62", ctypes.c_uint8),
("pad63", ctypes.c_uint8),
("pad64", ctypes.c_uint8),
]

Node.js (koffi)

const koffi = require("koffi");
const cbtevent = koffi.struct("cbtevent", {
time: "uint64_t",
src_agent: "uint64_t",
dst_agent: "uint64_t",
value: "int32_t",
buff_dmg: "int32_t",
overstack_value: "uint32_t",
skillid: "uint32_t",
src_instid: "uint16_t",
dst_instid: "uint16_t",
src_master_instid: "uint16_t",
dst_master_instid: "uint16_t",
iff: "uint8_t",
buff: "uint8_t",
result: "uint8_t",
is_activation: "uint8_t",
is_buffremove: "uint8_t",
is_ninety: "uint8_t",
is_fifty: "uint8_t",
is_moving: "uint8_t",
is_statechange: "uint8_t",
is_flanking: "uint8_t",
is_shields: "uint8_t",
is_offcycle: "uint8_t",
pad61: "uint8_t",
pad62: "uint8_t",
pad63: "uint8_t",
pad64: "uint8_t",
});

Layout corroboration

The offset table above (derived from natural alignment) is confirmed by independent implementations: community Rust bindings declare the identical #[repr(C)] layout, and at least one from-scratch reimplementation carries a compile-time test asserting sizeof == 64 and skillid at byte offset 36 — matching the derived table exactly.

One field nuance recorded by the community bindings (not in the official notes): for strike events, is_flanking values lie “in a range of 1 to 135 degrees where 135 is rear” — i.e. it is an angle indicator, not a plain boolean.

See also