Data produced by HCP MACE
Lifecycle
Capture follows the MACE mission state, when AutoStartTransport is on (see
Configure):
| Mission state | What happens |
|---|---|
| Running | Transport, event source and scheduler start; the HEAT Capture session resumes |
| Paused | Collectors stop, one final frame is published for whatever they already captured, the HEAT Capture session pauses |
| Stopped | Same as Paused, then the transport drains its buffer and closes the HEAT Capture session |
| Loading / Initialized / Reset / Undefined | No-op |
Entity-state capture and event capture run as two independent loops, decoupled by a shared event buffer: a MACE callback (weapon fire, DIS collision/designator PDU) can enqueue an event at any time, on MACE’s own thread, independent of the periodic capture tick.
Operator attribution
HeatUserComponent.user_name (the authenticated HEAT Capture session user, in canonical GUID
form) is attached only to the entity this MACE instance is actively flying:
entity.IsInternalEntity && entity.ManeuverState == ManeuverStateEnum.maneuverManeuverState is an active-control signal, not an identity claim; IsInternalEntity exists
specifically to stop a remote DIS/TENA entity in a distributed simulation from being attributed
to the local operator. ARMOR is a visual/output attachment in this model, not the control-input
source - MACE remains the source of truth for what “controlled” means here.
Entity components
Populated when applicable, subject to the cadence and content settings in Configure:
| Component | Source | Notes |
|---|---|---|
HeatUserComponent | See operator attribution above | Only on the locally-controlled entity |
WorldPositionComponent | Position, orientation | Latitude, longitude, altitude, heading, pitch, roll |
DynamicsComponent | Linear/angular velocity, acceleration, speeds | |
HealthComponent | Health, mobility-kill, kill flags | max_health is hardcoded to 1.0 - MACE exposes no separate maximum |
AirDataComponent / AircraftDataComponent / FwaDataComponent | Air-domain extraction | Environment and flight detail are independently optional; FwaDataComponent (control surfaces) is fixed-wing only |
EmissionComponent | Active emitter modes | Per tick, toggleable |
SensorContactsComponent | Perceived radar contacts | Per tick, toggleable - this is what an operator’s radar actually sees, not ground truth |
ReceiverCharacteristicsComponent / ReceiverEnvironmentComponent | Receiver mode data | Characteristics are change-gated; environment publishes every tick |
SignatureComponent | RCS, EOIR mode | IR-intensity normalization is unconfirmed against a reference |
CombatStateComponent | Team affiliation, postures, EMCON | cleared_hot has no MACE source and is never populated |
IffComponent | IFF modes | Modes 4/5 are flags only - MACE exposes no code or PIN for either |
DataLinkComponent | Link 16 / SADL | Header-level only; individual J-series message records are not consumed |
UnitTypeComponent / ResourceStoresComponent | Entity type, fuel and munitions | |
AircraftLightingComponent / GroundVehicleLightingComponent | Lighting state | MACE’s “on” maps only to high-beam - there is no separate low-beam signal to capture |
LinkedEntityComponent | Reverse child-to-parent scan (MACE exposes no direct parent accessor) | link_type is never set - no MACE signal distinguishes attachment kind |
RadioComponent | DIS transmitter PDU cache | Frequency, band, secure flag, selected flag; transmit frequency duplicates what EmissionComponent already carries for the same entity |
CloudDataComponent | Weather |
WeaponLoadoutComponent is never populated. MACE’s IHardpoint exposes no store/loadout
field for this plugin to read, so weapon-station and magazine data - populated by some other
plugins in this catalogue - has no MACE source here.
Slow-changing components (UnitType, Signature, ReceiverCharacteristics, CombatState,
IFF, DataLink, Radio, and, when PlatformStateMode is OnChange, Health and the lighting/
TargetData/LinkedEntity group) are emitted only when their serialized bytes actually change.
A component that disappears after having a value still emits one empty instance as an explicit
removal marker, so a consumer can tell “gone” from “never sent.”
A tick with nothing to report - no entity due for publication and no event pending - publishes no
frame at all, rather than an empty one. simulationTimeSeconds is therefore not a continuous
per-tick counter from a consumer’s point of view; gaps in it correspond to genuinely idle ticks,
not lost data.
Events
Every discrete occurrence emits a TrackingEvent (the authoritative verb) together with an
EntityDataEvent carrying the same verb’s typed payload - always as a pair, never one without
the other.
| Event | Trigger |
|---|---|
FIRED | MACE WeaponFire |
DETONATION | MACE WeaponDetonation |
HIT | MACE WeaponDamage |
COLLISION | DIS CollisionPDU |
LASED | DIS DesignatorPDU |
STATE_CHANGED (grounded/airborne, stall, overspeed, weapon-selection) | Per-tick state diff |
TARGETLOCKED / TARGETRELEASED | Per-tick target-assignment diff |
RADAR_EMISSION_STARTED / RADAR_EMISSION_STOPPED | Per-tick transmitting-emitter diff |
ESM_CONTACT_DETECTED / ESM_CONTACT_LOST | Per-tick RWR contact diff |
JAMMED | Per-tick jamming-onset diff |
Jamming has no stop event. Only the onset (JAMMED) is emitted; there is no corresponding
“jamming stopped” verb in this version, so a consumer cannot tell from events alone when a
jamming condition ends.
Transition events (everything below HIT in the table above) are detected by diffing each
entity’s state between ticks, at the global CaptureIntervalMs cadence - always, regardless of
that entity’s own publish interval setting. A transition that starts and fully ends between two
ticks of a raised CaptureIntervalMs is missed; callback-driven events (fire, detonation, hit,
collision, lased) are never subject to this and are always captured.
Known extraction gaps
Beyond the per-component notes above, confirmed directly in source:
- The MACE-API-reading code itself (translating
IPhysicalEntity/IModeinto a snapshot) has no fixture or mock test harness - only the pure logic downstream of it (conversion math, id hashing, enum mapping, event builders, the change gate) has unit coverage. - Save/load entity-id stability has not been validated against a live save/load cycle.
- Jamming victim-list resolution has not been exercised against a live jamming lock.