Event System

The event system is how plugins communicate without direct dependencies. When something happens in one plugin (item collected, ability used, quest completed), it publishes an event. Any other plugin can subscribe to that event and react.

ISparkEvent Interface

Every event implements ISparkEvent:

public interface ISparkEvent
{
    string EventType { get; }
    float Timestamp { get; }
    string Source { get; }
    int Priority { get; }
    bool CanBeCancelled { get; }
}
Property
Description

EventType

A string identifier for the event type (e.g., "ItemPickedUp").

Timestamp

When the event was created (Time.time).

Source

Optional string identifying what caused the event.

Priority

Event priority. Higher priority events may be processed differently by some systems.

CanBeCancelled

Whether handlers can consume (stop) this event.

Creating Custom Events

Inherit from SparkEventBase, which provides default implementations for most properties:

SparkEventBase automatically sets Timestamp to Time.time at construction. Priority defaults to 0 and CanBeCancelled defaults to false.

To make an event cancellable, also implement IConsumableEvent:

Publishing Events

Use SparkEventBus.Publish<T>() for immediate, synchronous dispatch:

All subscribed handlers run synchronously in priority order before Publish returns.

For batch processing, queue events and process them together:

Queuing is useful when multiple state changes happen as part of a single action and you want all events to fire after all changes are applied.

Subscribing to Events

Implement ISparkEventHandler<T>:

Register the handler with the event bus:

Unsubscribe when no longer needed:

Always unsubscribe handlers when the subscribing object is destroyed or disabled. Failing to do so can cause memory leaks and errors.

Handler Priority and Ordering

Handlers execute in descending priority order. Higher HandlerPriority values run first:

This lets you create handlers that can validate or block an event before lower-priority handlers process it.

Event Consumption

When an event implements IConsumableEvent, a handler can stop propagation by returning true from Handle(). Subsequent lower-priority handlers will not receive the event.

For non-consumable events, the return value of Handle() is ignored. All handlers always run.

Type Matching

The event bus supports polymorphic subscriptions. If you subscribe to a base class or interface, your handler receives all events of that type and its subtypes:

String-Based Event Listeners

For simpler use cases (often in UI bindings), Spark provides StringBasedEventListener. This lets you subscribe to events by their EventType string rather than by C# type. This is primarily used by the editor and UI systems.

Built-in Event Types

Spark and its plugins publish many events. Here are some common categories:

UI Events (from Core):

  • UIPanelShownEvent, UIPanelHiddenEvent

  • FirstUIPanelOpenedEvent, AllUIPanelsClosedEvent

  • EscapeKeyPressedEvent

  • ShowEventMessageEvent

Character Events (from Character plugin):

  • Character creation and loading events

Game Settings Events (from GameSettings plugin):

  • GameSettingsLoadedEvent

  • GameSettingsUIOpenedEvent, GameSettingsUIClosedEvent

  • KeybindChangedEvent

Each optional plugin adds its own events. See the Plugin API Reference section for complete event listings per plugin.

Error Handling

The event bus catches and logs exceptions thrown by handlers. A failing handler does not prevent other handlers from receiving the event. Exceptions are logged with full stack traces for debugging.

Best Practices

  • Keep events immutable. Set all properties in the constructor and expose them as read-only.

  • Use descriptive EventType strings that match the class name (e.g., "MountSummoned" for MountSummonedEvent).

  • Always pair Subscribe with Unsubscribe to prevent leaks.

  • Keep handlers lightweight. If a handler needs to do heavy work, queue it for the next frame.

  • Use event consumption sparingly. Most events should reach all handlers.

  • Prefer specific event types over base class subscriptions. Specific types are faster and clearer.

  • Include a Source string in events to help with debugging and filtering.

Last updated

Was this helpful?