133 lines
6.1 KiB
C#
133 lines
6.1 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;
|
|
// 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}");
|
|
}
|
|
|
|
/// <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}");
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|