update light

This commit is contained in:
CuongNV
2026-05-29 10:02:52 +07:00
parent 4662e1a089
commit a681d15e26
3 changed files with 70 additions and 67 deletions
@@ -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
{
/// <summary>
/// Scene game (Bootstrap): chờ gate chỉ khi <see cref="GameContentBootstrap"/> cùng scene.
/// Nếu đã chạy scene GameContentBootstrap trước → <see cref="GameContentBootstrapSession.IsContentReady"/>.
/// Scene Bootstrap (index 1): Addressables luôn được init thẳng vì
/// <see cref="GameContentBootstrap"/> đã chạy xong ở scene 0 (<see cref="GameContentBootstrapSession.IsContentReady"/> = true).
/// </summary>
[DefaultExecutionOrder(-1990)]
public class AddressableManager : MonoSingleton<AddressableManager>
@@ -38,14 +36,6 @@ namespace BrewMonster.Scripts
private Dictionary<string, float> _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;
/// <summary>Get the count of currently loaded assets.</summary>
@@ -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();
}
/// <summary>
/// Waits for <see cref="GameContentBootstrap"/> (version HTTP + optional URL rewrite) when that gate is active.
/// </summary>
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<bool> 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<string> _assetToForceRelease = new();
private void Update()
@@ -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}");
}
/// <summary>
@@ -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)
{
@@ -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
/// <summary>
/// 设置一天中的时刻(与 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
/// </summary>
public bool SetTimeOfTheDay(float vTime)
{
@@ -52,14 +60,34 @@ namespace BrewMonster.Scripts
return true;
}
/// <summary>
/// 同时设置4h动画相位(C++公式)和24h真实相位(shader nightControl用) // Set both the 4h animation phase (C++ formula) and the real 24h phase (for shader nightControl)
/// </summary>
/// <param name="phase4h">nTimeInDay / (4f*3600f) — wrap to [0,1), drives sun/moon animation</param>
/// <param name="phase24h">nTimeInDay / (24f*3600f) — [0,1), drives nightControl shader (0=day 1=night based on real server time)</param>
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;
}
/// <summary>
/// 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)
/// </summary>
void RefreshDayNightFactorsFromPhase()
{
float v = (float)m_vTimeOfTheDay;
// update day night factor — same branches as PC EC_SunMoon.cpp UpdateWithTime (lines 894918)
// 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));
}
/// <summary>
/// 用24h真实相位计算 nightControl(与相同阈值,但基于实际服务器时间) // Compute nightControl from real 24h phase using same thresholds
/// </summary>
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;
}
}
}