using SPTarkov.DI.Annotations; using SPTarkov.Server.Core.Generators; using SPTarkov.Server.Core.Helpers; using SPTarkov.Server.Core.Models.Eft.Weather; using SPTarkov.Server.Core.Models.Enums; using SPTarkov.Server.Core.Models.Spt.Config; using SPTarkov.Server.Core.Servers; using SPTarkov.Server.Core.Utils; namespace SPTarkov.Server.Core.Services; [Injectable(InjectionType.Singleton)] public class RaidWeatherService( TimeUtil timeUtil, WeatherGenerator weatherGenerator, SeasonalEventService seasonalEventService, WeightedRandomHelper weightedRandomHelper, ConfigServer configServer ) { protected readonly WeatherConfig _weatherConfig = configServer.GetConfig(); protected readonly 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 staringTimestamp = timeUtil.GetTodayMidnightTimeStamp(); // How far into future do we generate weather var futureTimestampToReach = staringTimestamp + timeUtil.GetHoursAsSeconds(_weatherConfig.Weather.GenerateWeatherAmountHours ?? 1); // Keep adding new weather until we have reached desired future date var nextTimestamp = staringTimestamp; while (nextTimestamp <= futureTimestampToReach) { var newWeatherToAddToCache = weatherGenerator.GenerateWeather(currentSeason, nextTimestamp); // Add generated weather for time period to cache _weatherForecast.Add(newWeatherToAddToCache); // Increment timestamp so next loop can begin at correct time nextTimestamp += GetWeightedWeatherTimePeriod(); } } /// /// Get a time period to increment by, e.g. 15 or 30 minutes as milliseconds /// /// milliseconds protected long GetWeightedWeatherTimePeriod() { var chosenTimePeriodMinutes = weightedRandomHelper .WeightedRandom(_weatherConfig.Weather.TimePeriod.Values, _weatherConfig.Weather.TimePeriod.Weights) .Item; return chosenTimePeriodMinutes * 60; } /// /// 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); } } }