Events
There are two types of events in Bolt. Global events and entity events. Global events are sent at a connection level and not to a particular entity. Global events have a number of overrides that allow them to fine tune who receives the event (either defined in the Bolt event in the user interface or overridden through code). Entity events are sent to a BoltEntity.
Event Types
Global Events:
Global events can be either be ReliableOrdered or Unreliable. In order to create an event you first must have defined it in Bolt and then you must compile Bolt (in order to generate the backing code for the new event as Bolt uses a code generator behind the scenes).
Entity Events:
Entity events are always unreliable. They are sent to an explicit Bolt entity and Bolt will automatically ignore connections that do not have the entity scoped to it when sending entity events.
Events Reliability
Reliable Events:
Reliable events in Bolt are guaranteed to arrive and to arrive in the order they were sent. The only reliable events that can be sent in Bolt are Global Events.
There is a 3 byte overhead per reliable event.
Unreliable Events:
Remember that Bolt does not send events as a separate packet. The way Bolt works is that it packs everything (state, events, etc) into a single packet each send tick based on your SendRate (see Packets Under the Hood, above). For unreliable events, Bolt will try to pack the event into this packet in two subsequent send ticks; if it was unable to fit the event in either of those attempts, it will drop the event. Essentially Bolt will try to fit unreliable events into the end of the packet if any space is remaining. It will try in two subsequent packets to fit the event into the packet and after that it just gives up and deletes the event. Keep in mind “unreliable” in this context has nothing to do with an “unreliable” network packet in the traditional sense.
There is a 1 byte overhead per unreliable event.
Buffering
Also note that Bolt will not buffer events. If an event arrives for an entity (via an entity event) and the entity doesn’t exist, Bolt will just drop the event. If you need a reliable entity event you should just use a global event with the entity as a field of the event. However, keep in mind that since Bolt packs events and states together in a single packet, not everything can make it into a packet for each send tick - this means that if you try to send an event to an entity right after creating it, you will find that sometimes the event arrives before or after the entity is created. Bolt events and entities are created in separate logical streams in the packet and they will not be ordered with respect to each other.
Bolt Event Generation
Bolt will generate a new class for your event derived from the Bolt Event class after you compile Bolt. So if we created an event EventTest
then Bolt would generate (you can see this event metadata by right clicking on it in Visual Studio
and clicking Go To Definition
):
public class EventTest : Event
{
// ...
}
You then can create the event with one of the the static creation methods. Each of these methods allows you to specify endpoint information. If you specify no target information the defaults from the Event specified in Bolt will be used. If you just want to send the event to a particular connection there is an override specifically for that.
public static EventTest Create();
public static EventTest Create(BoltConnection connection);
public static EventTest Create(GlobalTargets targets);
public static EventTest Create(BoltEntity entity);
public static EventTest Create(ReliabilityModes reliability);
public static EventTest Create(BoltEntity entity,EntityTargets targets);
public static EventTest Create(GlobalTargets targets,ReliabilityModes reliability);
public static EventTest Create(BoltConnection connection,ReliabilityModes reliability);
Once you create your event you can populate the event with your data. The Bolt code generator will generate fields for all of the data you added when you created the event in Bolt and compiled Bolt. For example, if we had added a field called “MyField” as an integer in Bolt for this event we could do:
// Create and setup
var myEvent = EventTest.Create(GlobalTargets.AllClients);
myEvent.MyField = 5;
// Send the event
myEvent.Send()
Receiving Global Events
You can receive global events by deriving a class from GlobalEventListener
and adding it to the scene. Bolt will automatically find all GlobalEventListeners
and register them if they are in the scene when Bolt starts. However, Bolt will de-register them after it shuts down so if you are using a singleton listener and you want the listeners to persist make sure that you override PersistBetweenStartupAndShutdown
in your derived class and return true
.
You can also decorate a GlobalEventListener
derived class with [BoltGlobalBehaviour()]
, and using the various parameters have that listener automatically created when Bolt starts (the two common scenarios using this attribute are adding network type specific listeners (i.e. client vs server) or scene specific listeners). This is used in the tutorials.
Once you have a GlobalEventListener
derived class you can simply override the event handler for the global event you are interested in and implement your logic for receiving the event.
You can also register your own listeners with BoltNetwork.AddGlobalEventListener
and BoltNetwork.RemoveGlobalEventListener
. You can also register for singular events with BoltNetwork.AddGlobalEventCallback
and BoltNetwork.RemoveGlobalEventCallback
although I have not used them myself. You could also forgot GlobalEventListener
and implement the interfaces yourself and manually register the listeners.
You can retrieve the connection that sent the event with EventInstance.RaisedBy
.
IEventListener
This interface can be implemented on Bolt.GlobalEventListener
, Bolt.EntityEventListener
and Bolt.EntityEventListener<T>
in order to modify if the event is still raised if the MonoBehaviour/GameObject
is disabled (by default it will not be raised).
public interface IEventListener
{
bool InvokeIfDisabled { get; }
bool InvokeIfGameObjectIsInactive { get; }
}
Example:
[BoltGlobalBehaviour(BoltNetworkModes.Server)]
public class BoltServerCallbacks : Bolt.GlobalEventListener, Bolt.IEventListener
{
public bool InvokeIfDisabled { return true; }
public bool InvokeIfGameObjectIsInactive { return true; }
// event callback overrides below
}