using System; using System.Collections; using FishNet.Object; using TMPro; using Types; using UnityEngine; using UnityEngine.Rendering.Universal; // 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 float dayLengthInMinutes = 15f; // public float dayStartTimeInHours = 6f; // Start time in hours public Light2D globalLight; public TMP_Text timeText; public TMP_Text dayText; public TMP_Text seasonText; public Gradient lightColorGradient; public Gradient lightIntensityGradient; private readonly int _daysPerMonth = 28; private readonly int _monthsPerYear = 4; // private Season _currentSeason; // private float _currentTime; // private int _daysPassed; private GameManager _gameManager; private bool _isFirstDay = true; private void Awake() { _gameManager = GameManager.Instance; } private void Start() { if (IsServerInitialized) { dayText.text = GetCurrentDayOfMonth().ToString(); seasonText.text = GetCurrentSeason().ToString(); StartCoroutine(ServerDayNightCycleCoroutine()); _isFirstDay = false; } } private void Update() { timeText.text = GetCurrentTime(); //todo: optimize to only update on day change dayText.text = GetCurrentDayOfMonth().ToString(); seasonText.text = GetCurrentSeason().ToString(); var timeSettings = GameManager.Instance.GetTimeSettings(); timeSettings.CurrentTime = timeSettings.DayStartTimeInHours / 24 * timeSettings.DayLengthInMinutes * 60; GameManager.Instance.RequestUpdateTimeSettingsServerRpc(timeSettings); } public override void OnStartClient() { base.OnStartClient(); UpdateUIDisplay(); } private void UpdateUIDisplay() { timeText.text = GetCurrentTime(); //todo: optimize to only update on day change dayText.text = GetCurrentDayOfMonth().ToString(); seasonText.text = GetCurrentSeason().ToString(); } public override void OnStartServer() { base.OnStartServer(); StartCoroutine(ServerDayNightCycleCoroutine()); } 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.GetTimeSettings().DaysPassed % _daysPerMonth; } public int GetCurrentMonth() { return GetDaysPassed() / _daysPerMonth % _monthsPerYear; } public int GetCurrentMonth(int daysPassed) { return daysPassed / _daysPerMonth % _monthsPerYear; } private string GetCurrentTime() { var timeSettings = GameManager.Instance.GetTimeSettings(); // 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); // Convert to 12-hour format and add AM/PM var hours12 = hours % 12; if (hours12 == 0) hours12 = 12; var amPm = hours < 12 ? "AM" : "PM"; return $"{hours12:D2}:{minutes:D2} {amPm}"; } public int GetDaysPassed() { var timeSettings = GameManager.Instance.GetTimeSettings(); return timeSettings.DaysPassed; } [Server] private IEnumerator ServerDayNightCycleCoroutine() { // var previousSeason = GetCurrentSeason(); while (true) { var timeSettings = _gameManager.GetTimeSettings(); // 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.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(); } } }