using System; // ЧАСЫ ИГРЫ: единственный источник "сейчас" для игровых правил (население, а дальше -- производство). // // Время игры = реальное время UTC + сдвиг. Сдвиг нужен только отладочной панели ("+1 час"): // перемотка идёт через те же правила, что и офлайн-прогресс, отдельной логики у неё нет. // Сдвиг НЕ сохраняется -- после перезапуска игры время снова реальное. // // Модули берут время только отсюда: GameClock.UnixNow, а не DateTime.UtcNow. public static class GameClock { static long offsetSeconds; // Для тестов: подменить "реальное" время. null -- настоящие часы устройства. public static Func RealUnixSource; public static long OffsetSeconds => offsetSeconds; // Текущее время игры, секунды Unix public static long UnixNow => RealUnix() + offsetSeconds; public static DateTime UtcNow => DateTimeOffset.FromUnixTimeSeconds(UnixNow).UtcDateTime; // Промотать время вперёд (отладка). Модули узнают об этом из GameTimeAdvancedEvent и досчитываются. public static void Advance(long seconds) { if (seconds <= 0) return; offsetSeconds += seconds; EventBus.Publish(new GameTimeAdvancedEvent { Seconds = seconds, UnixNow = UnixNow }); } // Вернуть реальное время (сдвиг = 0). Модули воспримут это как "часы ушли назад" и просто продолжат с этого момента. public static void ResetOffset() { offsetSeconds = 0; } static long RealUnix() { return RealUnixSource != null ? RealUnixSource() : DateTimeOffset.UtcNow.ToUnixTimeSeconds(); } }