State Handling
STATE is the single source of truth for your simulation. PurrDiction records, reconciles, and interpolates states so clients stay responsive while remaining consistent with server authority.
Requirements
STATEmust be a struct implementingIPredictedData<STATE>(which extendsIMath<STATE>andIPackedAuto).Provide deterministic math on your state via
IMath<T>methods (the default linear interpolation usesAdd,Scale,Negate).
What Goes in STATE
Simulation‑critical data only: positions, rotations, velocities, timers, flags; anything that affects future ticks.
Do not store transient view data; compute those in
UpdateView.
Lifecycle and Reconciliation
Simulation loop writes
currentStateeach tick.PurrDiction saves snapshots and reconciles against server frames as they arrive.
On rollback:
ReadStateloads the verified snapshot.Rollback(tick)applies it and callsSetUnityState(state)for external components.UpdateRollbackInterpolationState(delta, accumulateError)adjusts view smoothing.
Unity bridging:
protected override void GetUnityState(ref STATE state)— Read Unity → STATE when needed.protected override void SetUnityState(STATE state)— Write STATE → Unity on rollback.
View vs Verified
viewStateis the smoothed state to render this frame.verifiedStateexposes the most recent authoritative snapshot, when present.Override
UpdateView(STATE viewState, STATE? verified)to drive visuals.Call
ResetInterpolation()to clear accumulated error (e.g., teleports).
Example: Minimal STATE
public struct MyState : IPredictedData<MyState>
{
public Vector3 pos; public Quaternion rot;
public void Dispose() {}
// IMath<MyState> default ops come from packer codegen; override Interpolate if non-linear
}
public class Mover : PredictedIdentity<MyState>
{
protected override MyState GetInitialState() => new MyState { pos = transform.position, rot = transform.rotation };
protected override void GetUnityState(ref MyState s) { s.pos = transform.position; s.rot = transform.rotation; }
protected override void SetUnityState(MyState s) { transform.SetPositionAndRotation(s.pos, s.rot); }
protected override void Simulate(ref MyState s, float dt) { /* mutate s deterministically */ }
protected override void UpdateView(MyState view, MyState? verified) { transform.SetPositionAndRotation(view.pos, view.rot); }
}Last updated