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
EventIdsenum. 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 however that there is not always a clear choice of name under this scheme, and so this guidance is only loosely followed.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_Syncis processed by the client to synchronize an entity with the server, but it is exclusively sent by the client. Similarly,Core_Movement_Moveis sent and processed by both the client and server.If the event needs to carry any information, either select an existing
IEventDetailsclass 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.EventIdsOfInterestproperty.Add or update a
Controllerand/orInternalControllerclass as needed to expose a method-based API for sending the new event.Controllerclasses should be in the same namespace as the primary processing system, whereasInternalControllerclasses should be in the same namespace as the primary system responsible for sending the event.Note
Controllerclasses are generally preferred forCoreevents and for events that are sent and processed within a single application; they provide an asynchronous API for interacting with the system.InternalControllerclasses 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
IOutboundEventSetclass for any application that will be sending the event over the network.Add the event ID to the
XAllowedEventsInboundPipelineStageclass (whereXisClientorServer) for any application that will be receiving the event over the network.Add the event ID to
DeliveryMethodOutboundPipelineStagewith an appropriate network delivery method. When in doubt, chooseDeliveryMethod.ReliableUnordered.Add the event ID to
ValidationInboundPipelineStagewith the appropriateIEventDetailsValidatorclass for theIEventDetailsclass associated with the event. You may need to create a newIEventDetailsValidatorclass if the event uses a newIEventDetailsclass 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
ValidationInboundPipelineStagewith theNullEventDetailsValidatorvalidator, otherwise the event will be rejected by the receiving application.If the event will be sent from the server, add the event ID to
ServerConnectionMappingOutboundPipelineStagewith 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
SourceEntityMappingInboundPipelineStagewith 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
SourceEntityMappingInboundPipelineStagemitigates 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
PlayerFilterInboundPipelineStageand 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.
PlayerFilterInboundPipelineStageis 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.