Table of Contents

Class CharacterPositionHistory

Namespace
FishMMO.Shared
Assembly
FishMMO.Shared.dll

Server-side ring buffer of where a character's collider was on each recent tick.

public class CharacterPositionHistory : NetworkBehaviour
Inheritance
Object
Component
Behaviour
MonoBehaviour
NetworkBehaviour
CharacterPositionHistory
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.CreateReconcile()
NetworkBehaviour.Reconcile_Reader<T>(PooledReader, ref T)
NetworkBehaviour.OnStartServerCalled
NetworkBehaviour.OnStartClientCalled
NetworkBehaviour.WritePayload(NetworkConnection, Writer)
NetworkBehaviour.ReadPayload(NetworkConnection, Reader)
NetworkBehaviour.OnStartNetwork()
NetworkBehaviour.OnStopNetwork()
NetworkBehaviour.OnOwnershipServer(NetworkConnection)
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

Why this exists. Hits resolve on the server against current positions, while a client aims at peers it renders behind the server by its interpolation buffer plus its own latency. The gap is the peer's speed times that staleness — measured at 0.64 m for a 40 ms connection and 2.2 m at 300 ms — against ability hitboxes authored at half a metre. No amount of tuning closes that. The server has to be able to ask "where was this character when the shooter saw it", and this is what lets it.

Server only, by construction. Recording starts in OnStartServer() and the tick subscription is never taken on a client. Rewinding is a server-side query against authoritative history; it is deliberately not part of the deterministic simulation, so it cannot influence what clients predict and cannot desynchronise them.

Cost. One CharacterPositionHistory.Snapshot per tick per character, in a pre-allocated ring — no per-tick allocation. At the default window that is a fixed 28 bytes times the buffer length per character, held for the character's lifetime.

Properties

Capacity

Capacity of the ring, for diagnostics and tests.

public int Capacity { get; }

Property Value

int

IsRewound

True while this character's collider is displaced by a rewind.

public bool IsRewound { get; }

Property Value

bool

MaximumRewindMilliseconds

Maximum rewind window, in milliseconds.

public float MaximumRewindMilliseconds { get; }

Property Value

float

RecordedTicks

Number of ticks currently held, for diagnostics and tests.

public int RecordedTicks { get; }

Property Value

int

Methods

OnStartServer()

Called on the server after initializing this object. SyncTypes modified before or during this method will be sent to clients in the spawn message.

public override void OnStartServer()

OnStopServer()

Called on the server before deinitializing this object.

public override void OnStopServer()

TryResolve(RewindTarget, out Snapshot)

Resolves where this character was at tick, interpolating between the two recorded ticks that bracket it.

public bool TryResolve(RewindTarget target, out CharacterPositionHistory.Snapshot snapshot)

Parameters

target RewindTarget

The point in the past to resolve.

snapshot CharacterPositionHistory.Snapshot

The resolved transform.

Returns

bool

True when history covers the requested tick.

Remarks

The whole-tick overload below is what actually reads the ring; this blends the two samples the target sits between. A client's view of a peer comes from interpolation and lands between ticks, so resolving only on tick boundaries reproduced a pose it never rendered. With a zero fraction the bounds collapse and this is exactly the whole-tick result.

TryResolve(uint, out Snapshot)

public bool TryResolve(uint tick, out CharacterPositionHistory.Snapshot snapshot)

Parameters

tick uint
snapshot CharacterPositionHistory.Snapshot

Returns

bool