using System; using asap.core; using game; using GameCore; using TimeManager.Event; using UniRx; using UnityEngine; namespace TimeManager { /// /// 时间刷新管理器 - 检测跨天、跨小时并触发刷新。须在启动链中显式 Resolve<TimeRefreshManager>()(见 ActivityManager.Init)。 /// public class TimeRefreshManager : IDisposable { public TimeRefreshManager(ITimeTickService tickService, IUserService userService) { _tickService = tickService; _userService = userService; _sessionStartTime = ZZTimeHelper.UtcNow().UtcNowOffset(); _lastCheckedHour = _sessionStartTime.Hour; CheckLastLogin(); _tickService.MinuteTick .Subscribe(_ => { CheckSessionCrossDay(); CheckSessionCrossHour(); }) .AddTo(_disposables); } private readonly ITimeTickService _tickService; private readonly IUserService _userService; private int _lastCheckedDayOfYear = -1; private int _lastCheckedHour = -1; private DateTime _sessionStartTime; private CompositeDisposable _disposables = new(); #region Check登录时间 private void CheckLastLogin() { if (IsLastLoginToday()) return; Debug.Log("上次登录不是今天"); OnCrossDayRefresh(); } private void CheckSessionCrossDay() { if (!IsSessionCrossDay()) return; OnCrossDayRefresh(); _sessionStartTime = ZZTimeHelper.UtcNow().UtcNowOffset(); } private void CheckSessionCrossHour() { if (!IsSessionCrossHour()) return; OnCrossHourRefresh(); var now = ZZTimeHelper.UtcNow().UtcNowOffset(); _lastCheckedHour = now.Hour; } #endregion #region 登录时间相关 /// /// 判断上次登录是否是今天 /// 从 UserService 获取 PlayFab 记录的真实上次登录时间 /// public bool IsLastLoginToday() { var lastLoginTime = GetLastLoginTime(); if (!lastLoginTime.HasValue) { return false; // 从未登录过 } var now = ZZTimeHelper.UtcNow().UtcNowOffset(); return lastLoginTime.Value.DayOfYear == now.DayOfYear && lastLoginTime.Value.Year == now.Year; } /// /// 判断当前会话是否跨天(从登录到现在的过程中是否跨过了午夜) /// public bool IsSessionCrossDay() { var now = ZZTimeHelper.UtcNow().UtcNowOffset(); return _sessionStartTime.DayOfYear != now.DayOfYear || _sessionStartTime.Year != now.Year; } /// /// 判断当前会话是否跨小时(从上次检查到现在是否跨过了整点) /// public bool IsSessionCrossHour() { var now = ZZTimeHelper.UtcNow().UtcNowOffset(); return now.Hour != _lastCheckedHour; } /// /// 获取上次登录时间(从 UserService 获取) /// public DateTime? GetLastLoginTime() { return _userService?.LastLoginTime; } /// /// 获取会话开始时间(本次游戏启动时间) /// public DateTime GetSessionStartTime() { return _sessionStartTime; } #endregion /// /// 跨天刷新逻辑 /// private void OnCrossDayRefresh() { try { // 1. 发送活动跨天刷新事件 GContext.Publish(new ActivityCrossDayRefreshEvent()); } catch (Exception e) { Debug.LogError($"[TimeRefreshManager] Error during cross day refresh: {e.Message}\n{e.StackTrace}"); } } /// /// 跨小时刷新逻辑 /// private void OnCrossHourRefresh() { try { // 发送跨小时刷新事件 GContext.Publish(new ActivityCrossHourRefreshEvent()); } catch (Exception e) { Debug.LogError($"[TimeRefreshManager] Error during cross hour refresh: {e.Message}\n{e.StackTrace}"); } } public void Dispose() { _disposables?.Dispose(); _disposables = null; Debug.Log("[TimeRefreshManager] Disposed."); } } }