using FishNet.Managing; using FishNet.Managing.Timing; using FishNet.Serializing; using FishNet.Transporting; using System.Runtime.CompilerServices; using UnityEngine; namespace FishNet.Object.Synchronizing.Internal { public class SyncBase : ISyncType { #region Public. /// /// True if this SyncBase has been registered within it's containing class. /// public bool IsRegistered { get; private set; } /// /// True if a SyncObject, false if a SyncVar. /// public bool IsSyncObject { get; private set; } /// /// The settings for this SyncVar. /// public Settings Settings = new Settings(); /// /// How often updates may send. /// public float SendTickRate => Settings.SendTickRate; /// /// True if this SyncVar needs to send data. /// public bool IsDirty { get; private set; } /// /// NetworkManager this uses. /// public NetworkManager NetworkManager = null; /// /// NetworkBehaviour this SyncVar belongs to. /// public NetworkBehaviour NetworkBehaviour = null; /// /// Next time a SyncVar may send data/ /// public uint NextSyncTick = 0; /// /// Index within the sync collection. /// public uint SyncIndex { get; protected set; } = 0; /// /// Channel to send on. /// internal Channel Channel => _currentChannel; #endregion #region Private. /// /// Sync interval converted to ticks. /// private uint _timeToTicks; /// /// Channel to use for next write. To ensure eventual consistency this eventually changes to reliable when Settings are unreliable. /// private Channel _currentChannel; #endregion /// /// Initializes this SyncBase. /// public void InitializeInstance(NetworkBehaviour nb, uint syncIndex, WritePermission writePermissions, ReadPermission readPermissions, float tickRate, Channel channel, bool isSyncObject) { NetworkBehaviour = nb; SyncIndex = syncIndex; _currentChannel = channel; IsSyncObject = isSyncObject; Settings = new Settings() { WritePermission = writePermissions, ReadPermission = readPermissions, SendTickRate = tickRate, Channel = channel }; NetworkBehaviour.RegisterSyncType(this, SyncIndex); } /// /// Sets the SyncIndex. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetRegistered() { Registered(); } /// /// Called when the SyncType has been registered, but not yet initialized over the network. /// protected virtual void Registered() { IsRegistered = true; } /// /// PreInitializes this for use with the network. /// public void PreInitialize(NetworkManager networkManager) { NetworkManager = networkManager; _timeToTicks = NetworkManager.TimeManager.TimeToTicks(Settings.SendTickRate, TickRounding.RoundUp); } /// /// Called after OnStartXXXX has occurred. /// /// True if OnStartServer was called, false if OnStartClient. protected internal virtual void OnStartCallback(bool asServer) { } /// /// Dirties this Sync and the NetworkBehaviour. /// public bool Dirty() { /* Reset channel even if already dirty. * This is because the value might have changed * which will reset the eventual consistency state. */ _currentChannel = Settings.Channel; /* Once dirty don't undirty until it's * processed. This ensures that data * is flushed. */ bool canDirty = NetworkBehaviour.DirtySyncType(IsSyncObject); IsDirty |= canDirty; return canDirty; } /// /// Sets IsDirty to false. /// internal void ResetDirty() { //If not a sync object and using unreliable channel. if (!IsSyncObject && Settings.Channel == Channel.Unreliable) { //Check if dirty can be unset or if another tick must be run using reliable. if (_currentChannel == Channel.Unreliable) _currentChannel = Channel.Reliable; //Already sent reliable, can undirty. Channel will reset next time this dirties. else IsDirty = false; } //If syncObject or using reliable unset dirty. else { IsDirty = false; } } /// /// True if dirty and enough time has passed to write changes. /// /// /// internal bool WriteTimeMet(uint tick) { return (IsDirty && tick >= NextSyncTick); } /// /// Writes current value. /// /// /// True to set the next time data may sync. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void WriteDelta(PooledWriter writer, bool resetSyncTick = true) { WriteHeader(writer, resetSyncTick); } /// /// Writers the header for this SyncType. /// /// /// protected virtual void WriteHeader(PooledWriter writer, bool resetSyncTick = true) { if (resetSyncTick) NextSyncTick = NetworkManager.TimeManager.Tick + _timeToTicks; writer.WriteByte((byte)SyncIndex); } /// /// Writes current value if not initialized value. /// /// public virtual void WriteFull(PooledWriter writer) { } /// /// Sets current value. /// /// public virtual void Read(PooledReader reader) { } /// /// Resets to initialized values. /// public virtual void Reset() { NextSyncTick = 0; ResetDirty(); } } }