using Core.Generators; using Core.Helpers; using Core.Models.Eft.Weather; using Core.Models.Enums; using Core.Models.Spt.Config; using Core.Servers; using Core.Utils; using SptCommon.Annotations; namespace Core.Services; [Injectable(InjectionType.Singleton)] public class RaidWeatherService( TimeUtil _timeUtil, WeatherGenerator _weatherGenerator, SeasonalEventService _seasonalEventService, WeightedRandomHelper _weightedRandomHelper, ConfigServer _configServer ) { protected WeatherConfig _weatherConfig = _configServer.GetConfig(); protected List _weatherForecast = []; /// /// Generate 24 hours of weather data starting from midnight today /// public void GenerateWeather(Season currentSeason) { // When to start generating weather from in milliseconds var staringTimestampMs = _timeUtil.GetTodayMidnightTimeStamp(); // How far into future do we generate weather var futureTimestampToReachMs = staringTimestampMs + _timeUtil.GetHoursAsSeconds(_weatherConfig.Weather.GenerateWeatherAmountHours ?? 1) * 1000; // Convert to milliseconds // Keep adding new weather until we have reached desired future date var nextTimestampMs = staringTimestampMs; while (nextTimestampMs <= futureTimestampToReachMs) { var newWeatherToAddToCache = _weatherGenerator.GenerateWeather(currentSeason, nextTimestampMs); // Add generated weather for time period to cache _weatherForecast.Add(newWeatherToAddToCache); // Increment timestamp so next loop can begin at correct time nextTimestampMs += GetWeightedWeatherTimePeriodMs(); } } /// /// Get a time period to increment by, e.g. 15 or 30 minutes as milliseconds /// /// milliseconds protected long GetWeightedWeatherTimePeriodMs() { var chosenTimePeriodMinutes = _weightedRandomHelper.WeightedRandom( _weatherConfig.Weather.TimePeriod.Values, _weatherConfig.Weather.TimePeriod.Weights ) .Item; return chosenTimePeriodMinutes * 60 * 1000; // Convert to milliseconds } /// /// Find the first matching weather object that applies to the current time /// public Weather GetCurrentWeather() { var currentSeason = _seasonalEventService.GetActiveWeatherSeason(); ValidateWeatherDataExists(currentSeason); return _weatherForecast.Find(weather => weather.Timestamp >= _timeUtil.GetTimeStamp()); } /// /// Find all matching weather objects that applies to the current time + future /// public IEnumerable GetUpcomingWeather() { var currentSeason = _seasonalEventService.GetActiveWeatherSeason(); ValidateWeatherDataExists(currentSeason); return _weatherForecast.Where(weather => weather.Timestamp >= _timeUtil.GetTimeStamp()); } /// /// Ensure future weather data exists /// protected void ValidateWeatherDataExists(Season currentSeason) { // Clear expired weather data _weatherForecast.RemoveAll(weather => weather.Timestamp < _timeUtil.GetTimeStamp()); // Check data exists for current time var result = _weatherForecast.Where(weather => weather.Timestamp >= _timeUtil.GetTimeStamp()); if (!result.Any()) { GenerateWeather(currentSeason); } } }