Adding Events
Sovereign Engine utilizes events for cross-network communication as well as internal communication within each application. It is frequently necessary to add new events to the client and/or server in the process of adding new systems, features, or game mechanics. This guide outlines the process of adding a new event and (optionally) configuring the event to be repeated over the event connection.
Adding a New Event
Adding a new event without network replication is a straightforward process:
Add a new event to the
EventIds
enum. Note that this enum is organized by application (client/server/”core”) and system. The general naming convention for events is to name them after the primary system responsible for processing the event and its location.Note
Specifying the application of an event indicates the application that is responsible for processing the event, not the sending application. For example,
Client_EntitySynchronization_Sync
is processed by the client to synchronize an entity with the server, but it is exclusively sent by the client. Similarly,Core_Movement_Move
is sent and processed by both the client and server.If the event needs to carry any information, either select an existing
IEventDetails
class or create a new one to carry this information. Event details classes should be named by their contents rather than the function of their corresponding events so that they may be more easily reused across multiple events.Subscribe to the event in any systems that need to process it by adding the new event ID to the
ISystem.EventIdsOfInterest
property.Add or update a
Controller
and/orInternalController
class as needed to expose a method-based API for sending the new event.Controller
classes should be in the same namespace as the primary processing system, whereasInternalController
classes should be in the same namespace as the primary system responsible for sending the event.Note
Controller
classes are generally preferred forCore
events and for events that are sent and processed within a single application; they provide an asynchronous API for interacting with the system.InternalController
classes are necessary when the event is processed exclusively in a different application than where it is sent as the processing system will not be present in the sending application.
Replicating an Event via the Network
Many events need to be replicated over the event connection in one or both directions. By default, events are not replicated over the network, and events are not accepted over the network unless the receiving application is explicity configured to do so. This configuration requires a number of changes:
Add the event ID to the
IOutboundEventSet
class for any application that will be sending the event over the network.Add the event ID to the
XAllowedEventsInboundPipelineStage
class (whereX
isClient
orServer
) for any application that will be receiving the event over the network.Add the event ID to
DeliveryMethodOutboundPipelineStage
with an appropriate network delivery method. When in doubt, chooseDeliveryMethod.ReliableUnordered
.Add the event ID to
ValidationInboundPipelineStage
with the appropriateIEventDetailsValidator
class for theIEventDetails
class associated with the event. You may need to create a newIEventDetailsValidator
class if the event uses a newIEventDetails
class or one that has not been used with a network replicated event yet.Note
If the event has no associated details, it must still be added to
ValidationInboundPipelineStage
with theNullEventDetailsValidator
validator, otherwise the event will be rejected by the receiving application.If the event will be sent from the server, add the event ID to
ServerConnectionMappingOutboundPipelineStage
with the appropriate connection mapper. The connection mapper is responsible for determining which connections will receive the event when it is sent by the server. Connection mappers typically use information in the event details to determine which players should receive the event.Note
Connection mappers can map events to any connection, not just to players in the game world. This distinction is important for template entity synchronization, where the template entities are loaded once at initial login and then kept in sync through a series of events that are broadcast to all connections by the server.
If the event will be sent from client to server, and if the event details must contain the entity ID of the player who sent the event, update
SourceEntityMappingInboundPipelineStage
with a new function that modifies the corresponding event details to contain the entity ID of the sender.Warning
Never trust the client to send the correct player entity ID for themselves. A malicious client could send an event with a spoofed entity ID. The
SourceEntityMappingInboundPipelineStage
mitigates this threat by overriding the entity ID in the details with the entity ID associated with the event server connection that received the event.If the event will be sent from client to server, and if the event should only be accepted from certain players (e.g. an admin-only event), update
PlayerFilterInboundPipelineStage
and add the appropriate filter function for the new event.Note
This could also be accomplished by including the entity ID in the event details, following step 6 above, and checking it in the systems.
PlayerFilterInboundPipelineStage
is the preferred solution as it eliminates duplicate checks across multiple systems and reduces the risk of incorrectly accepting a malicious event when a new system is added that consumes the event.