Table of Contents

Class CharacterPredictionController

Namespace
FishMMO.Shared
Assembly
FishMMO.Shared.dll

Unified prediction controller that replaces per-subsystem [Replicate]/[Reconcile]. Discovers all IPredictableController components on the same GameObject, sorts them by Order, and drives them through a single FishNet Prediction V2 pipeline. This avoids the issues caused by having multiple predicted NetworkBehaviours on the same NetworkObject.

public class CharacterPredictionController : NetworkBehaviour
Inheritance
Object
Component
Behaviour
MonoBehaviour
NetworkBehaviour
CharacterPredictionController
Inherited Members
NetworkBehaviour.IsSpawned
NetworkBehaviour.ComponentIndex
NetworkBehaviour.NetworkObject
NetworkBehaviour.MAXIMUM_NETWORKBEHAVIOURS
NetworkBehaviour.UNSET_NETWORKBEHAVIOUR_ID
NetworkBehaviour.ToString()
NetworkBehaviour.Reset()
NetworkBehaviour.OnValidate()
NetworkBehaviour.IsBehaviourReconciling
NetworkBehaviour.ClearReplicateCache()
NetworkBehaviour.Reconcile_Reader<T>(PooledReader, ref T)
NetworkBehaviour.OnStartServerCalled
NetworkBehaviour.OnStartClientCalled
NetworkBehaviour.WritePayload(NetworkConnection, Writer)
NetworkBehaviour.ReadPayload(NetworkConnection, Reader)
NetworkBehaviour.OnSpawnServer(NetworkConnection)
NetworkBehaviour.OnDespawnServer(NetworkConnection)
NetworkBehaviour.OnStartClient()
NetworkBehaviour.OnStopClient()
NetworkBehaviour.OnOwnershipClient(NetworkConnection)
NetworkBehaviour.ClearBuffedRpcs()
NetworkBehaviour.ExcludeOwnerFromUnbufferedObserversRpcs
NetworkBehaviour.IsClientOnly
NetworkBehaviour.IsServerOnly
NetworkBehaviour.IsHost
NetworkBehaviour.IsClient
NetworkBehaviour.IsServer
NetworkBehaviour.IsDeinitializing
NetworkBehaviour.NetworkManager
NetworkBehaviour.ServerManager
NetworkBehaviour.ClientManager
NetworkBehaviour.ObserverManager
NetworkBehaviour.TransportManager
NetworkBehaviour.TimeManager
NetworkBehaviour.SceneManager
NetworkBehaviour.PredictionManager
NetworkBehaviour.RollbackManager
NetworkBehaviour.NetworkObserver
NetworkBehaviour.IsClientInitialized
NetworkBehaviour.IsClientStarted
NetworkBehaviour.IsClientOnlyInitialized
NetworkBehaviour.IsClientOnlyStarted
NetworkBehaviour.IsServerInitialized
NetworkBehaviour.IsServerStarted
NetworkBehaviour.IsServerOnlyInitialized
NetworkBehaviour.IsServerOnlyStarted
NetworkBehaviour.IsHostInitialized
NetworkBehaviour.IsHostStarted
NetworkBehaviour.IsOffline
NetworkBehaviour.IsNetworked
NetworkBehaviour.GetIsNetworked()
NetworkBehaviour.IsManagerReconciling
NetworkBehaviour.Observers
NetworkBehaviour.IsOwner
NetworkBehaviour.IsController
NetworkBehaviour.HasAuthority
NetworkBehaviour.Owner
NetworkBehaviour.OwnerId
NetworkBehaviour.ObjectId
NetworkBehaviour.LocalConnection
NetworkBehaviour.OwnerMatches(NetworkConnection)
NetworkBehaviour.Despawn(GameObject, DespawnType?)
NetworkBehaviour.Despawn(NetworkObject, DespawnType?)
NetworkBehaviour.Despawn(DespawnType?)
NetworkBehaviour.Spawn(GameObject, NetworkConnection, Scene)
NetworkBehaviour.Spawn(NetworkObject, NetworkConnection, Scene)
NetworkBehaviour.RemoveOwnership()
NetworkBehaviour.GiveOwnership(NetworkConnection)
NetworkBehaviour.GetInstance<T>()
NetworkBehaviour.TryRegisterInstance<T>(T)
NetworkBehaviour.UnregisterInstance<T>()
NetworkBehaviour.CanLog(LoggingType)
MonoBehaviour.IsInvoking()
MonoBehaviour.CancelInvoke()
MonoBehaviour.StopCoroutine(Coroutine)
MonoBehaviour.StopAllCoroutines()
MonoBehaviour.destroyCancellationToken
MonoBehaviour.useGUILayout
MonoBehaviour.didStart
MonoBehaviour.didAwake
MonoBehaviour.runInEditMode
Behaviour.enabled
Behaviour.isActiveAndEnabled
Component.GetComponent<T>()
Component.TryGetComponent<T>(out T)
Component.GetComponentInChildren<T>()
Component.GetComponentsInChildren<T>()
Component.GetComponentInParent<T>()
Component.GetComponentsInParent<T>()
Component.GetComponents<T>()
Component.GetComponentIndex()
Component.CompareTag(TagHandle)
Component.transform
Component.transformHandle
Component.gameObject
Component.tag
Object.GetEntityId()
Object.GetInstanceID()
Object.GetHashCode()
Object.InstantiateAsync<T>(T)
Object.InstantiateAsync<T>(T, Transform)
Object.InstantiateAsync<T>(T, Vector3, Quaternion)
Object.InstantiateAsync<T>(T, Transform, Vector3, Quaternion)
Object.Instantiate(Object, Vector3, Quaternion)
Object.Instantiate(Object, Vector3, Quaternion, Transform)
Object.Instantiate(Object)
Object.Instantiate(Object, Scene)
Object.Instantiate<T>(T, InstantiateParameters)
Object.Instantiate<T>(T, Vector3, Quaternion, InstantiateParameters)
Object.Instantiate(Object, Transform)
Object.Instantiate<T>(T)
Object.Instantiate<T>(T, Vector3, Quaternion)
Object.Instantiate<T>(T, Vector3, Quaternion, Transform)
Object.Instantiate<T>(T, Transform)
Object.Destroy(Object)
Object.DestroyImmediate(Object)
Object.DontDestroyOnLoad(Object)
Object.DestroyObject(Object)
Object.FindObjectsOfType<T>()
Object.FindObjectsByType<T>(FindObjectsSortMode)
Object.FindObjectsByType<T>(FindObjectsInactive, FindObjectsSortMode)
Object.FindObjectOfType<T>()
Object.FindFirstObjectByType<T>()
Object.FindAnyObjectByType<T>()
Object.FindFirstObjectByType<T>(FindObjectsInactive)
Object.FindAnyObjectByType<T>(FindObjectsInactive)
Object.FindObjectsByType<T>()
Object.FindObjectsByType<T>(FindObjectsInactive)
Object.name
Object.hideFlags

