CoherenceInput is a component that enables a Simulator to take control of the simulation of another Client's objects based on the Client's inputs.
In situations where you want a centralized simulation of all inputs. Many game genres use client inputs and centralized simulation to guarantee the fairness of actions or the stability of physics simulations.
In situations where Clients have low processing power. If the Clients don't have sufficient processing power to simulate the World it makes sense to send inputs and just display the replicated results on the Clients.
In situations where determinism is important. RTS and fighting games will use CoherenceInput and rollback to process input events in a shared (not centralized) and deterministic way so that all Clients simulate the same conditions and produce the same results.
coherence currently only supports using CoherenceInput in a centralized way where a single Simulator is setup to process all inputs and replicate the results to all Clients.
Setting up an object for server-side simulation using CoherenceInput and CoherenceSync is done in three steps:
The simulation type of the CoherenceSync component is set to Server Side With Client Input
Setting the simulation type to this mode instructs the Client to automatically transfer State Authority for this object to the Simulator that is in charge of simulating inputs on all objects.
Each simulated CoherenceSync component is able to define its own, unique set of inputs for simulating that object. An input can be one of:
Button. A button input is tracked with just a binary on/off state.
Button Range. A button range input is tracked with a float value from 0 to 1.
Axis. An axis input is tracked as two floats from -1 to 1 in both the X and Y axis.
String. A string value representing custom input state. (max length of 63 characters)
To declare the inputs used by the CoherenceSync component, the CoherenceInput component is added to the object. The input is named and the fields are defined.
In this example, the input block is named Player Movement and the inputs are WASD and mouse for the XY mouse position.
In order for the inputs to be simulated on CoherenceSync objects, they must be optimized through baking.
If the CoherenceInput fields or name is changed, then the CoherenceSync object must be re-baked to reflect the new fields/values.
When a Simulator is running it will find objects that are set up using CoherenceInput components and will automatically assume authority and perform simulations. Both the Client and Simulator need to access the inputs of the CoherenceInput of the replicated object. The Client uses the Set* methods and the Simulator uses the Get* methods to access the state of the inputs of the object. In all of these methods, the name parameter is the same as the Name field in the CoherenceInput component.
public void SetButtonState(string name, bool value)
public void SetButtonRangeState(string name, float value)
public void SetAxisState(string name, Vector2 value)
public void SetStringState(string name, string value)
Simulator-Side Get* Methods
public bool GetButtonState(string name)
public float GetButtonRangeState(string name)
public Vector2 GetAxisState(string name)
public string GetStringState(string name)
For example, the mouse click position can be passed from the Client to the Simulator via the "mouse
" field in the setup example.
The Simulator can access the state of the input to perform simulations on the object which are then reflected back to the Client just as any replicated object is.
Each object only accepts inputs from one specific Client, called the object's Input Authority.
When a Client spawns an object it automatically becomes the Input Authority for that object. The object's creator will retain control over the object even after state authority has been transferred to the Simulator.
If an object is spawned directly by the Simulator, you will need to assign the Input Authority manually. Use the TransferAuthority method on the CoherenceSync component to assign or re-assign a Client that will take control of the object:
The ClientId used to specify Input Authority can currently only be accessed from the ClientConnection class. For detailed information about setting up the ClientConnection Prefab, see the Client connections page.
Use the OnInputAuthority and OnInputRemote events on the CoherenceSync component to be notified whenever an object changes input authority.
Only the object's current State Authority is allowed to transfer Input Authority.
In order to get notified when the Simulator (or host) takes state authority of the input you can use the OnInputSimulatorConnected event from the CoherenceSync component.
The OnInputSimulatorConnected event can also be raised on the Simulator or host if they have both input and state authority over an entity. This allows the session host to use inputs just like any other client but might be undesirable if input entities are created on the host and then have their input authority transferred to the clients.
To solve this you can check the CoherenceSync.IsSimulatorOrHost flag in the callback:
The CoherenceLiveQuery component can be used to limit the visible portion of the Game World that a player is allowed to see. The Replication Server filters out networked objects that are outside the range of the LiveQuery so that players can't cheat by inspecting the incoming network traffic.
When a query component is placed on a Game Object that is set to Server Side With Client Inputs the query visibility will be applied to the Game Object's Input Authority (i.e., the player) while the component remains in control of the State Authority (i.e. the Simulator). This prevents players from viewing other parts of the map by simply manipulating the radius or position of the query component.
See Area of interest for more information on how to use queries.
Using Server-side simulation takes a significantly longer period of time from the Client providing input until the game state is updated, compared to just using Client-side simulation. That's because of the time required for the input to be sent to the Simulator, processed, and then the updates to the object returned across the network. This round-trip time results in an input lag that can make controls feel awkward and slow to respond.
If you want to use a Server-authoritative setup without sacrificing input responsiveness, you need to use Client-side prediction. With Client-side prediction enabled, incoming network data is ignored for one or more bindings, allowing the Client to predict those values locally. Usually, position and rotation are predicted for the local player, but you can toggle Client-side prediction for any binding in the Configuration window.
By processing inputs both on the Client and on the Server, the Client can make a prediction of where the player is heading without having to wait for the authoritative Server response. This provides immediate input feedback and a more responsive playing experience.
Note that inputs should not be processed for Clients that neither have State Authority nor Input Authority. That's because we can only predict the local player; remote players and other networked objects are synced just as normal.
With Client-side prediction enabled, the predicted Client state will sometimes diverge from the Server state. This is called misprediction. When misprediction occurs, you will need to adjust the Client state to match the Server state in one way or another. This is called Server Reconciliation.
There are many possible approaches to Server Reconciliation and coherence doesn't favor one over another. The simplest method is to snap the Client state to the Server state once a misprediction is detected. Another method is to continuously blend from Client state to Server state.
Misprediction detection and reconciliation can be implemented in a binding's OnNetworkSampleReceived
event callback. This event is called every time new network data arrives, so we can test the incoming data to see if it matches with our local Client state.
The misprediction threshold is a measure of how far the prediction is allowed to drift from the Server state. Its value will depend on how fast your player is moving and how much divergence is acceptable in your particular game.
Remember that incoming sample data is delayed by the round-trip time to the Server, so it will trail the currently predicted state by at least a few frames, depending on network latency. The simulationFrame
parameter tells you the exact frame at which the sample was produced on the authoritative Server.
For better accuracy, incoming network samples should be compared to the predicted state at the corresponding simulation frame. This requires keeping a history buffer of predicted states in memory.
This feature is in the experimental phase.
A client-hosted session is an alternative way to use CoherenceInput in Server Side With Client Input mode that doesn't require a Simulator.
A Client that created a Room can join as a Host of this Room. Just like a Simulator, the Host will take over the State Authority of the CoherenceInput objects while leaving the Input Authority in the hands of the Client that created those objects.
The difference between a Host and a Simulator is that the Host is still a standard client connection, which means it counts towards the Room's client limit and will show up as a client connection in the connection list.
To connect as a Host all we have to do is call CoherenceMonoBridge.ConnectAsHost: