Lifecycle events and actions

Providing listeners for network or game events and managing the game lifetime.

Gameplay implementation is just one of the steps in creating a perfect game. There are many other factors that affect player experience. One of them, staying in close relation to gameplay, is maintaining the match lifetime and the currently playing squad.

If you prefer hands-on experience, check out “Match events” sample project included in Unity SDK package.

Joining a match

First things first, players can join a match using the following methods:

  • IElympics.ConnectAndJoinAsPlayer(Action<bool> connectedCallback, CancellationToken ct) – to join as a full player and have one’s input gathered and sent to the server,
  • IElympics.ConnectAndJoinAsSpectator(Action<bool> connectedCallback, CancellationToken ct)1 – to join in a read-only mode where only one-way (server to client) communication occurs and one is not counted as a match player.

Both of these methods are coroutines returning IEnumerator. The correct way of running them is using Unity StartCoroutine wrapper.

Normally, there is no need to call ConnectAndJoinAsPlayer manually as it is done by Elympics when client instance initializes. This behavior is customizable using “Connect On Start” checkbox of Elympics Client editor:

Elympics Client editor

ConnectAndJoinAsPlayer and ConnectAndJoinAsSpectator consist of three steps: they establish a connection to the game server, then perform user authentication and finally register a player in the match. Completion of each step can be tracked by implementing the following methods from IClientHandler interface:

  • IClientHandler.OnConnected(TimeSynchronizationData data),
  • IClientHandler.OnAuthenticated(string userId)userId becomes null when joining as a spectator,
  • IClientHandler.OnMatchJoined(string matchId)

along with their corresponding error handlers:

  • IClientHandler.OnConnectingFailed(),
  • IClientHandler.OnAuthenticatedFailed(string errorMessage),
  • IClientHandler.OnMatchJoinedFailed(string errorMessage).

Meanwhile on the server, only one callback is executed:

  • IServerHandler.OnPlayerConnected(ElympicsPlayer player)

ElympicsPlayer passed here is used to distinguish a player from others in player data array passed as the only parameter of server initialization callback (described below).

Leaving a match

A match can be also left using IElympics.Disconnect(). If the match isn’t ended immediately by the server, players can rejoin it.

As matches with players missing have a great chance of becoming unplayable, you may want to close the server after some delay (using the action described in the next section). To make sure the server is notified about such an event, you have to implement IServerHandler.OnPlayerDisconnected(ElympicsPlayer player).
As before, received in-match player identifier can be used as an index to player data array passed in server initialization callback.

After a client disconnects from the server, it runs its IClientHandler.OnDisconnectedByClient().

Finishing a match

As non-finished games take up resources, ending a match is a crucial step. Game server lifetime is currently limited to 24 hours, so no game runs indefinitely. But surely you don’t want your players to wait a whole day until they can play again. Or a 5-minute match to cost you much more than planned.

The method you need to call is IElympics.EndGame(). Depending on your circumstances, you can pass an optional parameter of type ResultMatchPlayerDatas containing match results.

The inclusion of ResultMatchPlayerDatas object is essential if you want to take advantage of intelligent matchmaking (using Elo rating or machine learning) or other score-related services provided by Elympics.

ResultMatchPlayerDatas is a list of ResultMatchPlayerData. Each entry should contain data associated with the corresponding player. As there is no player ID included, you should check InitialMatchPlayerDatas received at the start of the game for the correct order.

ResultMatchPlayerData stores game-specific byte[] GameEngineData and float[] MatchmakerData with a structure defined by Elympics. MatchmakerData must contain two elements:

  1. Matchmaker-compatible score. The greater this number is, the higher matchmaker rating. If your game takes a different approach (e.g. you’re creating a racing game where time becomes the score), you have to transform your data appropriately.
  2. Game-specific score details. You can put original, unprocessed score here.

You can read more about the matchmaker in the next chapter.

Of course, there are some situations when a match ends with no meaningful results to send to the matchmaker, e.g. not all players joined the game to begin with. In such case you should call EndGame() with no arguments.

