Coming from Client Authoritative

Key things to know when coming from client authoritative frameworks

Checking for “isHost”

How to replace “isHost”?

In client authoritative model you often use if (isHost) { ... } to make sure some part of the code runs only once, preferably on the host machine. For example, ending the match, tallying up the score etc. In the server authoritative paradigm there is no host player - every player is a client, and a dedicated machine is the server.

In Elympics SDK you can use if (Elympics.IsServer) { ... } to perform some code only on the server. However, the use cases are a bit more rare than in client-authoritative code, because large parts of the code are predictable, and can be run both on clients and on the server.

Use cases

Use cases in which it is a good practice to perform code on the server only are:

Code that is unpredictable

For example everything that involves randomisation, like spawning random items, map generating etc. Enabling the client to predict this will result in costly and unnecessary reconciliations.

Code that is hard to roll back

Every prediction might be wrong, so if the effects are highly impactful for the gameplay and hard to reconcile, it’s better to not predict them. For example, dying from damage - if a client predicts its death, it will show the deathcam, the visual effects, sound effects, lock player input, and start a respawn countdown. Reconciling all these things will not only be complicated, it will also look bad, as if the game glitched and broke and it will be very confusing for the player.

How to add a RPC?

RPCs, or Remote Procedure Calls, are at the core of client-authoritative multiplayer. A client informs all other clients of an action it performed, for example, dealt damage to another client.

In Elympics, there are no RPCs. Instead, there are player inputs and the game state.

Inputs

Player inputs are serialized and deserialized in IInputHandler and this is the only way a player can inform other players and the server about their action. Each tick, serialized inputs are sent to the server, who deserializes and applies them using the code you’ve written in IInputHandler. The changes made with this code are then synchronised with clients using ElympicsVars.

So, the example of dealing damage would be implemented this way:

  1. “Fire” input is serialized in IInputHandler
  2. “Fire” input is deserialized in IInputHandler
  3. Code with firing logic is performed, with this input passed as an argument
  4. This code modifies ElympicsFloat hp somewhere
  5. Code that is attached as a listener via hp.ValueChanged += ... will happen both on the server and on the clients

Server-side “RPC”

Sometimes you want to inform players about something that happened in code that was performed only on the server, for example, about a death of a player. Since there are no RPCs, the correct way to do this is to attach a listener to a variable, ElympicsBool IsDead; IsDead.ValueChanged += HandlePlayerDied;.

Then you can change the value somewhere

if (Elympics.IsServer)
{
    if (player.hp.Value <= 0)
        player.IsDead.Value = true;
}

Since ElympicsVars are synchronised every tick, all players as well as the server will perform HandlePlayerDied.

Remember that code executed this way will not be predictable.


Last modified September 29, 2022: Add production build script (b8cc0ff)