Single-player gameplay
How coherence behaves when a Client is not connected
Even though coherence is a networking solution, there might be instances when a Scene configured for online play is used offline, without connecting to a Replication Server. This can be useful for creating gameplay that works in an offline game mode (like a tutorial), or simply a game that can connect and disconnect seamlessly during uninterrupted gameplay.
The ability to create Prefabs and code that can be used both online and offline is an great tool that in the long term can streamline the development process, avoid duplicated code, ultimately creating less bugs.
Dos and Don'ts
To ensure that the code you write doesn't break when offline, follow these recommendations:
Check if a
CoherenceBridge
is connected usingCoherenceBridge.isConnected
.CoherenceSync
components also have a reference to the associated bridge, so if one is present in the Scene you can usesync.CoherenceBridge.isConnected
for convenience.When offline,
CoherenceSync.EntityState
isnull
. Use this to your advantage to identify the state of the connection.Authority is assumed on offline entities (
CoherenceSync.HasStateAuthority
always returnstrue
).You can use commands. They will be routed to local method calls.
When offline, some events on coherence components (e.g.,
CoherenceBridge.OnLiveQuerySynced
) won't be fired, so review any game logic that depends on them.Persistence and uniqueness are not resolved when offline, so don't make assumptions about their network state.
When offline, if you have a Prefab in the Scene that is set to Simulate In Server Side, it won't be automatically removed (since there's no connection, hence coherence can't infer if it's a Simulator or a Client connection). You can use
SimulatorUtility.IsSimulator
in anOnEnable()
and deactivate it.In case of a server-authoritative scenario using
CoherenceInput
, you might want to isolate state-changing code that would run in the Simulator into its own script. This way, it can be reused to directly affect the state of the entity when the game is offline.
See below for a more in-depth description of how the different components behave.
Components behavior when offline
This section describes how the different components offered by coherence behave when the game is offline.
CoherenceBridge
Because the CoherenceBridge
never tries to connect, it won't fire any connection-related events.
You won't be able to query the list of ClientConnections, and all Room or World related data or Services data won't be there.
However, you will be able to access through the CoherenceBridge
what is part of the setup at edit time. For instance, you will be able to inspect the list of CoherenceSyncConfig
objects in order to instantiate connected Prefabs.
CoherenceSync
Connected Prefabs that feature a CoherenceSync
can be instantiate and destroyed like usual while offline.
Authority
Because it's always the local Client that creates instances of connected Prefabs, it will automatically receive full authority on all of them. Consequently, the OnStateAuthority
callback will be invoked when the object is instantiated, in OnEnable()
. Check on sync.HasStateAuthority
will return true, as early as Awake()
.
The Client has authority to manipulate its state, and can destroy the Prefab instance at will.
If a Component has been configured to be enabled/disabled as a result of authority changes (that is, using Component Actions), it will be enabled.
Network Commands
No change in behavior. Network Commands will invoke the corresponding method with a direct invocation, with no network delay incurred.
Persistent entities
Prefabs marked as Persistent will not persist after an offline game session. They will be destroyed when the Scene they belong to is unloaded, and will not be automatically recreated if the Scene is re-loaded.
Persistence is tied to the World or Room the Client is connected to. If you need objects to persist between different offline sessions, you need to store their state some other way.
Unique entities
Like persistence, uniqueness is also verified within the context of the Room or World the Client is connected to, and is generally used for ensuring that a different Client can't bring an already existing entity to the simulation.
When offline, no check happens for uniqueness, meaning that unique entities can be instantiated multiple times. It is therefore up to the local gameplay code to make sure this doesn't happen in the first place.
Simulate in Server-side
Any Prefab for which the property Simulate In has been set to Server-Side will not be automatically deactivated on instantiation.
To ensure such a Prefab doesn't appear in an offline session, make sure to deactivate it in its code by using:
LiveQuery
LiveQuery
components will not have any effect offline. However, keep in mind that they will try to find the CoherenceBridge
, so if none is present they will throw an error. For this reason it's a good idea to keep them together, and only have a LiveQuery
in the scene if a CoherenceBridge
is present.
CoherenceNode
Any CoherenceNode
component will have no effect. There are no drawbacks for leaving it inside the Prefabs.
CoherenceInput
Given that it's inherently meant to be used in a Client-Server scenario, CoherenceInput
has no meaning offline.
However, you can safely leave the component on your Prefabs, and architect your scripts so that rather than sending inputs to CoherenceInput
regardless, they first check if the Client is connected and, in case of a negative answer, manipulate the entity's state instead.
It can be a good idea to isolate the code used to manipulate the entity's state during prediction, and reuse it for offline behavior.
If the game is online, input is sent to the Simulator via
CoherenceInput
, while at the same time prediction is done locally and applied. On the Simulator, the same code used from the Client to do prediction is used to compute the final state. Once an update is received, reconciliation code kicks in and corrects any mismatches.In offline mode, the same code used for the prediction is used for driving the entity's state instead, and no input is forwarded to
CoherenceInput
.
Last updated