Updateto run the simulation (every player might run at a different frame rate)
Playercomponent and a Prefab for it. We'll use the client connection system to make our
Playerrepresent a session participant and automatically spawn the selected Prefab for each player that connects to the Server. The
Playerwill also be responsible for handling inputs using the
Playercode looks as follows:
SetMovementwill be called by our "central" simulation code. Now that we have our
Playerdefined let's prepare a Prefab for it. Create a GameObject and attach the
Playercomponent to it, using the
CoherenceSyncinspector create a Prefab. The inspector view for our Prefab should look as follows:
Movaxis has been added to the CoherenceInput which will let us sync the movement input state
CoherenceMonoBridgeand enable the global query:
SetInputsis called by the system when it's time for our local
Playerto update its input state using the
Simulateis called when it's time to simulate a given frame. It is also called during frame re-simulation after misprediction - don't worry though, the complex part is handled by the
CoherenceInputSimulationinternals - all you need to do in this method is apply inputs from the
CoherenceInputto run the simulation
Rollbackis where we need to set the simulation state back to how it was at a given frame. The state is already provided in the
stateparameter, we just need to apply it
CreateStateis where we create a snapshot of our simulation so it can be used later in case of rollback
OnClientLeftare optional callbacks. We use them here to start and stop the simulation depending on the number of clients
Simulationscript to the MonoBridge object on scene and link the MonoBridge back to the
FixedNetworkUpdaterunning at different (usually lower) rate than Unity's
Updateloop, polling inputs using the functions like
Input.GetKeyDownis susceptible to a input loss, i.e. keys that were pressed during the
Updateloop might not show up as pressed in the
Updateis running five times for each network
FixedNetworkUpdate, if we polled inputs from the
FixedNetworkUpdatethere's a chance that an input was fully processed within the five
FixedNetworkUpdates, i.e. a key was "down" on the first
Update, "pressed" on the second, and "up" on a third one.
FixedUpdateInputworks by sampling inputs at
Updateand prolonging their lifetime to the network
FixedNetworkUpdateso they can be processed correctly there. For our last example that would mean "down" & "pressed" registered in the first
FixedNetworkUpdateafter the initial five updates, followed by an "up" state in the subsequent
CoherenceInput.InputBufferSize. When Clients try to predict too many frames into the future (more frames than the size of the buffer) the simulation will issue a pause. This pause affects only the local Client. As soon as the Client receives enough inputs to run another frame the simulation will resume.
OnPauseChange(bool isPaused)method from the
CoherenceInputSimulationhas a built-in debugging utility that collects various information about the input simulation on each frame. This data can prove extremely helpful in finding a simulation desync point.
CoherenceClientConnection.ClientIdof the local client.
CoherenceInputDebugger.OnDumpdelegate, where the string parameter is a JSON dump of the data.
CoherenceInputSimulation.Debugger. Most of the debugging data is recorded automatically, however, the user is free to append any arbitrary information to a frame debug data, as long as it is JSON serializable. This is done by using the
CoherenceInputDebugger.FramesToKeepproperty. For example, setting it to 1000 will instruct the debugger to keep only the latest 1000 frames worth of debugging information in the memory.
JsonPropertyattribute, we can control how a given field/property/class will be serialized. In this case, we've instructed the JSON serializer to use the custom
UnityVector3Converterfor serializing the vectors.
Frame- frame of this debug data
AckFrame- the common acknowledged frame, i.e. the lowest frame for which inputs from all clients have been received and are known to be valid (not mispredicted)
ReceiveFrame- the common received frame, i.e. the lowest frame for which inputs from all clients have been received
AckedAt- a frame at which this frame has been acknowledged, i.e. set as known to be valid (not mispredicted)
MispredictionFrame- a frame that is known to be mispredicted, or
-1if there's no misprediction
Hash- hash of the simulation state. Available only if the simulation state implements the
Initial state- the original simulation state at this frame, i.e. a one before rollback and resimulation
Initial inputs- original inputs at this frame, i.e. ones that were used for the first simulation of this frame
Updated state- the state of the simulation after rollback and resimulation. Available only in case of rollback and resimulation
Updated inputs- inputs after being corrected (post misprediction). Available only in case of rollback and resimulation
Input buffer states- dump of the input buffer states for each client. For details on the fields see the
Events- all debug events registered in this frame
InitialBufferSizevalue can be set directly in code however it must be done before the
Awakeof the baked component, which might require a script execution order configuration.
IClient.ClientFixedSimulationFrameframe for simulation - otherwise the
IClient.ClientSimulationFrameis used. Setting this to "true" is recommended for a deterministic simulation.