#if FISHNET_THREADED_TICKSMOOTHERS using FishNet.Managing.Timing; using FishNet.Object; using GameKit.Dependencies.Utilities; using UnityEngine; using Unity.Profiling; namespace FishNet.Component.Transforming.Beta { /// /// Smoothes this object between ticks. /// /// This can be configured to smooth over a set interval of time, or to smooth adaptively and make path corrections for prediction. public class TickSmootherController : IResettable { #region Public. // /// // /// Logic for owner smoothing. // /// // public UniversalTickSmoother UniversalSmoother { get; private set; } #endregion #region Private. #region Private Profiler Markers private static readonly ProfilerMarker _pm_OnUpdate = new("TickSmootherController.TimeManager_OnUpdate()"); private static readonly ProfilerMarker _pm_OnPreTick = new("TickSmootherController.TimeManager_OnPreTick()"); private static readonly ProfilerMarker _pm_OnPostTick = new("TickSmootherController.TimeManager_OnPostTick()"); #endregion /// /// private InitializationSettings _initializationSettings = new(); /// /// private MovementSettings _ownerMovementSettings = new(); /// /// private MovementSettings _spectatorMovementSettings = new(); /// /// True if OnDestroy has been called. /// private bool _destroyed; /// /// Cached timeManager reference. /// private TimeManager _timeManager; /// /// NetworkBehaviour which initialized this object. Value may be null when initialized for an Offline smoother. /// private NetworkBehaviour _initializingNetworkBehaviour; /// /// TickSmoothingManager. /// private TickSmoothingManager _tickSmoothingManager; /// /// Transform which initialized this object. /// private Transform _graphicalTransform; /// /// True if initialized with a null NetworkBehaviour. /// private bool _initializedOffline; /// /// True if subscribed to events used for adaptiveInterpolation. /// private bool _subscribedToAdaptiveEvents; /// /// True if currently subscribed to events. /// private bool _subscribed; /// /// True if initialized. /// private bool _isInitialized; #endregion public void Initialize(InitializationSettings initializationSettings, MovementSettings ownerSettings, MovementSettings spectatorSettings) { _tickSmoothingManager = initializationSettings.InitializingNetworkBehaviour?.NetworkManager.TickSmoothingManager ?? InstanceFinder.NetworkManager.TickSmoothingManager; _initializingNetworkBehaviour = initializationSettings.InitializingNetworkBehaviour; _graphicalTransform = initializationSettings.GraphicalTransform; _initializationSettings = initializationSettings; _ownerMovementSettings = ownerSettings; _spectatorMovementSettings = spectatorSettings; _initializedOffline = initializationSettings.InitializingNetworkBehaviour == null; _isInitialized = true; } public void OnDestroy() { TickSmoothingManager tsm = _tickSmoothingManager; if (tsm != null) tsm.Unregister(this); // ChangeSubscriptions(false); // StoreSmoother(); _destroyed = true; _isInitialized = false; } public void StartSmoother() { if (!_isInitialized) return; bool canStart = _initializedOffline ? StartOffline() : StartOnline(); if (!canStart) return; // RetrieveSmoothers(); // // UniversalSmoother.Initialize(_initializationSettings, _ownerMovementSettings, _spectatorMovementSettings); // // UniversalSmoother.StartSmoother(); TickSmoothingManager tsm = _tickSmoothingManager; if (tsm != null) tsm.Register(this, _initializationSettings, _ownerMovementSettings, _spectatorMovementSettings); bool StartOnline() { NetworkBehaviour nb = _initializingNetworkBehaviour; SetTimeManager(nb.TimeManager); return true; } bool StartOffline() { if (_timeManager == null) return false; return true; } } public void StopSmoother() { TickSmoothingManager tsm = _tickSmoothingManager; if (tsm != null) tsm.Unregister(this); if (!_initializedOffline) StopOnline(); // if (UniversalSmoother != null) // UniversalSmoother.StopSmoother(); void StopOnline() { SetTimeManager(tm: null); } // Intentionally left blank. // void StopOffline() { } } // public void TimeManager_OnUpdate() // { // using (_pm_OnUpdate.Auto()) // { // UniversalSmoother.OnUpdate(Time.deltaTime); // } // } // // public void TimeManager_OnPreTick() // { // using (_pm_OnPreTick.Auto()) // { // UniversalSmoother.OnPreTick(); // } // } // // /// // /// Called after a tick completes. // /// // public void TimeManager_OnPostTick() // { // using (_pm_OnPostTick.Auto()) // { // if (_timeManager != null) // UniversalSmoother.OnPostTick(_timeManager.LocalTick); // } // } // // private void PredictionManager_OnPostReplicateReplay(uint clientTick, uint serverTick) // { // UniversalSmoother.OnPostReplicateReplay(clientTick); // } // // private void TimeManager_OnRoundTripTimeUpdated(long rttMs) // { // UniversalSmoother.UpdateRealtimeInterpolation(); // } // // /// // /// Stores smoothers if they have value. // /// // private void StoreSmoother() // { // if (UniversalSmoother == null) // return; // // ResettableObjectCaches.Store(UniversalSmoother); // UniversalSmoother = null; // } // // /// // /// Stores current smoothers and retrieves new ones. // /// // private void RetrieveSmoothers() // { // StoreSmoother(); // UniversalSmoother = ResettableObjectCaches.Retrieve(); // } // /// // /// Sets a target transform to follow. // /// // public void SetTargetTransform(Transform value) // { // Transform currentTargetTransform = _initializationSettings.TargetTransform; // // if (value == currentTargetTransform) // return; // // bool clientStartCalled = (_initializedOffline && _timeManager != null) || (_initializingNetworkBehaviour != null && _initializingNetworkBehaviour.OnStartClientCalled); // // bool previousTargetTransformIsValid = (currentTargetTransform != null); // // // If target is different and old is not null then reset. // if (previousTargetTransformIsValid && clientStartCalled) // OnStopClient(); // // _initializationSettings.TargetTransform = value; // if (previousTargetTransformIsValid && clientStartCalled) // OnStartClient(); // } /// /// Sets a new PredictionManager to use. /// public void SetTimeManager(TimeManager tm) { if (tm == _timeManager) return; // Unsub from current. // ChangeSubscriptions(false); //Sub to newest. _timeManager = tm; // ChangeSubscriptions(true); } // /// // /// Changes the subscription to the TimeManager. // /// // private void ChangeSubscriptions(bool subscribe) // { // if (_destroyed) // return; // TimeManager tm = _timeManager; // if (tm == null) // return; // // if (subscribe == _subscribed) // return; // _subscribed = subscribe; // // bool adaptiveIsOff = _ownerMovementSettings.AdaptiveInterpolationValue == AdaptiveInterpolationType.Off && _spectatorMovementSettings.AdaptiveInterpolationValue == AdaptiveInterpolationType.Off; // // if (subscribe) // { // tm.OnUpdate += TimeManager_OnUpdate; // tm.OnPreTick += TimeManager_OnPreTick; // tm.OnPostTick += TimeManager_OnPostTick; // // if (!adaptiveIsOff) // { // tm.OnRoundTripTimeUpdated += TimeManager_OnRoundTripTimeUpdated; // PredictionManager pm = tm.NetworkManager.PredictionManager; // pm.OnPostReplicateReplay += PredictionManager_OnPostReplicateReplay; // _subscribedToAdaptiveEvents = true; // } // } // else // { // tm.OnUpdate -= TimeManager_OnUpdate; // tm.OnPreTick -= TimeManager_OnPreTick; // tm.OnPostTick -= TimeManager_OnPostTick; // // if (_subscribedToAdaptiveEvents) // { // tm.OnRoundTripTimeUpdated -= TimeManager_OnRoundTripTimeUpdated; // PredictionManager pm = tm.NetworkManager.PredictionManager; // pm.OnPostReplicateReplay -= PredictionManager_OnPostReplicateReplay; // } // } // } public void ResetState() { _initializationSettings = default; _ownerMovementSettings = default; _spectatorMovementSettings = default; _destroyed = false; _timeManager = null; _initializingNetworkBehaviour = null; _graphicalTransform = null; _subscribed = false; _subscribedToAdaptiveEvents = false; _isInitialized = false; } public void InitializeState() { } } } #endif