Server/project/src/generators/WeatherGenerator.ts

191 lines
6.8 KiB
TypeScript
Raw Normal View History

2023-03-03 15:23:46 +00:00
import { inject, injectable } from "tsyringe";
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
import { IWeather, IWeatherData } from "@spt-aki/models/eft/weather/IWeatherData";
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
import { WindDirection } from "@spt-aki/models/enums/WindDirection";
import { IWeatherConfig } from "@spt-aki/models/spt/config/IWeatherConfig";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
import { TimeUtil } from "@spt-aki/utils/TimeUtil";
2023-03-03 15:23:46 +00:00
@injectable()
export class WeatherGenerator
{
protected weatherConfig: IWeatherConfig;
constructor(
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
@inject("WinstonLogger") protected logger: ILogger,
@inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("TimeUtil") protected timeUtil: TimeUtil,
@inject("ApplicationContext") protected applicationContext: ApplicationContext,
2023-11-15 20:35:05 -05:00
@inject("ConfigServer") protected configServer: ConfigServer,
2023-03-03 15:23:46 +00:00
)
{
this.weatherConfig = this.configServer.getConfig(ConfigTypes.WEATHER);
}
2023-07-25 14:04:21 +01:00
/**
* Get current + raid datetime and format into correct BSG format and return
* @param data Weather data
* @returns IWeatherData
*/
2023-03-03 15:23:46 +00:00
public calculateGameTime(data: IWeatherData): IWeatherData
{
const computedDate = new Date();
const formattedDate = this.timeUtil.formatDate(computedDate);
data.date = formattedDate;
data.time = this.getBsgFormattedInRaidTime(computedDate);
data.acceleration = this.weatherConfig.acceleration;
data.winterEventEnabled = this.weatherConfig.forceWinterEvent;
2023-03-03 15:23:46 +00:00
return data;
}
/**
* Get server uptime seconds multiplied by a multiplier and add to current time as seconds
* Format to BSGs requirements
* @param currentDate current date
* @returns formatted time
*/
protected getBsgFormattedInRaidTime(currentDate: Date): string
{
const clientAcceleratedDate = this.getInRaidTime(currentDate);
return this.getBSGFormattedTime(clientAcceleratedDate);
}
/**
* Get the current in-raid time
* @param currentDate (new Date())
2023-11-15 20:35:05 -05:00
* @returns Date object of current in-raid time
2023-03-03 15:23:46 +00:00
*/
public getInRaidTime(currentDate: Date): Date
{
// Get timestamp of when client conneted to server
2023-11-15 20:35:05 -05:00
const gameStartTimeStampMS = this.applicationContext.getLatestValue(ContextVariableType.CLIENT_START_TIMESTAMP)
.getValue<number>();
2023-03-03 15:23:46 +00:00
// Get delta between now and when client connected to server in milliseconds
Adjust server raid time calculations to match client (!202) This change brings the server in raid time calculation (accelerated time/time you see when choosing a map) to parity with the client. The time returned by `getInRaidTime()` effectively is the same, but the server can stop using `acceleration - 1` and the adjacent comment has an answer. ----- The Tarkov client calculates current raid time via the following formula in `Session.GetCurrentLocationTime()`: `In Raid Time = Today's Date + Connection Time + Time Since Client Connection * Acceleration` The server currently uses the following: `In Raid Time = Current Date and Time + Time Since Client Connection * (Acceleration - 1)` The `Current Time` and `-1` used in the server calculation effectively cancel each other out if `acceleration > 1`. Removing both should have no effect on the calculated time (not date). The client side using `Today's Date + Connection Time` is kinda weird. Using `acceleration = 1`, you'd see the calculated date move 2 days after 24 hours. That said, I don't see the date portion of the raid time being used, so that might not matter. Either way, I've matched the formula to avoid any edge cases causing desync. Co-authored-by: OkaMoez <43766412+OkaMoez@users.noreply.github.com> Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/202 Co-authored-by: OkaMoez <okamoez@noreply.dev.sp-tarkov.com> Co-committed-by: OkaMoez <okamoez@noreply.dev.sp-tarkov.com> (cherry picked from commit afb64c1ebf20505bf3c91143aa4c8e6b65aac21c)
2024-01-20 09:59:23 +00:00
const deltaMSFromNow = currentDate.getTime() - gameStartTimeStampMS;
const acceleratedMS = deltaMSFromNow * (this.weatherConfig.acceleration);
// Match client side time calculations which start from the current date + connection time, not current time
const locationTime = new Date(gameStartTimeStampMS);
locationTime.setFullYear(currentDate.getFullYear());
locationTime.setMonth(currentDate.getMonth());
locationTime.setDate(currentDate.getDate());
const clientAcceleratedDate = new Date(locationTime.getTime() + acceleratedMS);
2023-03-03 15:23:46 +00:00
return clientAcceleratedDate;
}
/**
* Get current time formatted to fit BSGs requirement
* @param date date to format into bsg style
2023-07-25 14:04:21 +01:00
* @returns Time formatted in BSG format
2023-03-03 15:23:46 +00:00
*/
protected getBSGFormattedTime(date: Date): string
{
return this.timeUtil.formatTime(date).replace("-", ":").replace("-", ":");
}
/**
* Return randomised Weather data with help of config/weather.json
* @returns Randomised weather data
*/
public generateWeather(): IWeather
{
const rain = this.getWeightedRain();
const result: IWeather = {
cloud: this.getWeightedClouds(),
2023-03-03 15:23:46 +00:00
wind_speed: this.getWeightedWindSpeed(),
wind_direction: this.getWeightedWindDirection(),
wind_gustiness: this.getRandomFloat("windGustiness"),
rain: rain,
2023-11-15 20:35:05 -05:00
rain_intensity: (rain > 1) ? this.getRandomFloat("rainIntensity") : 0,
2023-03-03 15:23:46 +00:00
fog: this.getWeightedFog(),
temp: this.getRandomFloat("temp"),
pressure: this.getRandomFloat("pressure"),
time: "",
date: "",
2023-11-15 20:35:05 -05:00
timestamp: 0,
2023-03-03 15:23:46 +00:00
};
this.setCurrentDateTime(result);
return result;
}
/**
* Set IWeather date/time/timestamp values to now
* @param weather Object to update
*/
protected setCurrentDateTime(weather: IWeather): void
{
const currentDate = this.getInRaidTime(new Date());
const normalTime = this.getBSGFormattedTime(currentDate);
const formattedDate = this.timeUtil.formatDate(currentDate);
const datetime = `${formattedDate} ${normalTime}`;
weather.timestamp = Math.floor(currentDate.getTime() / 1000); // matches weather.date
weather.date = formattedDate; // matches weather.timestamp
weather.time = datetime; // matches weather.timestamp
}
protected getWeightedWindDirection(): WindDirection
{
2023-11-15 20:35:05 -05:00
return this.weightedRandomHelper.weightedRandom(
this.weatherConfig.weather.windDirection.values,
this.weatherConfig.weather.windDirection.weights,
).item;
2023-03-03 15:23:46 +00:00
}
protected getWeightedClouds(): number
{
2023-11-15 20:35:05 -05:00
return this.weightedRandomHelper.weightedRandom(
this.weatherConfig.weather.clouds.values,
this.weatherConfig.weather.clouds.weights,
).item;
}
2023-03-03 15:23:46 +00:00
protected getWeightedWindSpeed(): number
{
2023-11-15 20:35:05 -05:00
return this.weightedRandomHelper.weightedRandom(
this.weatherConfig.weather.windSpeed.values,
this.weatherConfig.weather.windSpeed.weights,
).item;
2023-03-03 15:23:46 +00:00
}
protected getWeightedFog(): number
{
2023-11-15 20:35:05 -05:00
return this.weightedRandomHelper.weightedRandom(
this.weatherConfig.weather.fog.values,
this.weatherConfig.weather.fog.weights,
).item;
2023-03-03 15:23:46 +00:00
}
protected getWeightedRain(): number
{
2023-11-15 20:35:05 -05:00
return this.weightedRandomHelper.weightedRandom(
this.weatherConfig.weather.rain.values,
this.weatherConfig.weather.rain.weights,
).item;
2023-03-03 15:23:46 +00:00
}
protected getRandomFloat(node: string): number
{
2023-11-15 20:35:05 -05:00
return parseFloat(
this.randomUtil.getFloat(this.weatherConfig.weather[node].min, this.weatherConfig.weather[node].max)
.toPrecision(3),
);
2023-03-03 15:23:46 +00:00
}
2023-11-15 20:35:05 -05:00
}