Moved values into config

moved code to more appropriate locations
Reduced duplicate code
Added comments
This commit is contained in:
Dev 2024-10-17 10:27:37 +01:00
parent 3d4c7795f7
commit eb6e61c1f0
4 changed files with 79 additions and 41 deletions

View File

@ -1,6 +1,7 @@
{ {
"acceleration": 7, "acceleration": 7,
"weather": { "weather": {
"generateWeatherAmountHours": 24,
"clouds": { "clouds": {
"values": [-1.5, -1, 0, 0.5, 1, 1.5], "values": [-1.5, -1, 0, 0.5, 1, 1.5],
"weights": [60, 50, 15, 5, 4, 3] "weights": [60, 50, 15, 5, 4, 3]
@ -36,7 +37,11 @@
"pressure": { "pressure": {
"min": 760, "min": 760,
"max": 764 "max": 764
} },
"timePeriod": {
"values": [15, 30],
"weights": [1, 2]
}
}, },
"seasonDates": [ "seasonDates": [
{ {

View File

@ -6,7 +6,7 @@ import { IBaseConfig } from "@spt/models/spt/config/IBaseConfig";
export interface IWeatherConfig extends IBaseConfig { export interface IWeatherConfig extends IBaseConfig {
kind: "spt-weather"; kind: "spt-weather";
acceleration: number; acceleration: number;
weather: Weather; weather: IWeatherValues;
seasonDates: ISeasonDateTimes[]; seasonDates: ISeasonDateTimes[];
overrideSeason?: Season; overrideSeason?: Season;
} }
@ -20,7 +20,9 @@ export interface ISeasonDateTimes {
endMonth: number; endMonth: number;
} }
export interface Weather { export interface IWeatherValues {
/** How many hours to generate weather data into the future */
generateWeatherAmountHours: number;
clouds: WeatherSettings<string>; clouds: WeatherSettings<string>;
windSpeed: WeatherSettings<number>; windSpeed: WeatherSettings<number>;
windDirection: WeatherSettings<WindDirection>; windDirection: WeatherSettings<WindDirection>;
@ -30,6 +32,8 @@ export interface Weather {
fog: WeatherSettings<string>; fog: WeatherSettings<string>;
temp: MinMax; temp: MinMax;
pressure: MinMax; pressure: MinMax;
/** Length of each weather period */
timePeriod: WeatherSettings<number>;
} }
export interface WeatherSettings<T> { export interface WeatherSettings<T> {

View File

@ -1,4 +1,5 @@
import { WeatherGenerator } from "@spt/generators/WeatherGenerator"; import { WeatherGenerator } from "@spt/generators/WeatherGenerator";
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
import { IWeather } from "@spt/models/eft/weather/IWeatherData"; import { IWeather } from "@spt/models/eft/weather/IWeatherData";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes"; import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { IWeatherConfig } from "@spt/models/spt/config/IWeatherConfig"; import { IWeatherConfig } from "@spt/models/spt/config/IWeatherConfig";
@ -18,6 +19,7 @@ export class RaidWeatherService {
@inject("DatabaseService") protected databaseService: DatabaseService, @inject("DatabaseService") protected databaseService: DatabaseService,
@inject("TimeUtil") protected timeUtil: TimeUtil, @inject("TimeUtil") protected timeUtil: TimeUtil,
@inject("WeatherGenerator") protected weatherGenerator: WeatherGenerator, @inject("WeatherGenerator") protected weatherGenerator: WeatherGenerator,
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
@inject("ConfigServer") protected configServer: ConfigServer, @inject("ConfigServer") protected configServer: ConfigServer,
) { ) {
this.weatherConfig = this.configServer.getConfig(ConfigTypes.WEATHER); this.weatherConfig = this.configServer.getConfig(ConfigTypes.WEATHER);
@ -25,62 +27,67 @@ export class RaidWeatherService {
this.generateWeather(); this.generateWeather();
} }
/**
* Generate 24 hours of weather data starting from midnight today
*/
public generateWeather() { public generateWeather() {
// When to start generating weather from // When to start generating weather from in milliseconds
const staringTimestamp = this.getLastFullHourTimestamp(); const staringTimestampMs = this.timeUtil.getTodaysMidnightTimestamp();
// How far into future do we generate weather // How far into future do we generate weather
const futureTimestampToReach = staringTimestamp + this.timeUtil.getHoursAsSeconds(24) * 1000; // TODO move 24 to config const futureTimestampToReachMs =
staringTimestampMs +
this.timeUtil.getHoursAsSeconds(this.weatherConfig.weather.generateWeatherAmountHours) * 1000; // Convert to milliseconds
// Keep adding new weather until we have reached desired future date // Keep adding new weather until we have reached desired future date
let nextTimestamp = staringTimestamp; let nextTimestampMs = staringTimestampMs;
while (nextTimestamp <= futureTimestampToReach) { while (nextTimestampMs <= futureTimestampToReachMs) {
const newWeather = this.weatherGenerator.generateWeather(nextTimestamp); const newWeather = this.weatherGenerator.generateWeather(nextTimestampMs);
this.logger.warning(`Handling ${new Date(nextTimestamp)}`); this.logger.warning(`Handling ${new Date(nextTimestampMs)}`);
this.weatherForecast.push(newWeather); this.weatherForecast.push(newWeather);
nextTimestamp += 30 * 60 * 1000; // TODO move to config nextTimestampMs += this.getWeightedWeatherTimePeriodMs();
} }
} }
protected getLastFullHourTimestamp() { protected getWeightedWeatherTimePeriodMs(): number {
const now = new Date(); const chosenTimePeriodMinutes = this.weightedRandomHelper.weightedRandom(
let hours = now.getHours(); this.weatherConfig.weather.timePeriod.values,
const minutes = now.getMinutes(); this.weatherConfig.weather.timePeriod.weights,
).item;
// If minutes are greater than 0, subtract 1 hour to get last full hour return chosenTimePeriodMinutes * 60 * 1000; // Convert to milliseconds
if (minutes > 0) {
hours--;
}
// Create a new Date object with the last full hour, 0 minutes, and 0 seconds
const lastFullHour = new Date(now.getFullYear(), now.getMonth(), now.getDate(), hours, 0, 0);
// Return timestamp of last full hour
return lastFullHour.getTime();
} }
/**
* Find the first matching weather object that applies to the current time
*/
public getCurrentWeather(): IWeather { public getCurrentWeather(): IWeather {
// Clear expired weather data this.validateWeatherDataExists();
this.weatherForecast = this.weatherForecast.filter((x) => x.timestamp < this.timeUtil.getTimestamp());
// return first weather object that is greater than/equal to now
const result = this.weatherForecast.find((x) => x.timestamp >= this.timeUtil.getTimestamp());
if (!result) {
this.generateWeather();
}
return this.weatherForecast.find((x) => x.timestamp >= this.timeUtil.getTimestamp()); return this.weatherForecast.find((x) => x.timestamp >= this.timeUtil.getTimestamp());
} }
/**
* Find the first matching weather object that applies to the current time + all following weather data generated
*/
public getUpcomingWeather(): IWeather[] { public getUpcomingWeather(): IWeather[] {
// Clear expired weather data this.validateWeatherDataExists();
this.weatherForecast = this.weatherForecast.filter((x) => x.timestamp < this.timeUtil.getTimestamp());
// return first weather object that is greater than/equal to now
const result = this.weatherForecast.filter((x) => x.timestamp >= this.timeUtil.getTimestamp());
if (result.length === 0) {
this.generateWeather();
}
return this.weatherForecast.filter((x) => x.timestamp >= this.timeUtil.getTimestamp()); return this.weatherForecast.filter((x) => x.timestamp >= this.timeUtil.getTimestamp());
} }
/**
* Ensure future weather data exists
*/
protected validateWeatherDataExists() {
// Clear expired weather data
this.weatherForecast = this.weatherForecast.filter((x) => x.timestamp < this.timeUtil.getTimestamp());
// Check data exists for current time
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();
}
}
} }

View File

@ -138,4 +138,26 @@ export class TimeUtil {
(60 - now.getMinutes()) * 60 * 1000 - now.getSeconds() * 1000 - now.getMilliseconds(); (60 - now.getMinutes()) * 60 * 1000 - now.getSeconds() * 1000 - now.getMilliseconds();
return (now.getTime() + millisecondsUntilNextHour) / 1000; return (now.getTime() + millisecondsUntilNextHour) / 1000;
} }
/**
* Returns the current days timestamp at 00:00
* e.g. current time: 13th march 14:22 will return 13th march 00:00
* @returns Timestamp
*/
public getTodaysMidnightTimestamp(): number {
const now = new Date();
let hours = now.getHours();
const minutes = now.getMinutes();
// If minutes greater than 0, subtract 1 hour to get last full hour
if (minutes > 0) {
hours--;
}
// Create a new Date object with the last full hour, 0 minutes, and 0 seconds
const lastFullHour = new Date(now.getFullYear(), now.getMonth(), now.getDate(), hours, 0, 0);
// Return above as timestamp
return lastFullHour.getTime();
}
} }