using System; using NitroxClient.MonoBehaviours; using NitroxModel.Networking; using NitroxModel.Packets; using UnityEngine; namespace NitroxClient.GameLogic; public partial class TimeManager { /// /// When first player connects to the server, time will resume when time will be resumed on server-side. /// According to this, we need to freeze time on first player connecting before it has fully loaded. /// private bool freezeTime = true; /// /// Latest moment at which we updated the time /// private DateTimeOffset latestRegistrationTime; /// /// Latest registered value of the time /// private double latestRegisteredTime; /// /// Moment at which real time elapsed was determined /// private DateTimeOffset realTimeElapsedRegistrationTime; /// /// Only registered value of real time elapsed given when connecting. Associated to /// private double realTimeElapsed; public float AuroraRealExplosionTime { get; set; } private const double DEFAULT_REAL_TIME = 0; /// /// Calculates the server's real time elapsed from an offset () and the delta time between /// and the offset's exact (). /// public double RealTimeElapsed { get { // Unitialized state if (realTimeElapsedRegistrationTime == default) { return DEFAULT_REAL_TIME; } if (freezeTime) { return realTimeElapsed; } return (ServerUtcNow() - realTimeElapsedRegistrationTime).TotalMilliseconds * 0.001 + realTimeElapsed; } } private const double DEFAULT_SUBNAUTICA_TIME = 480; /// /// Calculates the server's exact time from an offset () and the delta time between /// and the offset's exact (). /// /// /// This should only be used for DayNigthCycle internal calculations so that we don't use different times during the same frame. /// Use instead to get the current frame's time. /// public double CurrentTime { get { // Unitialized state if (latestRegisteredTime == 0) { return DEFAULT_SUBNAUTICA_TIME; } if (freezeTime) { return latestRegisteredTime; } return (ServerUtcNow() - latestRegistrationTime).TotalMilliseconds * 0.001 + latestRegisteredTime; } } /// /// Real deltaTime between two updates of local time through /// /// /// /// Replaces because it is capped by /// and may not reflect the real time which has passed between two frames once it's higher than the said maximum ///
See Time.maximumDeltaTime ///
/// /// This value is set to 0 when a time skip occurs to avoid undesired behaviours /// (e.g. consuming a day worth of energy just when you skipped 24 in-game hours) /// ///
public float DeltaTime = 0; public TimeManager(NtpSyncer ntpSyncer) { this.ntpSyncer = ntpSyncer; } public void ProcessUpdate(TimeChange packet) { if (freezeTime && Multiplayer.Main && Multiplayer.Main.InitialSyncCompleted) { freezeTime = false; } realTimeElapsedRegistrationTime = DateTimeOffset.FromUnixTimeMilliseconds(packet.UpdateTime); realTimeElapsed = packet.RealTimeElapsed; latestRegistrationTime = DateTimeOffset.FromUnixTimeMilliseconds(packet.UpdateTime); latestRegisteredTime = packet.CurrentTime; // No need to re-initialize the fields with the same data if (!serverOnlineMode) { SetServerCorrectionData(packet.OnlineMode, packet.UtcCorrectionTicks); } // If the server is in online mode, the server should try to get to online mode too if (!clientOnlineMode && serverOnlineMode) { AttemptNtpSync(); } // We don't want to have a big DeltaTime when processing a time skip so we calculate it beforehands float deltaTimeBefore = DeltaTime; DayNightCycle.main.timePassedAsDouble = CalculateCurrentTime(); DeltaTime = deltaTimeBefore; DayNightCycle.main.StopSkipTimeMode(); } /// /// Sets accordingly /// /// The newly calculated time from public double CalculateCurrentTime() { double currentTime = CurrentTime; DeltaTime = (float)(currentTime - DayNightCycle.main.timePassedAsDouble); // DeltaTime = 0 might end up causing a divide by 0 => NaN in some scripts if (DeltaTime == 0f) { DeltaTime = 0.00001f; } return currentTime; } public void InitRealTimeElapsed(double realTimeElapsed, long registrationTime, bool isFirstPlayer) { this.realTimeElapsed = realTimeElapsed; realTimeElapsedRegistrationTime = DateTimeOffset.FromUnixTimeMilliseconds(registrationTime); freezeTime = isFirstPlayer; } }