PUN Classic (v1), PUN 2 and Bolt are in maintenance mode. PUN 2 will support Unity 2019 to 2022, but no new features will be added. Of course all your PUN & Bolt projects will continue to work and run with the known performance in the future. For any upcoming or new projects: please switch to Photon Fusion or Quantum.

Events

Events are Bolt's way of setting up a RPC-like call over the network. Here we describe the types of events that can be created on Photon Bolt, their main differences, and the main usage scenarios.

In relation to how Bolt handles event, keep in mind 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.

Event Types

Global Events

Global Events can be both ReliableOrdered or Unreliable by passing in different parameters to the Create or Post method. In general most Global Events will be sent in Reliable mode (the default mode).

Global Events are sent at a connection level and not to a particular entity, meaning that the target player just need to be connected to the server in order to receive this kind of events. They are intended for things that exist around the game like:

  • Dealing with Authentication;
  • Handling player inventories;

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

Entity Events are always Unreliable, they are intended for small one-off effects like showing a damage indicator or maybe playing an explosion, things that are ephemeral and if one player misses it it doesn't matter.

Entity events are always sent to a particular BoltEntity, meaning that you need a reference to the target Entity, either by getting it from a BoltEntity component or similar.

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 events.

Unreliable Events

Unreliable events, on the other hand, are treted by Bolt differently. Bolt will try to pack the event into a 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 events.

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

In order to create a new Event definition, go to Bolt Assets window (Bolt/Assets menu), click with the right mouse button, and choose New Event. On the Bolt Editor window, you will be able to set the Event name, configure who can send this particular event, and create/setup all properties that will define the event.

One important aspect is who is allowed to send the event. For Global Events, you can choose between: (i) Everyone, meaning that both Server and Client peers can send this event globally, (ii) Only Server, so, only the server can create such event, (iii) Only Clients, all clients can send, but not the server, and (iv) None, so no one will be able to send this event globally. For Entity Events, the options are: (i) Everyone, which allows anyone to send this event, (ii) Only Owner, only the peer that has created the entity is able to send this event, (iii) Only Controller, the entity controller is the only one able to send events from this entity, and (iv) None, meaning that no one is able to send this event as an entity event.

event definition
Event Definition.

After you define the Event, you need to compile Bolt (Bolt/Compile Assembly menu). At this moment, Bolt will generate a new class for your event derived from the Bolt Event class. 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):

C#

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.

C#

// For Global Events
public static EventTest Create();
public static EventTest Create(ReliabilityModes reliability);
public static EventTest Create(GlobalTargets targets);
public static EventTest Create(GlobalTargets targets, ReliabilityModes reliability);
public static EventTest Create(BoltConnection connection);
public static EventTest Create(BoltConnection connection, ReliabilityModes reliability);

// For Entity Events
public static EventTest Create(BoltEntity entity);
public static EventTest Create(BoltEntity entity, EntityTargets targets);

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 and a MyText as an String in Bolt for this event we could do:

C#

void SendEvent()
{
    // Create and setup
    var myEvent = EventTest.Create(GlobalTargets.AllClients);
    myEvent.MyField = 5;
    myEvent.MyText = "hello event!";

    // Send the event
    myEvent.Send()
}

Extending the Create API, Bolt also creates methods with the name Post (available starting on Bolt version 1.2.13), that has the exact same signature as the Create methods described above, but also includes parameters for all fields of the event. The Post methods also send the events automatically when invoked. So, the previous code snippet could be rewritten as:

C#

void SendEvent()
{
    // Create, setup and send
    EventTest.Post(GlobalTargets.AllClients, 5, "hello event!");
}

You can use both methods without any problems.

Receiving Global Events

You can receive global events by deriving a class from Bolt.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 be 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 could also forgot GlobalEventListener and implement the interfaces yourself and manually register the listeners.

In addition to the properties that you've set to your event, Bolt also includes a few other fields that may be useful at some point:

  • evt.FromSelf: Returns true if this event was sent from the own connection;
  • evt.IsGlobalEvent: Returns true if this is a global event, false if an entity event;
  • evt.RaisedBy: The connection which raised this event;
  • evt.BinaryData:: The raw bytes of the event data.

You can read more about those properties on our API Docs here.

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).

C#

public interface IEventListener
{
    bool InvokeIfDisabled { get; }
    bool InvokeIfGameObjectIsInactive { get; }
}

Example:

C#

[BoltGlobalBehaviour(BoltNetworkModes.Server)]
public class BoltServerCallbacks : Bolt.GlobalEventListener, Bolt.IEventListener
{
    public bool InvokeIfDisabled { return true; }
    public bool InvokeIfGameObjectIsInactive { return true; }

    // event callback overrides below
}
Back to top