diff --git a/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs b/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs
index 6a50b72b10..9266651585 100644
--- a/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs
+++ b/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs
@@ -1,21 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.ResourceManagement.AsyncOperations;
-using UnityEngine.SceneManagement;
using UnityEngine.U2D;
namespace BrewMonster.Scripts
{
///
- /// Scene game (Bootstrap): chờ gate chỉ khi cùng scene.
- /// Nếu đã chạy scene GameContentBootstrap trước → .
+ /// Scene Bootstrap (index 1): Addressables luôn được init thẳng vì
+ /// đã chạy xong ở scene 0 ( = true).
///
[DefaultExecutionOrder(-1990)]
public class AddressableManager : MonoSingleton
@@ -38,14 +36,6 @@ namespace BrewMonster.Scripts
private Dictionary _releaseAssetTimestamps = new();
[SerializeField]private float _releaseAssetTimeout = 10f;
- [Header("Bootstrap gate")]
- [Tooltip("Max seconds to wait for GameContentBootstrap before initializing Addressables anyway.")]
- [SerializeField]
- float _bootstrapGateWaitTimeoutSeconds = 50f;
-
- [SerializeField]
- bool _verboseBootstrapWaitDebug = true;
-
public event Action OnDispose;
/// Get the count of currently loaded assets.
@@ -65,13 +55,7 @@ namespace BrewMonster.Scripts
protected override void Awake()
{
- if (_verboseBootstrapWaitDebug)
- {
- Debug.Log(
- $"[Cuong] AddressableManager: Awake | id={GetInstanceID()} scene={SceneManager.GetActiveScene().name} " +
- $"frame={Time.frameCount} bootstrapGate={GameContentBootstrap.GetGateDebugState()}");
- }
-
+ Debug.Log($"[Cuong] AddressableManager: Awake | id={GetInstanceID()} frame={Time.frameCount}");
base.Awake();
}
@@ -80,35 +64,11 @@ namespace BrewMonster.Scripts
base.Initialize();
_isInitialized = false;
_initializationTcs = new UniTaskCompletionSource();
- StartAddressablesInitAfterBootstrapGate().Forget();
+ StartAddressablesInitAsync().Forget();
}
- ///
- /// Waits for (version HTTP + optional URL rewrite) when that gate is active.
- ///
- async UniTaskVoid StartAddressablesInitAfterBootstrapGate()
+ async UniTaskVoid StartAddressablesInitAsync()
{
- if (GameContentBootstrapSession.IsContentReady || AddressablesInitService.IsInitialized)
- {
- Debug.Log(
- $"[Cuong] AddressableManager: Content bootstrap đã chạy ở scene trước — init Addressables (scene={SceneManager.GetActiveScene().name}).");
- }
- else
- {
- var gateState = GameContentBootstrap.GetGateDebugState();
- Debug.Log(
- $"[Cuong] AddressableManager: Đang chờ GameContentBootstrap (version / URL rewrite)... | " +
- $"id={GetInstanceID()} scene={SceneManager.GetActiveScene().name} gate={gateState}");
-
- var waited = await WaitForBootstrapGateWithTimeoutAsync();
- if (!waited)
- {
- Debug.LogWarning(
- $"[Cuong] AddressableManager: Bootstrap gate timeout ({_bootstrapGateWaitTimeoutSeconds:F0}s) — " +
- "InitializeAsync anyway. Nên dùng scene GameContentBootstrap riêng (index 0).");
- }
- }
-
Debug.Log("[Cuong] AddressableManager: Đang InitializeAsync Addressables...");
try
{
@@ -125,21 +85,6 @@ namespace BrewMonster.Scripts
}
}
- async UniTask WaitForBootstrapGateWithTimeoutAsync()
- {
- var timeoutSec = Mathf.Max(5f, _bootstrapGateWaitTimeoutSeconds);
- using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutSec));
- try
- {
- await GameContentBootstrap.WaitForPreAddressablesSetupIfAnyAsync(cts.Token);
- return true;
- }
- catch (OperationCanceledException)
- {
- return false;
- }
- }
-
#region Unity lifecycle
private List _assetToForceRelease = new();
private void Update()
diff --git a/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs b/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs
index 44187e9adf..729ac69e95 100644
--- a/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs
+++ b/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs
@@ -34,9 +34,12 @@ namespace BrewMonster.Network
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}");
+ // 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}");
}
///
@@ -54,6 +57,18 @@ namespace BrewMonster.Network
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)
{
diff --git a/Assets/PerfectWorld/Scripts/World/CECSunMoon.cs b/Assets/PerfectWorld/Scripts/World/CECSunMoon.cs
index e92db4588f..780e3f062c 100644
--- a/Assets/PerfectWorld/Scripts/World/CECSunMoon.cs
+++ b/Assets/PerfectWorld/Scripts/World/CECSunMoon.cs
@@ -11,7 +11,8 @@ namespace BrewMonster.Scripts
private const float DAY_NIGHT_START = (18.0f / 24.0f);
private const float DAY_NIGHT_END = (21.0f / 24.0f);
- public double m_vTimeOfTheDay; // time of the day 0.0f means 00:00, 1.0f means 24:00
+ public double m_vTimeOfTheDay; // time of the day 0.0f means 00:00, 1.0f means 24:00 (4h-cycle phase, matches C++ CECSunMoon)
+ public double m_vRealPhase; // 真实服务器时间对应的24h相位(用于 nightControl shader)// real 24h phase from server time, used for nightControl shader (not the 4h-wrapped cycle)
public float m_fDNFactor; // day or night factor
public float m_fDNFactorDest; // day or night factor dest
@@ -28,9 +29,15 @@ namespace BrewMonster.Scripts
public void Update()
{
- m_vTimeOfTheDay += Time.deltaTime / 3600.0 / 24.0 * TIME_SCALE;
+ double advance = Time.deltaTime / 3600.0 / 24.0;
+ // 4h cycle — same as C++ Tick(): drives sun/moon visual animation
+ m_vTimeOfTheDay += advance * TIME_SCALE;
while (m_vTimeOfTheDay > 1.0)
m_vTimeOfTheDay -= 1.0;
+ // 24h real-time phase — used for nightControl shader (not TIME_SCALE-sped-up)
+ m_vRealPhase += advance;
+ while (m_vRealPhase > 1.0)
+ m_vRealPhase -= 1.0;
RefreshDayNightFactorsFromPhase();
}
@@ -40,6 +47,7 @@ namespace BrewMonster.Scripts
///
/// 设置一天中的时刻(与 PC 版 CECSunMoon::SetTimeOfTheDay 对齐) // Set time-of-day phase [0,1), aligned with PC CECSunMoon::SetTimeOfTheDay
+ /// 仅设置4h动画相位;用 SetTimeOfTheDayFull 同时设置真实24h相位 // Sets 4h animation phase only; use SetTimeOfTheDayFull to also set the real 24h phase
///
public bool SetTimeOfTheDay(float vTime)
{
@@ -52,14 +60,34 @@ namespace BrewMonster.Scripts
return true;
}
+ ///
+ /// 同时设置4h动画相位(C++公式)和24h真实相位(shader nightControl用) // Set both the 4h animation phase (C++ formula) and the real 24h phase (for shader nightControl)
+ ///
+ /// nTimeInDay / (4f*3600f) — wrap to [0,1), drives sun/moon animation
+ /// nTimeInDay / (24f*3600f) — [0,1), drives nightControl shader (0=day 1=night based on real server time)
+ public bool SetTimeOfTheDayFull(float phase4h, float phase24h)
+ {
+ while (phase4h < 0f) phase4h += 1f;
+ while (phase4h > 1f) phase4h -= 1f;
+ m_vTimeOfTheDay = phase4h;
+
+ phase24h = Mathf.Clamp01(phase24h);
+ m_vRealPhase = phase24h;
+
+ RefreshDayNightFactorsFromPhase();
+ return true;
+ }
+
///
/// PC EC_SunMoon::UpdateWithTime 中昼夜因子段(供 minimap 与场景一致) // DN factor block from PC EC_SunMoon::UpdateWithTime
+ /// m_fDNFactor 由4h相位驱动(与C++一致,用于太阳/月亮视觉); nightControl 由24h真实相位驱动(shader正确反映服务器白天/黑夜)
+ /// m_fDNFactor is driven by the 4h phase (C++ compatible, for sun/moon visuals); nightControl is driven by the real 24h phase (shader correctly reflects server day/night)
///
void RefreshDayNightFactorsFromPhase()
{
float v = (float)m_vTimeOfTheDay;
- // update day night factor — same branches as PC EC_SunMoon.cpp UpdateWithTime (lines 894–918)
+ // m_fDNFactor — 4h cycle phase, same as C++ EC_SunMoon::UpdateWithTime lines 894-918
if (v < NIGHT_DAY_START)
{
m_fDNFactor = 1.0f;
@@ -87,7 +115,22 @@ namespace BrewMonster.Scripts
m_fDNFactorDest = 1.0f;
}
- _globalShaderVariables?.Apply(m_fDNFactor);
+ // nightControl shader — driven by m_vRealPhase (24h real server time, 0=day 1=night)
+ // 用真实24h相位计算 nightControl,确保正午=白天(0),午夜=黑夜(1),不受4h周期wrap影响
+ // Real 24h phase ensures noon=day(0), midnight=night(1), unaffected by 4h cycle wrapping
+ _globalShaderVariables?.Apply(ComputeNightControlFromRealPhase((float)m_vRealPhase));
+ }
+
+ ///
+ /// 用24h真实相位计算 nightControl(与相同阈值,但基于实际服务器时间) // Compute nightControl from real 24h phase using same thresholds
+ ///
+ static float ComputeNightControlFromRealPhase(float r)
+ {
+ if (r < NIGHT_DAY_START) return 1.0f;
+ if (r < NIGHT_DAY_END) return 1.0f - (r - NIGHT_DAY_START) / (NIGHT_DAY_END - NIGHT_DAY_START);
+ if (r < DAY_NIGHT_START) return 0.0f;
+ if (r < DAY_NIGHT_END) return (r - DAY_NIGHT_START) / (DAY_NIGHT_END - DAY_NIGHT_START);
+ return 1.0f;
}
}
}