Server-side and input queues

What are Input Queues?

Input queues enable a simulator to take control of the simulation of another client's objects based on the client's inputs.

When To Use Input Queues?

  • In situations where you want a centralized simulation of all inputs. Many game genres use input queues 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 use input queue and just display the replicated results on the clients.

  • In situations where determinism is important. RTS and fighting games will use input queues 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 input queues in a centralized way where a single simulator is setup to process all inputs and replicate the results to all clients.

Setup With CoherenceSync and CoherenceInput

Setting up an object to simulate via input queues using CoherenceSync is done in three steps:

1. Preparing the CoherenceSync component on the object prefab

The Simulation Type of the CoherenceSync component is set to Simulation Server With Client Input

Setting the simulation type to this mode instructs the client to automatically give authority over this object to the simulator in charge of simulating all inputs on all objects.

2. Declaring Inputs for the simulated object

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 - 1.

  • Axis. An axis input is tracked as two floats from 0 - 1 in both the X and Y axis.

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.

3. Bake the CoherenceSync object

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.

Using CoherenceInput

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.

Client-Side Set* Methods

  • public void SetButtonState(string name, bool value)

  • public void SetButtonRangeState(string name, float value)

  • public void SetAxisState(string name, Vector2 value)

Simulator-Side Get* Methods

  • public bool GetButtonState(string name)

  • public float GetButtonRangeState(string name)

  • public Vector2 GetAxisState(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.

using Coherence.Toolkit;
using UnityEngine;

public void SendMousePosition()
{
    var coherenceInput = GetComponent<CoherenceInput>();
    var mousePos = Input.mousePosition;
    coherenceInput.SetAxisState("mouse", new Vector2(mousePos.x, mousePos.y));
}

The simulator can access the state of the input to perform simulations on the object which are then reflected back to the client as any replicated object is.

using Coherence.Toolkit;
using UnityEngine;

public void ProcessMousePosition()
{
    var coherenceInput = GetComponent<CoherenceInput>();
    var mousePos = coherenceInput.GetAxisState("mouse");
    
    //Move object
}

Input Owner

Each object only accepts inputs from one specific client, called the object's Input Owner.

When a client spawns an object it automatically becomes the Input Owner for that object. This way, the object's creator will retain control over the object even after authority has been transferred to the simulator.

If an object is spawned directly by the simulator, you will need to assign the Input Owner manually. Use the SetInputOwner method on the CoherenceInput component to assign or re-assign a client that will take control of the object:

public void AssignNewInputOwner(ClientConnection newInputOwner)
{
    var coherenceInput = GetComponent<CoherenceInput>();
    coherenceInput.SetInputOwner(newInputOwner.ClientId);
}

The ClientId used to specify input owner can currently only be accessed from the ClientConnection class. For detailed information about setting up the ClientConnection prefab, see the Client Messages page.

Use the OnInputOwnerAssigned event on the CoherenceSync component to be notified whenever an object changes input owner.

Client-Side Prediction

Generally, using server-side simulation with simulators makes the time from the client providing input to the time the object is updated with that input significantly longer than just client-side simulation 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 can cause visual lag. Using input queues allows the client to perform prediction of the simulation to provide a smooth playing experience.

If the client simulates the inputs on the object as well as applying them to the CoherenceInput component and then blends the authoritative results from the simulator with the locally simulated results, then smoother and more responsive simulation is achieved.

Rollback is not currently available but is in the roadmap. Each client will be aware of the current global simulation frame and so the inputs can be applied by each client at the same frame in time and so client-side prediction can be even more accurate.

Last updated