# Events

The crowd actor broadcasts **multicast delegates** you can bind in Blueprint or C++ to react
to movement and population changes without polling every tick. Every event delivers an
**array of agent indices** that are valid at the moment it fires.

## Movement lifecycle

Fired **right after** each simulation tick.

==- OnAgentsReachedGoal
Agents that reached their slot this tick (their [settle](./02-formations.md#settling) latch
flipped on). Fires **once** per arrival - the typical place to switch a unit to its idle
animation or trigger "arrived" gameplay.
===

==- OnAgentsStuck
Ordered agents that made **no progress for `StuckTimeout` seconds**. **Re-fires every
interval** while they stay stuck. The standard reaction is to issue a fresh `SetAgentsTarget`
to re-path them.

Set `StuckTimeout = 0` to disable stuck events entirely.
===

==- OnAgentsOrdersCanceled
Agents whose **unfinished order was replaced** by a new `SetAgentsTarget` call. Useful for
cleaning up any per-order state you were tracking for those units.
===

## Population changes

These fire **before** the simulation tick that applies the change, so the indices they carry
are **still valid** in your handler - the agents are still in the arrays and queryable.

==- OnAgentsSpawned
The indices of every agent spawned via `SpawnAgent` / `SpawnAgentGrid` since the last
broadcast. Use it to grow your renderer's instance buffer or attach per-agent gameplay state.
===

==- OnAgentsRemoved
The indices queued by `RemoveAgent` since the last broadcast, fired **just before** the tick
that actually removes them - so you can read a removed agent's final position/transform, or
look up its [stable id](./04-indices_and_ids.md) to clean up id-keyed data, while it still
exists. After the tick, those indices are gone.
===

## Timing model

```
       ┌─────────────────────────── one frame ───────────────────────────┐
       │                                                                  │
  Flush spawns/removes ──► SimTick (applies removals, advances) ──► broadcast movement events
       │                          │                                       │
  OnAgentsSpawned            agents actually                        OnAgentsReachedGoal
  OnAgentsRemoved            added / removed here                   OnAgentsStuck
  (indices still valid)                                             OnAgentsOrdersCanceled
```

So **spawn/remove events lead** the change (indices still valid), and **movement events
trail** the tick (reporting what just happened).

## Binding an event

```cpp
// C++
Crowd->OnAgentsReachedGoal.AddDynamic(this, &AMyController::HandleReachedGoal);

void AMyController::HandleReachedGoal(const TArray<int32>& Indices)
{
    // Indices are valid right now; resolve to ids if you need to remember them.
}
```

In Blueprint, select the crowd actor and use the matching **red event node** under the
**Crowd Toolkit** category, or **Bind Event to On Agents Reached Goal**.

::: warning
Indices in an event are valid **at broadcast time only**. If you store any of them for later,
convert them to [stable ids](./04-indices_and_ids.md) first.
:::
