Skip to content

Events

To safely operate on a specific SubModel, ERS requires you to enter it. This sets the active context, so operations like entity creation or component access affect the correct submodel.

Types of events

Simulators are responsible for managing and executing events within ERS. Events are time-based actions scheduled to occur at specific simulation times. They are the core mechanism for driving behavior and communication between different parts of the model.

There are two types of events:

  • Local events (inside one simulator / submodel).
  • Sync-events (between simulators).

Local Events

Local events are scheduled and executed within a single simulator. They affect only that simulatorโ€™s submodel. They are used to update entities, change state, or trigger logic at future points in time. These events are managed by the simulator's event scheduler and executed during updates.

struct MyLocalEvent : ILocalEvent<MyLocalEvent>
{
    public void OnEvent()
    {
        // Logic to execute inside this simulator
    }
}

UInt64 eventKey = EventScheduler.ScheduleLocalEvent(priority, delay, new MyLocalEvent());

// Delay the event
EventScheduler.DelayEvent(key, time); // if 'time' is 1 then the event is delayed by 1 simulation time

// Cancel the event
EventScheduler.CancelEvent(key);

Sync-Events

Sync-events are used to send data or trigger logic between two simulators. They require a declared dependency (from -> to). Sync-events run in two parts:

  1. Sender side: logic that runs in the sending Simulator.
  2. Target side: logic that runs in the receiving Simulator.

ERS transfers data using a struct that both sender and target can write to and read from. This struct is made available to both the sender and the target during event execution. The sender side and target side run in sequence, they can never be executed in parallel. The struct must also be blittable (e.g. it must be data that can be copied safely without specialty).

Visual sync-event lifecycle

A sync-event is always executed in three steps:

  1. The event is scheduled and parameters are set (when scheduled).
  2. The sender side is executed in the submodel that scheduled the sync-event.
  3. The target side is executed in the target submodel.
%%{init: {'theme': 'base', 'themeVariables': { 'signalColor': '#A6B0BF' }}}%%
sequenceDiagram
    participant ERS as ERS Event Mechanism
    participant Sender as Sender Submodel
    participant Target as Target Submodel

    Note over ERS: Execute Event
    ERS->>Sender: 
    activate Sender
    Note right of Sender: Event is scheduled at<br/>"Time N"
    Note over Sender: Schedule Sync-Event
    Note over Sender: Set Event Data
    Sender->>ERS: 
    deactivate Sender
    Note over ERS: Finish event
    Note right of ERS: The simulation continues<br/>with other events

    Note right of ERS: Sender SubModel Reached<br/>"Time N"
    Note over ERS: Start Executing Sync-Event
    ERS->>Sender: 
    activate Sender
    Note over Sender: Execute SenderSide Callback
    Sender->>ERS: 
    deactivate Sender

    Note right of ERS: Target SubModel Reached<br/>"Time N"
    Note over ERS: Start Executing Sync-Event
    ERS->>Target: 
    activate Target
    Note over Target: Execute TargetSide Callback
    Target->>ERS: 
    deactivate Target

Code Example

When using separate methods, there is a clear indication what will be executed on each simulator / submodel.

struct MySyncEvent : ISyncEvent<MySyncEvent>
{

    // Data fields that will be transferred
    public double Data1;
    public double Data2;
    public double Data3;
    public Entity myEntity;

    public static string Name => "My awesome sync-event";

    public void OnSenderSide()
    {
        // Code to be executed in sender side, fill data and move entities
    }

    public void OnTargetSide()
    {
        // Code to be executed in target side, use information from sender side to update the target side
    }
}

The EventScheduler.ScheduleSyncEvent method is used to schedule the sync-events. As arguments, it requires a delay for the event, the target simulator on which the event will be scheduled, and the event data.

// Set data that will be available in the sender side
MySyncEvent syncEventData = new();
mySyncEventData.Data1 = 5;
mySyncEventData.Data2 = 10;
mySyncEventData.Data3 = 15;
mySyncEventData.myEntity = toadEntity;

// This event code can be used to delay/cancel the sync-event similarly to local events
UInt32 eventCode = EventScheduler.ScheduleSyncEvent<MySyncEvent>(
    delay,
    targetSimulatorId,
    mySyncEventData
);

Helper functions

The SyncEvent class provides a couple of helper functions that can be useful when implementing sync-events. For example, IsInsideSenderSide is used in the OnSyncEvent example above. Each of these functions are executed inside the currently entered submodel.

// Checks if the current thread is executing a sync-event
bool IsInsideSyncEvent();

// If inside a sync-event, check if it is the sender side
bool IsInsideSenderSide();

// If inside a sync-event, find the target of the sync-event
int GetTargetSimulatorId();

// If inside a sync-event find the sender of the sync-event
int GetSenderSimulatorId();
Was this page helpful?