using System; using System.Collections; using FishNet.Object; using FishNet.Object.Synchronizing; using Types; using UnityEngine; // possible future additions // weather sys // skybox changes based on time of day // moon and stars // clouds // rain // Sound effects, bird chrirping, crickets, wind, etc // Temperture? // Lighting effects! So that the transition is more visually appealing // Moonlight phases based on day of month ect // Seasons - impact the length of day, temp, weather, etc namespace Managers { public class GameTimeManager : NetworkBehaviour { public static GameTimeManager Instance; [SerializeField] private bool isPaused = true; [SerializeField] private bool isFirstDay = true; private readonly int _daysPerMonth = 28; private readonly SyncVar _dayText = new(new SyncTypeSettings { WritePermission = WritePermission.ServerOnly, ReadPermission = ReadPermission.Observers }); private readonly int _monthsPerYear = 4; private readonly SyncVar _seasonText = new(new SyncTypeSettings { WritePermission = WritePermission.ServerOnly, ReadPermission = ReadPermission.Observers }); private readonly SyncVar _timeText = new(new SyncTypeSettings { WritePermission = WritePermission.ServerOnly, ReadPermission = ReadPermission.Observers }); private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; } /*private void Start() { /*if (IsServerInitialized) { dayText.Value = GetCurrentDayOfMonth().ToString(); StartCoroutine(ServerDayNightCycleCoroutine()); _isFirstDay = false; }#1# }*/ private void Start() { // if (IsServerInitialized) InitializeServerData(); } private void Update() { if (isPaused) return; if (GameManager.Instance == null) Debug.LogError("GameManager.Instance is null in GameTimeManager.Update()"); // var timeSettings = GameManager.Instance.GetTimeSettings(); // if (timeSettings == null) return; // timeSettings.CurrentTime = CalculateCurrentTime(); // GameManager.Instance.RequestUpdateTimeSettingsServerRpc(timeSettings); } private void InitializeServerData() { if (GameManager.Instance == null) { Debug.LogError("GameManager.Instance is null in GameTimeManager.InitializeServerData()"); return; } var timeSettings = GameManager.Instance.GetTimeSettings(); if (timeSettings == null) { Debug.LogError("TimeSettings is null in GameTimeManager.InitializeServerData()"); return; } _dayText.Value = GetCurrentDayOfMonth().ToString(); StartCoroutine(ServerDayNightCycleCoroutine()); isFirstDay = false; } public override void OnStartClient() { base.OnStartClient(); /*UpdateUIDisplay();*/ } /*private void UpdateUIDisplay() { _timeText.Value = GetCurrentTimeFormatted(); //todo: optimize to only update on day change _dayText.Value = GetCurrentDayOfMonth().ToString(); _seasonText.Value = GetCurrentSeason().ToString(); }*/ public override void OnStartServer() { base.OnStartServer(); /*// StartCoroutine(ServerDayNightCycleCoroutine()); Debug.Log("GameTimeManager.OnStartServer() triggered"); */ if (IsServerInitialized) { Debug.Log("GameTimeManager.OnStartServer() triggered, initializing server data"); InitializeServerData(); } } public static event Action OnDayChange; public static event Action OnSeasonChange; public Season GetCurrentSeason() { return GetCurrentSeason(GetDaysPassed()); } public Season GetCurrentSeason(int daysPassed) { var month = GetCurrentMonth(daysPassed); return month switch { 0 => Season.Spring, 1 => Season.Summer, 2 => Season.Fall, 3 => Season.Winter, _ => Season.Spring }; } public int GetCurrentDayOfMonth() { return GameManager.Instance.GetTimeSettings().DaysPassed % _daysPerMonth; } public int GetCurrentMonth() { return GetDaysPassed() / _daysPerMonth % _monthsPerYear; } public int GetCurrentMonth(int daysPassed) { return daysPassed / _daysPerMonth % _monthsPerYear; } public GameTime GetGameTime() { if (GameManager.Instance == null) { Debug.LogError("GameManager not found"); return new GameTime(); } var timeSettings = GameManager.Instance.GetTimeSettings(); if (timeSettings == null) return new GameTime(); // Calculate the current hour and minute based on the time of day var timeOfDay = timeSettings.CurrentTime / (timeSettings.DayLengthInMinutes * 60); var hours = Mathf.FloorToInt(timeOfDay * 24); var minutes = Mathf.FloorToInt((timeOfDay * 24 - hours) * 60); var seconds = Mathf.FloorToInt((timeOfDay * 24 - hours) * 60 * 60); return new GameTime { hour = hours, minute = minutes, second = seconds }; } public string GetCurrentTimeFormatted() { if (GameManager.Instance == null) { Debug.LogError("GameManager not found"); return "00:00"; } var timeSettings = GameManager.Instance.GetTimeSettings(); Debug.Log("Current settings start time: " + timeSettings.DayStartTimeInHours); Debug.Log("Current settings day length: " + timeSettings.DayLengthInMinutes); if (timeSettings == null) return "00:00"; // Calculate the current hour and minute based on the time of day var gameTime = GetGameTime(); Debug.Log("Current time: " + gameTime.hour + ":" + gameTime.minute); var hours = gameTime.hour; var minutes = gameTime.minute; // Convert to 12-hour format and add AM/PM var hours12 = hours % 12; if (hours12 == 0) hours12 = 12; var amPm = hours < 12 ? "AM" : "PM"; Debug.Log("Hours: " + hours + " AM/PM: " + amPm); return $"{(int)hours12:D2}:{(int)minutes:D2} {amPm}"; } public int GetDaysPassed() { var timeSettings = GameManager.Instance.GetTimeSettings(); return timeSettings?.DaysPassed ?? 0; } public void Pause() { Debug.Log("GameTimeManager.Pause()"); isPaused = true; } public void Resume() { Debug.Log("GameTimeManager.Resume()"); isPaused = false; } [Server] private IEnumerator ServerDayNightCycleCoroutine() { // var previousSeason = GetCurrentSeason(); while (true) { if (isPaused) yield return new WaitForSeconds(0.5f); if (GameManager.Instance == null) { Debug.LogWarning("GameManager.Instance is null in GameTimeManager.ServerDayNightCycleCoroutine()"); yield return new WaitForSeconds(0.5f); continue; } var timeSettings = GameManager.Instance.GetTimeSettings(); if (timeSettings == null) { Debug.LogWarning("TimeSettings is null in GameTimeManager.ServerDayNightCycleCoroutine()"); yield return new WaitForSeconds(0.5f); continue; } // Calculate the current time of day between 0 (midnight) and 1 (next midnight) var timeOfDay = timeSettings.CurrentTime / (timeSettings.DayLengthInMinutes * 60); /*// Adjust the intensity of the light source based on the time of day globalLight.color = lightColorGradient.Evaluate(timeOfDay); globalLight.intensity = lightIntensityGradient.Evaluate(timeOfDay).a;*/ // increment current time timeSettings.CurrentTime += Time.deltaTime; // check if a day has passed if (timeSettings.CurrentTime >= timeSettings.DayLengthInMinutes * 60) { timeSettings.DaysPassed++; Debug.Log("Day " + timeSettings.DaysPassed + " has passed"); timeSettings.CurrentTime = 0; isFirstDay = false; OnDayChange?.Invoke(); var newSeason = GetCurrentSeason(timeSettings.DaysPassed); if (newSeason != timeSettings.Season) { Debug.Log("Season changed from " + timeSettings.Season + " to " + newSeason); timeSettings.Season = newSeason; OnSeasonChange?.Invoke(); } } GameManager.Instance.RequestUpdateTimeSettingsServerRpc(timeSettings); UpdateClientsRpc(timeOfDay); yield return null; } } [ObserversRpc] private void UpdateClientsRpc(float timeOfDay) { // globalLight.color = lightColorGradient.Evaluate(timeOfDay); // globalLight.intensity = lightIntensityGradient.Evaluate(timeOfDay).a; // UpdateUIDisplay(); } } }