Skip to main content

Resolution results

HTTP 202 means the server stored a plan, nothing more — the actions have not resolved yet. Their results turn up in the next state.data.events array.

Start from event_type, then read the fields listed for that event:

{
"event_id": "3f360e7e-d9bd-4f48-9a51-5cf751b04075",
"tick": 10583,
"event_type": "UNIT_MOVE_FAILED",
"reason_code": "MOVE_BLOCKED_TERRAIN",
"actor_id": "9d3e4941-2816-4a39-a220-df8cd95e877d",
"position": [120, 85]
}
Looking forGo to
Upkeep, Core damage, repair, or spawningEconomy and Core events
Harvesting or depositingWorker events
Sweeps, shots, and damageCombat events
Unit movement or Core migrationMovement events
Beacon actions or respawningBeacon and respawn events

Field rules

FieldPresence and meaning
event_idAlways present. Use this UUID to avoid processing the same event twice after reconnecting.
tickAlways present. Tick in which the result was resolved.
event_typeAlways present. Read this before the other optional fields.
reason_codePresent only when the event has a defined reason. Successful events do not send an empty string.
actor_idThe player's Core or Unit whose action produced the result, when there is one.
target_idThe affected Core or Unit, when exposing it is part of the result.
positionCell relevant to the resolved result. Its exact meaning is stated in each catalog row.
valuesEvent-specific object. Keys are stable per event row; the object is omitted when no values apply.

Optional fields that do not apply are left out rather than sent as null.

Economy and Core events

event_typereason_codeIDs and positionvaluesMeaning
UPKEEP_PAIDabsentactor_id: Core; position: Core cell{due: int, paid: int, deficit: int}Upkeep was collected. A positive deficit is then applied as Core damage.
CORE_DAMAGEDATTACK or UPKEEP_DEFICITtarget_id: Core; position: Core cell{damage: int, shield_damage: int, hp_damage: int}Total Core damage and how it was split between shield and HP.
CORE_DESTROYEDATTACK or UPKEEP_DEFICITtarget_id: destroyed Core; position: destruction cellFor an attack with named participants: {destroyed_by: string[]}; otherwise absentThe player's Core and remaining Units were removed and respawn waiting began.
CORE_ACTION_FAILEDCORE_NOT_MOVING or CORE_ALREADY_MOVINGactor_id: Core; position: Core cellabsentCANCEL_MOVE was used on a normal Core, or an incompatible Core action was used during migration.
CORE_REPAIR_FAILEDSHIELD_FULL or INSUFFICIENT_RESOURCESactor_id: Core; position: Core cellabsentOne-shield repair could not be applied.
CORE_REPAIR_SUCCEEDEDabsentactor_id: Core; position: Core cell{shield: int, cost: int}Shield after repair and resources spent.
CORE_SPAWN_FAILEDCELL_UNIT_LIMITactor_id: Core; position: Core cell{limit: int}Core cell has reached the occupiable-entity limit.
CORE_SPAWN_FAILEDINSUFFICIENT_RESOURCESactor_id: Core; position: Core cell{required: int}Resources are below the selected Unit's cost.
CORE_SPAWN_FAILEDDETERMINISTIC_ID_COLLISIONactor_id: Core; position: Core cellabsentDefensive collision check rejected the deterministic spawn ID.
CORE_SPAWN_SUCCEEDEDabsentactor_id: Core; target_id: new Unit; position: Core cell{unit_type: UnitType, cost: int}One Unit was created on the Core cell.

destroyed_by lists participant usernames in a deterministic order. You only see it for an attack, and only when at least one participant can be named.

Worker events

event_typereason_codeIDs and positionvaluesMeaning
DEPOSIT_FAILEDWORKER_EMPTYactor_id: Worker; position: Worker cellabsentWorker has no cargo.
DEPOSIT_FAILEDCORE_NOT_PRESENTactor_id: Worker; position: Worker cellabsentOwned Core is absent or not on the same cell.
DEPOSIT_FAILEDCORE_MOVINGactor_id: Worker; target_id: Core; position: Worker cellabsentThe colocated Core is migration-restricted this Tick.
DEPOSIT_SUCCEEDEDabsentactor_id: Worker; target_id: Core; position: shared cell{amount: int}All Worker cargo moved into Core resources.
HARVEST_FAILEDNOT_RESOURCE_CELLactor_id: Worker; position: Worker cellabsentCurrent terrain is not a resource cell.
HARVEST_FAILEDCARGO_FULLactor_id: Worker; position: Worker cellabsentWorker already carries resources.
HARVEST_SUCCEEDEDabsentactor_id: Worker; position: Worker cell{amount: int}Resources loaded into Worker cargo.
BEACON_HARVEST_BONUSabsentactor_id: Worker; position: Worker cell{amount: int}Bonus portion of the harvest granted by carrying the Beacon.

Combat events

