Files
test/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs
T
2026-05-13 10:15:29 +07:00

118 lines
5.2 KiB
C#

using UnityEngine;
using System;
using BrewMonster.Scripts;
//TODO: [DUCK] EC_Game shouldn't be in BrewMonster.Network namespace, it should be in BrewMonster.Scripts namespace.
namespace BrewMonster.Network
{
public partial class EC_Game
{
private static uint m_AbsTickStart;
private static int m_AbsTimeStart;
private static int m_iTimeError; // 服务器与本机时间差(秒) // Time error in seconds
private static int m_iTimeZoneBias; // 服务器时区偏移(秒) // Server timezone bias in seconds
private static bool m_bServerTimeInited;
private static float m_dwTickTime; // Logic time of current tick
private static float m_dwRealTickTime; // Real tick time
public static int GetTimeZoneBias() { return m_iTimeZoneBias; }
/// <summary>
/// 与 PC CECGameRun::CreateWorld / CECWorld::InitNatureObjects 末尾一致:按当前服务器钟面刷新昼夜相位 // Match PC after world load / nature init
/// </summary>
public static void SyncSunMoonTimeOfDayFromServerClock()
{
int serverGmt = GetServerGMTTime();
ApplySunMoonPhaseFromServerGmtUnix(serverGmt);
}
static void ApplySunMoonPhaseFromServerGmtUnix(int serverGmtUnixSeconds)
{
long shiftedUnix = (long)serverGmtUnixSeconds - (long)m_iTimeZoneBias * 60L;
if (shiftedUnix < 0L)
shiftedUnix = 0L;
var serverLocalUtc = DateTimeOffset.FromUnixTimeSeconds(shiftedUnix).UtcDateTime;
int nTimeInDay = serverLocalUtc.Hour * 3600 + serverLocalUtc.Minute * 60 + serverLocalUtc.Second;
float phase = nTimeInDay / (4f * 3600f);
SetTimeOfTheDay(phase);
BMLogger.Log($"[Cuong] SyncSunMoon server-local {serverLocalUtc.Hour:D2}:{serverLocalUtc.Minute:D2}:{serverLocalUtc.Second:D2}, phase={phase}");
}
/// <summary>
/// 将昼夜相位写入 SunMoon(与 PC GetWorld()->GetSunMoon()->SetTimeOfTheDay 用法一致) // Push day/night phase to SunMoon (same role as PC)
/// </summary>
public static void SetTimeOfTheDay(float vTime)
{
var sunMoon = CECSunMoon.Instance;
if (sunMoon == null)
{
BMLogger.LogWarning("[Cuong] EC_Game.SetTimeOfTheDay: CECSunMoon.Instance is null.");
return;
}
sunMoon.SetTimeOfTheDay(vTime);
BMLogger.Log($"[Cuong] EC_Game.SetTimeOfTheDay vTime(in)={vTime}, m_vTimeOfTheDay={sunMoon.m_vTimeOfTheDay}");
}
// 设置时间误差 // Set time error
public static void SetServerTime(int iSevTime, int iTimeZoneBias)
{
BMLogger.Log($"[Cuong] SetServerTime iSevTime={iSevTime}, iTimeZoneBias={iTimeZoneBias}");
int nowUnix = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
m_iTimeError = iSevTime - nowUnix; // 记录与本机的时间差 // store delta with local
m_iTimeZoneBias = iTimeZoneBias; // 记录服务器时区偏移 // store server timezone bias
ApplySunMoonPhaseFromServerGmtUnix(iSevTime);
// 防沉迷时长修正 // Anti-wallow playtime adjust
// S2C::player_wallow_info wallowinfo = GetGameRun()->GetWallowInfo();
// if (wallowinfo.anti_wallow_active)
// {
// wallowinfo.play_time += m_iTimeError - iOldTimeError;
// GetGameRun()->SetWallowInfo(wallowinfo);
// }
// 初始化绝对时间参考点 // Initialize absolute time reference
m_AbsTimeStart = iSevTime;
m_AbsTickStart = (uint)(Time.realtimeSinceStartup * 1000.0f);
m_bServerTimeInited = true;
BMLogger.Log($"[Cuong] SetServerTime TickStart (ms) = {m_AbsTickStart}");
}
public static int GetServerAbsTime()
{
// Fallback: if server time was never initialized (SetServerTime not called),
// return local unix time seconds so task timestamps (usually epoch seconds) still work.
// This makes wait-time/countdown and timetable logic behave correctly even before server sync.
if (!m_bServerTimeInited || m_AbsTimeStart == 0)
{
return (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds() + m_iTimeError;
}
uint curTick = (uint)(Time.realtimeSinceStartup * 1000.0f);
if (curTick < m_AbsTickStart)
{
// if player run this game more than 49.71 days...
uint sec = (((uint)~0u - m_AbsTickStart + 1u) + curTick) / 1000u;
m_AbsTickStart = curTick;
m_AbsTimeStart += (int)sec;
return m_AbsTimeStart;
}
else
{
uint sec = (curTick - m_AbsTickStart) / 1000u;
return m_AbsTimeStart + (int)sec;
}
}
// Get real tick time of current frame
public static float GetRealTickTime()
{
return (uint)(Time.deltaTime * 1000f);
return Mathf.Abs(m_dwRealTickTime);
// return Time.realtimeSinceStartup;
}
}
}