When a match ends, the following callbacks are run on clients (in the order listed):

  • IClientHandler.OnMatchEnded(string matchId),
  • IClientHandler.OnDisconnectedByServer().

DefaultServerHandler

As mentioned earlier, it’s really important to end a game correctly. This is why Elympics prefab includes DefaultServerHandler which closes the match if any connected player leaves. It also calls EndGame() if not all players join the game in the first 30 seconds of server lifetime.

DefaultServerHandler object inside Elympics prefab

The handler outputs logs to console when players connect and disconnect and when it decides if the game should be ended.
Messages such as “Waiting for game to start” could make you think that games are started using a method analogous to EndGame(). However, that is not true. The start of a server means the start of a match.

Providing a custom implementation

If the behavior described above is not suited for your game, you can disable the built-in implementation of IServerHandler.

DefaultServerHandler script checks Behaviour.isActiveAndEnabled property in every implemented IServerHandler method, so you can untick DefaultServerHandler component or the whole DefaultServerHandler object in inspector to prevent it from executing.

Disabling DefaultServerHandler component

Deactivating DefaultServerHandler game object

Alternatively you can just remove DefaultServerHandler component from DefaultServerHandler object in the instance of Elympics prefab.

Removing DefaultServerHandler component

DefaultServerHandler class is a good starting point for implementing a custom server lifetime guard. After copying the code, you can modify it to suit your needs.

Other events

Initialization

When a game instance starts, an initialization callback is run with game and player data passed as the only parameter. To retrieve the data you can implement appriopriate methods of IServerHandler, IClientHandler and IBotHandler interfaces.

The data is stored as instances of InitialMatchPlayerData. The class consists of the following properties:

  • ElympicsPlayer Player – in-match player identifier,
  • string UserId – globally unique player identifier,
  • bool IsBot – information if player is a bot,
  • double BotDifficulty – how well a bot should play (if the player is a bot),
  • byte[] GameEngineData – optional game-specific data which you can use to provide initial settings for a match,
  • float[] MatchmakerData – optional game and player-related data for matchmaker to learn from (if ML matchmaking is enabled).

For a server, the method is IServerHandler.OnServerInit(InitialMatchPlayerDatas initialMatchPlayerDatas). It provides not a single instance of InitialMatchPlayerData, but a list of such objects. Each object corresponds to one of match players.

For a client, you should implement IClientHandler.OnStandaloneClientInit(InitialMatchPlayerData data).
There is also IClientHandler.OnClientsOnServerInit(InitialMatchPlayerDatas data) used only in “Local Player And Bots” development mode. For convenience, it provides a list of all clients run inside the server instance.

For a bot, you can use IBotHandler.OnBotsOnServerInit(InitialMatchPlayerDatas initialMatchPlayerDatas) as running bots inside the server instance is the default option. As in the case of OnClientsOnServerInit, the method provides a list of data of all bots running in the server.
If you changed the setting, you should use OnStandaloneBotInit(InitialMatchPlayerData initialMatchPlayerData) instead.
The setting is available in Elympics Game Config:

&ldquo;Bots inside server&rdquo; setting in Elympics Game Config

Providing InitialMatchPlayerDatas

There are two points at which you can input GameEngineData and MatchmakerData for your game to use during the initialization process.

The first is when you call ElympicsLobbyClient.PlayOnline(). This method accepts four optional parameters, including float[] matchmakerData = null and byte[] gameEngineData = null. Check out the next chapter for more details.

The second approach requires using your own back end. The definition of needed endpoints can be found in External Game Backend integration chapter, along with instructions on how to configure the back-end address to be used by your game.

Clock synchronization

The one last callback to describe is IClientHandler.OnSynchronized(TimeSynchronizationData data). It is called every time a client synchronizes its clock with the server (using NTP protocol).

An implementation of this method can be used to track the condition of network connection using information from TimeSynchronizationData object passed as the only parameter. For example RoundTripDelay property can be displayed as “ping” in an in-game UI.


  1. The spectator mode is an experimental feature. Its behavior may change in future releases. ↩︎