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;
}
}