Remarks

Dynamic components: The sorted IPredictableController array is built once in Awake. Components added after Awake completes will not participate in the prediction pipeline. All IPredictableController implementations must be attached to the GameObject before the scene loads.

Properties

CurrentLocalTickSnapshot

Snapshot of the current LocalTick (TimeManager.LocalTick) captured at the start of the FishMMO.Shared.CharacterPredictionController.TimeManager_OnTick() pipeline. This is the raw local authoritative tick observed at the TimeManager level — it is NOT a replicate-domain tick. Consumers that require a replicate-domain tick must translate this value via the appropriate controller helpers (e.g., ResolveAuthoritativeTick on target controllers). Used by external consumers (e.g., AbilityObject) to avoid subscription-order drift between tick callbacks.

public uint CurrentLocalTickSnapshot { get; }

Property Value

uint

CurrentReplicateTickSnapshot

Snapshot of the replicate input tick captured at the start of the current Replicate(CharacterReplicateData, ReplicateState, Channel) pass. Controllers that receive callbacks before their own ordered OnReplicate has run can use this as the current replicate-domain reference instead of projecting elapsed raw LocalTick time into prediction state.

public uint CurrentReplicateTickSnapshot { get; }

Property Value

uint

CurrentViewOffsetFraction

The sub-tick remainder of CurrentViewOffsetTicks, in 1/256ths of a tick.

public byte CurrentViewOffsetFraction { get; }

Property Value

byte

CurrentViewOffsetTicks

The view offset carried by the most recent replicate input — how many ticks behind server-present the owning client was rendering its peers.

