|
|
@@ -1,23 +1,21 @@
|
|
|
using System;
|
|
|
using System.Linq;
|
|
|
-
|
|
|
+using Fort23.UTool;
|
|
|
+using UnityEngine;
|
|
|
|
|
|
namespace Fort23.Core
|
|
|
{
|
|
|
public static class TimeHelper
|
|
|
{
|
|
|
public static int refreshHour = 0;
|
|
|
-
|
|
|
public static readonly long epoch = 0;
|
|
|
-
|
|
|
- private static readonly DateTime ServerStartTime = new DateTime(2025, 4, 1, 0, 0, 0, DateTimeKind.Utc); // 服务器开服时间
|
|
|
-
|
|
|
-
|
|
|
+ private static readonly DateTime ServerStartTime = new DateTime(2025, 4, 1, 0, 0, 0, DateTimeKind.Utc);
|
|
|
public static DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
|
|
|
|
|
|
public const long OneDay = 86400000;
|
|
|
public const long Hour = 3600000;
|
|
|
public const long Minute = 60000;
|
|
|
+
|
|
|
private static long _clientFrame;
|
|
|
|
|
|
public static long clientFrame
|
|
|
@@ -25,18 +23,80 @@ namespace Fort23.Core
|
|
|
set => _clientFrame = value;
|
|
|
}
|
|
|
|
|
|
- public static long GetServerStartTime()
|
|
|
- {
|
|
|
- return ((ServerStartTime.Ticks - epoch) / 10000) + (8 * 60 * 60 * 1000);
|
|
|
- }
|
|
|
+
|
|
|
+ // 最近一次校准的网络时间戳毫秒
|
|
|
+ private static long _startNetworkMs = 0;
|
|
|
+
|
|
|
+ // 最近一次校准时的 Unity 时间
|
|
|
+ private static float _lastSyncUnityTime = 0f;
|
|
|
+
|
|
|
+ // 游戏首次启动时间
|
|
|
+ private static float _gameStartTime;
|
|
|
+
|
|
|
+ private const int SyncInterval = 300;
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 用于唯一Id生成,不重复
|
|
|
+ /// 是否获取了网络时间
|
|
|
/// </summary>
|
|
|
- /// <returns></returns>
|
|
|
- public static long ClientNowMicroseconds()
|
|
|
+ public static bool IsNetworkTimeReady { get; private set; } = false;
|
|
|
+
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 必须在游戏启动时调用(异步)
|
|
|
+ /// </summary>
|
|
|
+ public static async CTask InitNetworkTime()
|
|
|
{
|
|
|
- return DateTime.UtcNow.Ticks - epoch;
|
|
|
+ // 启动时的 Unity 时间
|
|
|
+ _gameStartTime = Time.unscaledTime;
|
|
|
+
|
|
|
+ // 首次同步
|
|
|
+ await SyncWithNetwork();
|
|
|
+
|
|
|
+ //每隔五分钟重新同步一次时间
|
|
|
+ TimerComponent.Instance.AddTimer(SyncInterval * 1000, null, Int32.MaxValue, () => { SyncWithNetwork(); });
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 核心:与百度时间同步
|
|
|
+ private static async CTask SyncWithNetwork()
|
|
|
+ {
|
|
|
+ var networkTime = await NetworkTime.GetNetworkTimeAsync();
|
|
|
+ if (networkTime.HasValue)
|
|
|
+ {
|
|
|
+ long networkMs = (long)(networkTime.Value - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc))
|
|
|
+ .TotalMilliseconds;
|
|
|
+
|
|
|
+ if (!IsNetworkTimeReady)
|
|
|
+ {
|
|
|
+ // 首次同步
|
|
|
+ _startNetworkMs = networkMs;
|
|
|
+ _lastSyncUnityTime = Time.unscaledTime;
|
|
|
+ IsNetworkTimeReady = true;
|
|
|
+ LogTool.Log($"首次网络时间同步成功: {networkTime.Value:yyyy-MM-dd HH:mm:ss} UTC");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 定期校准:计算漂移并修正
|
|
|
+ float elapsedUnity = Time.unscaledTime - _lastSyncUnityTime;
|
|
|
+ long expectedMs = _startNetworkMs + (long)(elapsedUnity * 1000);
|
|
|
+ long driftMs = networkMs - expectedMs;
|
|
|
+
|
|
|
+ if (Mathf.Abs((float)driftMs) > 5000) // 漂移 > 5 秒才修正(避免微小误差)
|
|
|
+ {
|
|
|
+ _startNetworkMs = networkMs;
|
|
|
+ _lastSyncUnityTime = Time.unscaledTime;
|
|
|
+ LogTool.Log($"时间校准: 漂移 {driftMs}ms,已修正");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ LogTool.Log($"时间校准: 漂移 {driftMs}ms,正常");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ LogTool.Warning("网络时间校准失败,保持当前时间");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -50,18 +110,37 @@ namespace Fort23.Core
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 客户端时间(毫秒)
|
|
|
+ /// 获取安全的当前时间戳(毫秒)
|
|
|
/// </summary>
|
|
|
- /// <returns></returns>
|
|
|
+ private static long GetSafeNowMs()
|
|
|
+ {
|
|
|
+ if (!IsNetworkTimeReady || _startNetworkMs == 0)
|
|
|
+ return (long)(DateTime.UtcNow.Ticks / 10000); // 回退
|
|
|
+
|
|
|
+ // Unity运行毫秒(完全不受系统时间影响)
|
|
|
+ float elapsedUnity = Time.unscaledTime - _gameStartTime;
|
|
|
+ long elapsedMs = (long)(elapsedUnity * 1000);
|
|
|
+
|
|
|
+
|
|
|
+ return _startNetworkMs + elapsedMs;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public static long GetServerStartTime()
|
|
|
+ {
|
|
|
+ return ((ServerStartTime.Ticks - epoch) / 10000) + (8 * 60 * 60 * 1000);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static long ClientNowMicroseconds()
|
|
|
+ {
|
|
|
+ return GetSafeNowMs() * 1000;
|
|
|
+ }
|
|
|
+
|
|
|
public static long ClientNow()
|
|
|
{
|
|
|
- return ((DateTime.UtcNow.Ticks - epoch) / 10000) + (8 * 60 * 60 * 1000);
|
|
|
+ return GetSafeNowMs() + (8 * 60 * 60 * 1000); // 东八区
|
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// 客户端时间(秒)
|
|
|
- /// </summary>
|
|
|
- /// <returns></returns>
|
|
|
public static long ClientNowSeconds()
|
|
|
{
|
|
|
return ClientNow() / 1000;
|
|
|
@@ -69,38 +148,19 @@ namespace Fort23.Core
|
|
|
|
|
|
public static DateTime DateTimeNow()
|
|
|
{
|
|
|
- return DateTime.Now;
|
|
|
+ return DateTimeOffset.FromUnixTimeMilliseconds(ClientNow()).UtcDateTime;
|
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// 服务器时间(毫秒)
|
|
|
- /// </summary>
|
|
|
- /// <returns></returns>
|
|
|
public static long ServerNow()
|
|
|
{
|
|
|
return ClientNow();
|
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// 服务器时间(秒)
|
|
|
- /// </summary>
|
|
|
- /// <returns></returns>
|
|
|
public static long ServerNowSeconds()
|
|
|
{
|
|
|
return ClientNowSeconds();
|
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// 时间戳转字符串
|
|
|
- /// </summary>
|
|
|
- /// <param name="value"></param>
|
|
|
- /// <returns></returns>
|
|
|
- public static string ToHour(this int value)
|
|
|
- {
|
|
|
- int fen = value / 60;
|
|
|
- int hour = fen / 60;
|
|
|
- return (hour + 1) + "";
|
|
|
- }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 客户端时间(年月日)
|
|
|
@@ -143,7 +203,6 @@ namespace Fort23.Core
|
|
|
return 20201010;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/// <summary>
|
|
|
/// 客户端时间(月日时分秒)
|
|
|
/// </summary>
|
|
|
@@ -204,7 +263,6 @@ namespace Fort23.Core
|
|
|
}
|
|
|
|
|
|
string result = $"{month}月{day}日{hour}:{minute}:{second}";
|
|
|
-
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
@@ -223,7 +281,8 @@ namespace Fort23.Core
|
|
|
string[] holiday2022 = { "1231" };
|
|
|
string[] holiday2023 =
|
|
|
{
|
|
|
- "0101", "0102", "0121", "0122", "0123", "0124", "0125", "0126", "0127", "0405", "0501", "0502", "0503", "0504", "0505", "0622", "0623",
|
|
|
+ "0101", "0102", "0121", "0122", "0123", "0124", "0125", "0126", "0127", "0405", "0501", "0502", "0503",
|
|
|
+ "0504", "0505", "0622", "0623",
|
|
|
"0929", "1002", "1003", "1004", "1005", "1006"
|
|
|
};
|
|
|
|
|
|
@@ -271,20 +330,20 @@ namespace Fort23.Core
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
public static long GetBaseRefreshTime(long baseTime, int day = 1)
|
|
|
{
|
|
|
DateTime dateTime = DateTimeOffset.FromUnixTimeMilliseconds(baseTime).DateTime;
|
|
|
int hour = dateTime.Hour;
|
|
|
- DateTime refreshDateTime = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, refreshHour, 0, 0, DateTimeKind.Utc);
|
|
|
+ DateTime refreshDateTime = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, refreshHour, 0, 0,
|
|
|
+ DateTimeKind.Utc);
|
|
|
if (hour < refreshHour)
|
|
|
{
|
|
|
day -= 1;
|
|
|
}
|
|
|
|
|
|
refreshDateTime = refreshDateTime.AddDays(day);
|
|
|
-
|
|
|
long refreshTime = new DateTimeOffset(refreshDateTime).ToUnixTimeMilliseconds();
|
|
|
-
|
|
|
return refreshTime;
|
|
|
}
|
|
|
}
|