Overview
This page discusses the implementation of the event system. The event system
provides a publish and subscribe pattern for distributed system.
The following topics are covered:
- Publishing events
- Subscription to events
- Two phase commit events
- Creating your own events
Introduction
Basicaly, events in the multiplayer framework are like normal network objects.
They have some special properties though: They have a short lifespan and can
not be synchronized over the network. On the other hand, events need to be
registered the very same way like every object. Check out the section
about object synchronisation to get more
information about that topic.
You use events for example to send
messages to other peers. Peers can subscribe handlers to each event, that allows
them to execute something or to process the data that was being sent. Afterwards,
the event object will be destroyed. Unlike normal network objects, events do not
need a unique ID, which is therefore 0 by default. You can of course use an ID
for you own purpose, but you'll also have to serialize it yourself.
Because events are normal objects, they are sent through the very same unreliable
mechanism. You can not be sure, that every remote peer has received your event.
As there are various tasks, where it is necessary to know that an event has been
properly received, the multiplayer framework supports a special kind of events,
the so called two phase commit events (2PC). For such an event, the receiver of an
event will immediately return an acknowledgement. Of course this acknowledgement
could also be lost, so 2PC events will resend themselves until all remote peers
either acknowledged the reception or a timeout occurred. The drawback of this method
is performance: It takes significantly longer until a consensus is reached. You
should take this into consideration, if you need to use 2PC events. As a
consequence of this system, 2PC events need IDs again. Those IDs have less
restrictions than normal object IDs: They must only be unique per event and
peer/host. Remember: 'Normal' object IDs are unique on the whole network!
Object creation an destruction is an application of 2PC events.
Using events
A basic (non 2PC) event inherits from the class EM_NET_EVENT_OBJECT that itself inherits from EM_NET_OBJECT.
Publishing events over the network
To publish an event, ie sending it to another peer, you first need a new event instance. Since predefined events are already registered, you can do this by calling the corresponding creation query in EM_NET_OBJECT_TYPES or one of its descendants. The next step is to set the group to which you want to publish the event. Do this using set_group. The event will then be published to every connection in the specified group by calling publish. That's about all the magic there is!
On the remote peer, the event will not be received on the group you set with
set_group!
set_group
only specifies the set of connections you want to send the event to.
Events always arrive at the
personal_group
on the remote side of each connection. This behaviour is by design.
EM_NET_BASE provides you with the convenience feature publish that publishes an event to the standard group.
Subscription for incoming events
You now know how to publish event. Now let's look at the other side of the
connection: To receive events, you have to subscribe for them. Events that
have no subscribers will just vanish. Some of the predefined events already
have some procedures registered. The two events
EM_NET_TIME_SYNC_REQUEST
and EM_NET_TIME_SYNC_REQUEST
are two examples of events that you usually don't have to deal with: They
are registered and processed in the background. Of course, it is possible
to subscribe another handler in case you need it.
To subscribe a handler (ie an agent) to an event,
EM_NET_BASE provides
you with the feature subscribe_by_type_id.
You can get the event ID through EM_NET_OBJECT_TYPES
or one of its descendants. The agent that you supply as
argument will be called as soon as the event has been received.
Illustration of the event system

- In the illustration, there are four peers: peer_A, peer_B, peer_C and peer_D.
- The illustration shows the point of view from peer_C.
- There are three groups: red, green and blue.
- The three peers are distributed to these three groups. Each group has its own unique set of objects (the grey rectangles).
- If peer_C sends an event to the green group the EM_NET_EVENT_CONTAINER_OBJECT from the green group is used to fulfil the task. That's why each group owns its container: This enables a distinction between the different destinations.
- Because of the fact that groups are only used for organizational purposes and are not a part from the protocol itself, there's only one EM_NET_EVENT_CONTAINER_OBJECT for all incoming events. The default is to publish the incoming events to EM_NET_BASE and to the EM_NET_CONNECTION that was the sender of the event. If you would like to publish events to groups you can easily extend the framework: EM_NET_GROUP inherits as well from EM_NET_EVENT_CONTAINER_OBJECT which enables the programmer to subscribe for events per group. One would then need to implement a mechanism which selects all groups where an event should be published. This is highly program specific and enabling a solution per default would be performance consuming.
Characteristics of 2PC events
Two phase commit events are the tool if you need reliable transmission of events. A receiver of a 2PC
event will automatically acknowledge its reception. The sender remembers which host didn't respond after
some time and will resend the event for such a host. This timeout interval, as well as the number of times
an interval will be resent, can be specified by the application developer. If all connections responded
with an acknowledge in time, a success agent will be called. In all other cases a timeout agent is called,
supplying a list of the non-responding connections as argument.
A 2PC event is a class that inherits from
EM_NET_2PC_EVENT_OBJECT.
The following additional features are available:
- set_success_agent allows to set an agent that is called if all connections responded with an acknowledgement in time.
- set_timeout_agent allows to set an agent that is called if at least one connection didn't respond with an acknowledgement in time. A list of non-responding connection is supplied as argument to the agent.
- set_resend_time allows to set a time in milliseconds, after which an event is resent to all connection that didn't send an acknowledgement.
- set_resends_left allows to set the number of times an event is resent at most.
Implement custom events
Non-2PC events
Implementing custom events is very similar to normal object registration. First, you need to create a new class that inherits from EM_NET_EVENT_OBJECT which will represent your event. Afterwards, register a unique type ID like it is described in the object synchronisation section. You may now extend the event with functionality and/or data you need. The last step is to implement the deferred features serialize, unserialize and serialization_byte_count.