public byte CurrentViewOffsetTicks { get; }

Property Value

byte

Remarks

Read by LagCompensationTick to decide how far to rewind a hit query. Cached from the replicate rather than read off a live controller for the usual reason: the value has to be the one that belongs to the tick being simulated, including during a replay. Zero for a server-driven character, which compensates nothing.

Latched from real input only — see CaptureViewOffset(CharacterReplicateData, ReplicateState). This is not the value from the most recent invocation of the replicate body, because plenty of those carry no input at all.

HasInputAuthority

True when this peer is the one responsible for producing this character's replicate input for the current tick. AI characters answer "the server"; everyone else answers "the owning client".

public bool HasInputAuthority { get; }

Property Value

bool

PendingReplicateTickSnapshot

Best available replicate-domain tick for the upcoming Replicate(CharacterReplicateData, ReplicateState, Channel) pass, captured during FishNet.Managing.Timing.TimeManager.OnPreTick before arbitrary FishNet.Managing.Timing.TimeManager.OnTick subscribers can run. This closes the window where ability objects or region callbacks execute before this controller's own FishMMO.Shared.CharacterPredictionController.TimeManager_OnTick() subscription and would otherwise observe the previous tick's CurrentReplicateTickSnapshot.

public uint PendingReplicateTickSnapshot { get; }

Property Value

uint

Methods

ApplyObserverTransportMode()

Stops the NetworkTransform duplicating position when prediction already carries it.

public void ApplyObserverTransportMode()

Remarks

A forwarded object's observers simulate it: they receive the owner's replicate input and the server's reconcile, and run the same motor. The NetworkTransform on top of that is the same position a second time, on its own channel, and the two writers also fight over the transform on the observing client.

Only when prediction genuinely moves this character. That means a KCCPlayer, which is the only thing that fills CharacterReconcileData.MotorState. NPCs run the same prediction pipeline for their abilities, buffs and attributes but are moved by a NavMeshAgent, so their MotorState is default every tick and the NetworkTransform is the only thing that moves them anywhere. Silencing it for an NPC because forwarding happened to be on would freeze it for every observer while it carried on fighting.

Position and rotation are switched rather than the component disabled, because NetworkTransform.enabled does not stop it: it sends from a TimeManager subscription taken in OnStartNetwork and receives through an ObserversRpc, and neither consults enabled. Scale is left alone — prediction does not carry it.

Server side only. The server decides what it sends, and a client flipping its own copy would change nothing except what that client itself transmits.

Public because the mode can change at runtime: whatever flips NetworkObject.SetStateForwarding — an arena or tournament handing out precision for the duration of a match — must call this afterwards, or the character keeps the transport it started with.

CreateReconcile()

Creates reconcile data by running all OnCreateReconcile(ref CharacterReconcileData) calls and dispatches via Reconcile(CharacterReconcileData, Channel). Gated on FishNet.Object.NetworkBehaviour.IsServerStarted and FishNet.Object.NetworkBehaviour.IsSpawned to prevent NRE during network startup.

public override void CreateReconcile()

OnOwnershipServer(NetworkConnection)

Drops the latched view offset when this object changes hands.

public override void OnOwnershipServer(NetworkConnection prevOwner)

Parameters

prevOwner NetworkConnection

The connection that owned this object before.

Remarks

The offset describes ONE connection's latency, and CaptureViewOffset(CharacterReplicateData, ReplicateState) holds the last measured value across input gaps on purpose. That makes it stale rather than merely absent when the connection behind it changes, so the two places the connection can change — a new owner, and a pooled object's despawn — clear it rather than letting the next owner inherit the previous one's latency until its first input arrives.

OnStartNetwork()

Subscribes to FishNet.Managing.Timing.TimeManager.OnPreTick and FishNet.Managing.Timing.TimeManager.OnTick events and validates that state forwarding is enabled for observer prediction.

public override void OnStartNetwork()

OnStartServer()

Registers this character for per-observer streaming (density-scaled range and the full-rate observer cap). See ObserverStreamingRegistry.

public override void OnStartServer()

OnStopNetwork()

Unsubscribes from FishNet.Managing.Timing.TimeManager tick events and resets all tick snapshots to unset.

public override void OnStopNetwork()

OnStopServer()

Removes this character from per-observer streaming.

public override void OnStopServer()