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:
- Sender side: logic that runs in the sending Simulator.
- 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:
- The event is scheduled and parameters are set (when scheduled).
- The sender side is executed in the submodel that scheduled the sync-event.
- 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();