event_typereason_codeIDs and positionvaluesMeaning
SWEEP_RESOLVEDabsentactor_id: Vanguard; position: swept adjacent cell{targets_hit: int}Sweep resolved; 0 is a valid result.
SHOT_MISSEDalways SHOT_MISSEDactor_id: Ranger; target_id: requested UUID; position: submitted expected_cellabsentShot failed dynamically. The detailed cause is intentionally hidden.
SHOT_HITabsentactor_id: Ranger; target_id: hit Core or Unit; position: target cell{damage: int}Valid shot contributed damage.
UNIT_DAMAGEDATTACKtarget_id: damaged Unit; position: Unit cell{damage: int, hp: int}Aggregated damage and HP after damage, clamped to 0. hp: 0 means the Unit was destroyed.
DESTRUCTION_PARTICIPATIONUNIT or COREtarget_id: destroyed object; position: destruction cellabsentThis player contributed at least one damage to the destroyed object.

The victim never gets a separate UNIT_DESTROYED event. Detect a kill from UNIT_DAMAGED.values.hp === 0, together with the Unit's absence from the new complete state.

Every dynamic Ranger failure carries the same SHOT_MISSED reason — a missing or moved target, a friendly target, bad range, a blocked line, all of them. The result is designed to reveal nothing about hidden state.

Movement events

event_typereason_codeIDs and positionvaluesMeaning
UNIT_MOVE_SUCCEEDEDabsentactor_id: Unit; position: destinationabsentUnit completed its one-cell move.
UNIT_MOVE_FAILEDSee Unit movement reasonsactor_id: Unit; position: unchanged originabsentUnit stayed at its origin.
CORE_MOVE_STARTEDabsentactor_id: Core; position: origin{destination: Position, progress: int, required: int}A migration began. Current values are progress 1, required 4.
CORE_MOVE_PROGRESSabsentactor_id: Core; position: origin{progress: int, required: int}Existing migration advanced but did not yet move the Core.
CORE_MOVE_SUCCEEDEDabsentactor_id: Core; position: destinationabsentFinal migration Tick moved the Core.
CORE_MOVE_FAILEDSee resolved movement reasonsactor_id: Core; position: unchanged originabsentFinal migration move failed; Core returns to NORMAL.
CORE_MOVE_START_FAILEDSee start reasonsactor_id: Core; position: originabsentSTART_MOVE failed before migration state began.
CORE_MOVE_CANCELLEDabsentactor_id: Core; position: originabsentExisting migration was cancelled and Core returned to NORMAL.

Unit movement reasons:

  • MOVE_OUT_OF_BOUNDS: signed int64 coordinate overflow would occur;
  • MOVE_BLOCKED_TERRAIN: destination is obstacle terrain;
  • MOVE_CONTESTED: different owners claimed the same destination;
  • MOVE_SWAP_BLOCKED: two hostile entities attempted a two-way swap;
  • MOVE_DESTINATION_OCCUPIED: a hostile occupant is not successfully leaving;
  • MOVE_DEPENDENCY_FAILED: a required departure failed;
  • CELL_UNIT_LIMIT: the destination would exceed the entity limit.

CORE_MOVE_FAILED can use CORE_DESTINATION_TERRAIN_BLOCKED, MOVE_CONTESTED, MOVE_SWAP_BLOCKED, MOVE_DESTINATION_OCCUPIED, MOVE_DEPENDENCY_FAILED, or CELL_UNIT_LIMIT.

CORE_MOVE_START_FAILED can use CORE_DESTINATION_OUT_OF_BOUNDS, CORE_DESTINATION_TERRAIN_BLOCKED, CORE_DESTINATION_OCCUPIED, or CELL_UNIT_LIMIT.

Beacon and respawn events

event_typereason_codeIDs and positionvaluesMeaning
BEACON_PICKUP_FAILEDCORE_MOVING, ALREADY_CARRIED, or BEACON_NOT_PRESENTactor_id: Core or Unit; position: actor cellabsentPickup could not be completed.
BEACON_PICKED_UPabsentactor_id: new carrier; position: pickup cellabsentActor became the carrier.
BEACON_DROP_FAILEDCORE_MOVING or NOT_BEACON_CARRIERactor_id: Core or Unit; position: actor cellabsentDrop could not be completed.
BEACON_DROPPEDabsentactor_id: former carrier; position: drop cellabsentVoluntary drop completed.
BEACON_DROPPED_ON_DEATHabsentactor_id: destroyed carrier; position: death cellabsentBeacon automatically moved to the ground.
RESPAWN_DELAYEDNO_LEGAL_SPAWNno IDs or positionabsentNo legal deterministic spawn candidate was found; next attempt is one Tick later.
CORE_RESPAWNEDabsenttarget_id: new Core; position: spawn cell{resources: int, workers: int}Player became ACTIVE with starting resources and Workers.

Decoding example

function applyEvent(event) {
switch (event.event_type) {
case 'UNIT_MOVE_FAILED':
markUnitBlocked(event.actor_id, event.position, event.reason_code);
break;
case 'CORE_SPAWN_SUCCEEDED':
registerSpawn(
event.target_id,
event.position,
event.values.unit_type,
);
break;
case 'SHOT_MISSED':
// The protocol does not reveal why it missed.
break;
}
}

Replace your old objects with the new state.objects. Events are there to explain how the new state came about — do not replay them as patches against the old one.