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; } /// /// 与 PC CECGameRun::CreateWorld / CECWorld::InitNatureObjects 末尾一致:按当前服务器钟面刷新昼夜相位 // Match PC after world load / nature init /// 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; // C++ formula: nTimeInDay / (4f*3600f) — drives 4h sun/moon animation cycle (matches EC_Game.cpp SetServerTime) float phase4h = nTimeInDay / (4f * 3600f); // Real 24h phase: maps server time directly to [0,1) — used for nightControl shader (noon=day, midnight=night) float phase24h = nTimeInDay / (24f * 3600f); SetTimeOfTheDayFull(phase4h, phase24h); BMLogger.Log($"[Cuong] SyncSunMoon server-local {serverLocalUtc.Hour:D2}:{serverLocalUtc.Minute:D2}:{serverLocalUtc.Second:D2}, phase4h={phase4h:F3} phase24h={phase24h:F3}"); } /// /// 将昼夜相位写入 SunMoon(与 PC GetWorld()->GetSunMoon()->SetTimeOfTheDay 用法一致) // Push day/night phase to SunMoon (same role as PC) /// 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}"); } static void SetTimeOfTheDayFull(float phase4h, float phase24h) { var sunMoon = CECSunMoon.Instance; if (sunMoon == null) { BMLogger.LogWarning("[Cuong] EC_Game.SetTimeOfTheDayFull: CECSunMoon.Instance is null."); return; } sunMoon.SetTimeOfTheDayFull(phase4h, phase24h); BMLogger.Log($"[Cuong] EC_Game.SetTimeOfTheDayFull phase4h={phase4h:F3} phase24h={phase24h:F3}, m_vTimeOfTheDay={sunMoon.m_vTimeOfTheDay:F3} m_vRealPhase={sunMoon.m_vRealPhase:F3}"); } // 设置时间误差 // 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; } } }