Improvements to how weather temperature is calculated - takes into account current season

Centralised the season override into `getActiveWeatherSeason()`
Adjusted weather values based on client data
This commit is contained in:
Dev 2024-10-17 13:05:01 +01:00
parent eb6e61c1f0
commit 0b729fba11
6 changed files with 68 additions and 30 deletions

View File

@ -3,12 +3,12 @@
"weather": {
"generateWeatherAmountHours": 24,
"clouds": {
"values": [-1.5, -1, 0, 0.5, 1, 1.5],
"weights": [60, 50, 15, 5, 4, 3]
"values": [-1, 0, 0.5, 1, 1.5],
"weights": [100, 15, 5, 4, 3]
},
"windSpeed": {
"values": [0, 1, 2, 3],
"weights": [4, 3, 2, 1]
"values": [0, 1, 2, 3, 4],
"weights": [6, 3, 2, 1, 1]
},
"windDirection": {
"values": [1, 2, 3, 4, 5, 6, 7, 8],
@ -19,8 +19,8 @@
"max": 1
},
"rain": {
"values": [1, 2, 3],
"weights": [25, 1, 1]
"values": [1, 2, 3, 4, 5],
"weights": [25, 1, 1, 1, 1]
},
"rainIntensity": {
"min": 0,
@ -31,12 +31,30 @@
"weights": [25, 8, 5, 5, 1]
},
"temp": {
"min": 0,
"max": 24
"0": {
"min": 17,
"max": 32
},
"1": {
"min": 7,
"max": 15
},
"2": {
"min": -10,
"max": 5
},
"3": {
"min": 1,
"max": 15
},
"4": {
"min": 0,
"max": 24
}
},
"pressure": {
"min": 760,
"max": 764
"max": 780
},
"timePeriod": {
"values": [15, 30],

View File

@ -30,7 +30,7 @@ export class WeatherController {
let result: IWeatherData = { acceleration: 0, time: "", date: "", weather: undefined, season: 1 }; // defaults, hydrated below
result = this.weatherGenerator.calculateGameTime(result);
result.weather = this.weatherGenerator.generateWeather();
result.weather = this.weatherGenerator.generateWeather(result.season);
return result;
}
@ -46,10 +46,7 @@ export class WeatherController {
/** Handle client/localGame/weather */
public generateLocal(sesssionId: string): IGetLocalWeatherResponseData {
const result: IGetLocalWeatherResponseData = {
season:
this.weatherConfig.overrideSeason !== null
? this.weatherConfig.overrideSeason
: this.seasonalEventService.getActiveWeatherSeason(),
season: this.seasonalEventService.getActiveWeatherSeason(),
weather: [],
};

View File

@ -3,6 +3,7 @@ import { WeatherHelper } from "@spt/helpers/WeatherHelper";
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
import { IWeather, IWeatherData } from "@spt/models/eft/weather/IWeatherData";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { Season } from "@spt/models/enums/Season";
import { WindDirection } from "@spt/models/enums/WindDirection";
import { IWeatherConfig } from "@spt/models/spt/config/IWeatherConfig";
import { ILogger } from "@spt/models/spt/utils/ILogger";
@ -46,10 +47,7 @@ export class WeatherGenerator {
data.time = this.getBsgFormattedInRaidTime();
data.acceleration = this.weatherConfig.acceleration;
data.season =
this.weatherConfig.overrideSeason !== null
? this.weatherConfig.overrideSeason
: this.seasonalEventService.getActiveWeatherSeason();
data.season = this.seasonalEventService.getActiveWeatherSeason();
return data;
}
@ -79,7 +77,7 @@ export class WeatherGenerator {
* Return randomised Weather data with help of config/weather.json
* @returns Randomised weather data
*/
public generateWeather(timestamp?: number): IWeather {
public generateWeather(currentSeason: Season, timestamp?: number): IWeather {
const clouds = this.getWeightedClouds();
// Force rain to off if no clouds
@ -93,7 +91,7 @@ export class WeatherGenerator {
rain: rain,
rain_intensity: rain > 1 ? this.getRandomFloat("rainIntensity") : 0,
fog: this.getWeightedFog(),
temp: this.getRandomFloat("temp"), // TODO - lower value at night / take into account season
temp: 0, // TODO - lower value at night / take into account season
pressure: this.getRandomFloat("pressure"),
time: "",
date: "",
@ -102,9 +100,17 @@ export class WeatherGenerator {
this.setCurrentDateTime(result, timestamp);
result.temp = this.getRaidTemperature(currentSeason, result.time);
return result;
}
protected getRaidTemperature(currentSeason: Season, currentTimeBsgFormatted: string): number {
// TODO, take into account time of day
const minMax = this.weatherConfig.weather.temp[currentSeason];
return Number.parseFloat(this.randomUtil.getFloat(minMax.min, minMax.max).toPrecision(2));
}
/**
* Set IWeather date/time/timestamp values to now
* @param weather Object to update

View File

@ -30,7 +30,7 @@ export interface IWeatherValues {
rain: WeatherSettings<number>;
rainIntensity: MinMax;
fog: WeatherSettings<string>;
temp: MinMax;
temp: Record<Season, MinMax>;
pressure: MinMax;
/** Length of each weather period */
timePeriod: WeatherSettings<number>;

View File

@ -2,10 +2,12 @@ import { WeatherGenerator } from "@spt/generators/WeatherGenerator";
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
import { IWeather } from "@spt/models/eft/weather/IWeatherData";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { Season } from "@spt/models/enums/Season";
import { IWeatherConfig } from "@spt/models/spt/config/IWeatherConfig";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { DatabaseService } from "@spt/services/DatabaseService";
import { SeasonalEventService } from "@spt/services/SeasonalEventService";
import { TimeUtil } from "@spt/utils/TimeUtil";
import { inject, injectable } from "tsyringe";
@ -19,18 +21,20 @@ export class RaidWeatherService {
@inject("DatabaseService") protected databaseService: DatabaseService,
@inject("TimeUtil") protected timeUtil: TimeUtil,
@inject("WeatherGenerator") protected weatherGenerator: WeatherGenerator,
@inject("SeasonalEventService") protected seasonalEventService: SeasonalEventService,
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
@inject("ConfigServer") protected configServer: ConfigServer,
) {
this.weatherConfig = this.configServer.getConfig(ConfigTypes.WEATHER);
this.generateWeather();
const currentSeason = this.seasonalEventService.getActiveWeatherSeason();
this.generateWeather(currentSeason);
}
/**
* Generate 24 hours of weather data starting from midnight today
*/
public generateWeather() {
public generateWeather(currentSeason: Season) {
// When to start generating weather from in milliseconds
const staringTimestampMs = this.timeUtil.getTodaysMidnightTimestamp();
@ -42,13 +46,20 @@ export class RaidWeatherService {
// Keep adding new weather until we have reached desired future date
let nextTimestampMs = staringTimestampMs;
while (nextTimestampMs <= futureTimestampToReachMs) {
const newWeather = this.weatherGenerator.generateWeather(nextTimestampMs);
this.logger.warning(`Handling ${new Date(nextTimestampMs)}`);
this.weatherForecast.push(newWeather);
const newWeatherToAddToCache = this.weatherGenerator.generateWeather(currentSeason, nextTimestampMs);
// Add generated weather for time period to cache
this.weatherForecast.push(newWeatherToAddToCache);
// Increment timestamp so next loop can begin at correct time
nextTimestampMs += this.getWeightedWeatherTimePeriodMs();
}
}
/**
* Get a time period to increment by, e.g 15 or 30 minutes as milliseconds
* @returns milliseconds
*/
protected getWeightedWeatherTimePeriodMs(): number {
const chosenTimePeriodMinutes = this.weightedRandomHelper.weightedRandom(
this.weatherConfig.weather.timePeriod.values,
@ -62,7 +73,8 @@ export class RaidWeatherService {
* Find the first matching weather object that applies to the current time
*/
public getCurrentWeather(): IWeather {
this.validateWeatherDataExists();
const currentSeason = this.seasonalEventService.getActiveWeatherSeason();
this.validateWeatherDataExists(currentSeason);
return this.weatherForecast.find((x) => x.timestamp >= this.timeUtil.getTimestamp());
}
@ -71,7 +83,8 @@ export class RaidWeatherService {
* Find the first matching weather object that applies to the current time + all following weather data generated
*/
public getUpcomingWeather(): IWeather[] {
this.validateWeatherDataExists();
const currentSeason = this.seasonalEventService.getActiveWeatherSeason();
this.validateWeatherDataExists(currentSeason);
return this.weatherForecast.filter((x) => x.timestamp >= this.timeUtil.getTimestamp());
}
@ -79,7 +92,7 @@ export class RaidWeatherService {
/**
* Ensure future weather data exists
*/
protected validateWeatherDataExists() {
protected validateWeatherDataExists(currentSeason: Season) {
// Clear expired weather data
this.weatherForecast = this.weatherForecast.filter((x) => x.timestamp < this.timeUtil.getTimestamp());
@ -87,7 +100,7 @@ export class RaidWeatherService {
const result = this.weatherForecast.filter((x) => x.timestamp >= this.timeUtil.getTimestamp());
if (result.length === 0) {
// TODO - replace with better check, if < 1 hours worth of data exists?
this.generateWeather();
this.generateWeather(currentSeason);
}
}
}

View File

@ -232,6 +232,10 @@ export class SeasonalEventService {
}
public getActiveWeatherSeason(): Season {
if (this.weatherConfig.overrideSeason !== null) {
return this.weatherConfig.overrideSeason;
}
const currentDate = new Date();
for (const seasonRange of this.weatherConfig.seasonDates) {
// Figure out start and end dates to get range of season