Best Practices
Use Structs for INPUT
and STATE
Define
INPUT
andSTATE
as structs in C#, not classes.Structs are value types, which ensures predictable behavior during prediction and reconciliation.
Example:
Why?
Structs are copied by value, making them ideal for storing snapshot data that needs to be reconciled.
Avoids unintended side effects that can occur with reference types (classes).
2. Initialize State with GetInitialState
Use the
protected override STATE GetInitialState()
method to define the default values for yourSTATE
struct.This method is called when the entity is first created, ensuring that it starts with a valid initial state.
Example:
Why?
Ensures that your entity starts with a consistent and predictable state.
Avoids undefined behavior caused by uninitialized state variables.
3. Treat STATE
as the Source of Truth
Any data that affects the simulation should be part of the
STATE
struct.Use
STATE
to store:Entity position, rotation, and velocity.
Flags or variables that control behavior (e.g.,
isJumping
,isShooting
).
Avoid modifying Unity components directly (e.g.,
Transform.position
) without synchronizing them with theSTATE
.
Why?
The
STATE
struct is reconciled by the CSP system, ensuring consistency between the client and server.Directly modifying Unity components can lead to desynchronization and unpredictable behavior.
4. Use GetUnityState
and SetUnityState
for External Components
If your
STATE
affects Unity components (e.g.,Transform
,Rigidbody
), use these overrides to synchronize them:protected override void GetUnityState(ref STATE state)
:Updates the
STATE
struct with data from Unity components (e.g., reading theTransform.position
).
protected override void SetUnityState(STATE state)
:Applies the
STATE
to Unity components (e.g., setting theTransform.position
).
Example:
Why?
These methods ensure that Unity components are properly synchronized with the
STATE
, maintaining consistency during prediction and reconciliation.
5. Make SerializeField
Constants Only
Use
SerializeField
only for constant values that do not change during simulation (e.g., speed, prefab references).Avoid using
SerializeField
for variables that are part of the simulation logic (e.g., position, velocity).
Why?
SerializeField
variables are not reconciled by the CSP system, so changing them during simulation can lead to desynchronization.
6. Keep Simulation Logic Deterministic
Ensure that all simulation logic (e.g., movement, physics) is deterministic and based on the
STATE
orINPUT
.
Why?
Deterministic logic ensures that the client and server produce the same results, even when running at different times or frame rates.
Summary of Best Practices
Practice
Why It Matters
Use structs for INPUT
and STATE
Ensures predictable behavior and avoids side effects of reference types.
Use GetInitialState
for defaults
Provides a consistent starting state for entities.
Treat STATE
as the source of truth
Prevents desynchronization and maintains consistency between client and server.
Use GetUnityState
and SetUnityState
Properly synchronizes Unity components with the STATE
.
Make SerializeField
constants only
Avoids desynchronization caused by unreconciled changes.
Last updated