Event System
io.vrctools.event - a tiny publish/subscribe event system for UdonSharp behaviours.
The VRCTools Event System lets UdonSharp behaviours publish events that other behaviours subscribe to at runtime. Handlers can be added and removed dynamically as objects are created or destroyed - something Udon does not offer out of the box.
You rarely install this package yourself. It is a dependency of World Utilities and other VRCTools packages and is installed automatically by Creator Companion. Read on if you want to emit or consume events from your own scripts.
Concepts
- An emitter extends
AbstractEventEmitter(orAbstractSynchronizedEventEmitterfor networked behaviours) and declares a fixed number of event slots, identified by integer constants. - A handler is any
UdonSharpBehaviourplus the name of one of itspublicmethods. Handlers register for a specific event slot. - Emitting an event calls every registered handler via
SendCustomEvent, in registration order.
Emitting events
using UdonSharp;
using VRC.SDKBase;
using VRCTools.Event;
public class Doorbell : AbstractEventEmitter {
public const int EVENT_RUNG = 0;
public const int EVENT_COUNT = 1;
public override int EventCount => EVENT_COUNT;
public override void Interact() {
this._EmitEvent(EVENT_RUNG);
}
}
Event ids must be in the range 0 .. EventCount - 1.
Subscribing to events
using UdonSharp;
using UnityEngine;
public class DoorbellSpeaker : UdonSharpBehaviour {
public Doorbell doorbell;
public AudioSource chime;
private void Start() {
this.doorbell._RegisterHandler(Doorbell.EVENT_RUNG, this, nameof(this._OnRung));
}
private void OnDestroy() {
// remove this handler from every event of the emitter...
this.doorbell._UnregisterHandler(this);
// ...or from a single event:
// this.doorbell._UnregisterHandler(Doorbell.EVENT_RUNG, this, nameof(this._OnRung));
}
// handlers are invoked via SendCustomEvent and therefore must be public
public void _OnRung() {
this.chime.Play();
}
}
API
| Member | Description |
|---|---|
abstract int EventCount |
Number of event slots the emitter provides. |
_RegisterHandler(int eventId, UdonSharpBehaviour handler, string eventName) |
Subscribes handler.eventName to an event. The same handler may register multiple times. |
_UnregisterHandler(UdonSharpBehaviour handler) |
Removes the handler from all events. |
_UnregisterHandler(int eventId, UdonSharpBehaviour handler, string eventName) |
Removes one specific registration. |
protected _EmitEvent(int eventId) |
Calls all handlers registered for the event. |
bool IsUpdatingHandlers |
true while the emitter is calling its handlers. |
Rules & gotchas
- Handlers must be
public. They are invoked by name throughSendCustomEvent. - No registration during emission. Calling
_RegisterHandleron an emitter while it is emitting is rejected with an error. Register inStart()or defer withSendCustomEventDelayedFrames. - Events before registration are lost. Emitters don’t queue events. If the emitter publishes an initial state from
its own
Start(), read that state yourself after registering. - Unregister when you go away. Handlers belonging to destroyed objects are skipped with a warning, but explicitly
unregistering in
OnDestroy()keeps the handler lists clean. - Emitters are
UdonSharpBehaviours. Udon# cannot compile interfaces, so emitting requires extending one of the abstract base classes.
Synchronized emitters
AbstractSynchronizedEventEmitter offers the same API on top of the
AbstractSynchronizedBehaviour base class from the
Common Library, which adds congestion aware manual synchronization with automatic retries. World Utilities’
synchronized values are built on it.
Changelog
See the release history.