152 lines
4.3 KiB
TypeScript
152 lines
4.3 KiB
TypeScript
import { Server } from 'socket.io'
|
|
|
|
import Logger, { LoggerType } from '#application/logger'
|
|
import { World } from '#entities/world'
|
|
import SocketManager from '#managers/socketManager'
|
|
import WorldRepository from '#repositories/worldRepository'
|
|
|
|
type WeatherState = {
|
|
rainPercentage: number
|
|
fogDensity: number
|
|
}
|
|
|
|
class WeatherManager {
|
|
private static readonly CONFIG = {
|
|
UPDATE_INTERVAL_MS: 60_000, // Check weather every minute
|
|
RAIN_CHANCE: 0.2, // 20% chance
|
|
FOG_CHANCE: 0.15, // 15% chance
|
|
RAIN_PERCENTAGE_RANGE: { min: 50, max: 100 },
|
|
FOG_DENSITY_RANGE: { min: 30, max: 100 }
|
|
} as const
|
|
|
|
private readonly logger = Logger.type(LoggerType.APP)
|
|
private io: Server | null = null
|
|
private intervalId: NodeJS.Timeout | null = null
|
|
|
|
private weatherState: WeatherState = {
|
|
rainPercentage: 0,
|
|
fogDensity: 0
|
|
}
|
|
|
|
public async boot(): Promise<void> {
|
|
this.io = SocketManager.getIO()
|
|
await this.loadWeather()
|
|
this.startWeatherLoop()
|
|
this.logger.info('Weather manager loaded')
|
|
}
|
|
|
|
public getWeatherState(): WeatherState {
|
|
return { ...this.weatherState }
|
|
}
|
|
|
|
public randomWeatherValue(type: 'rain' | 'fog' ) {
|
|
switch (type) {
|
|
case 'rain':
|
|
return this.getRandomNumber(WeatherManager.CONFIG.RAIN_PERCENTAGE_RANGE.min, WeatherManager.CONFIG.RAIN_PERCENTAGE_RANGE.max)
|
|
case 'fog':
|
|
return this.getRandomNumber(WeatherManager.CONFIG.FOG_DENSITY_RANGE.min, WeatherManager.CONFIG.FOG_DENSITY_RANGE.max)
|
|
}
|
|
}
|
|
|
|
public async setRainValue(value? : number): Promise<void> {
|
|
if (value === undefined) {
|
|
value = this.weatherState.fogDensity > 0 ? 0 : this.randomWeatherValue('fog')
|
|
}
|
|
|
|
this.updateWeatherProperty('rain', value)
|
|
await this.saveAndEmitWeather()
|
|
}
|
|
|
|
public async setFogValue(value? : number): Promise<void> {
|
|
if (value === undefined) {
|
|
value = this.weatherState.fogDensity > 0 ? 0 : this.randomWeatherValue('fog')
|
|
}
|
|
|
|
this.updateWeatherProperty('fog', value)
|
|
await this.saveAndEmitWeather()
|
|
}
|
|
|
|
public cleanup(): void {
|
|
this.intervalId && clearInterval(this.intervalId)
|
|
}
|
|
|
|
private async loadWeather(): Promise<void> {
|
|
try {
|
|
const worldRepository = new WorldRepository()
|
|
const world = await worldRepository.getFirst()
|
|
if (world) {
|
|
this.weatherState = {
|
|
rainPercentage: world.rainPercentage,
|
|
fogDensity: world.fogDensity
|
|
}
|
|
}
|
|
} catch (error) {
|
|
this.logError('load', error)
|
|
}
|
|
}
|
|
|
|
private startWeatherLoop(): void {
|
|
this.intervalId = setInterval(async () => {
|
|
this.updateRandomWeather()
|
|
await this.saveAndEmitWeather()
|
|
}, WeatherManager.CONFIG.UPDATE_INTERVAL_MS)
|
|
}
|
|
|
|
private updateRandomWeather(): void {
|
|
if (Math.random() < WeatherManager.CONFIG.RAIN_CHANCE) {
|
|
this.updateWeatherProperty('rain', this.randomWeatherValue('rain') )
|
|
}
|
|
if (Math.random() < WeatherManager.CONFIG.FOG_CHANCE) {
|
|
this.updateWeatherProperty('fog', this.randomWeatherValue('fog'))
|
|
}
|
|
}
|
|
|
|
private updateWeatherProperty(type: 'rain' | 'fog', value: number): void {
|
|
if (type === 'rain') {
|
|
this.weatherState.rainPercentage = value
|
|
}
|
|
|
|
if (type === 'fog') {
|
|
this.weatherState.fogDensity = value
|
|
}
|
|
}
|
|
|
|
private async saveAndEmitWeather(): Promise<void> {
|
|
await this.saveWeather()
|
|
this.emitWeather()
|
|
}
|
|
|
|
private emitWeather(): void {
|
|
this.io?.emit('weather', this.weatherState)
|
|
}
|
|
|
|
private async saveWeather(): Promise<void> {
|
|
try {
|
|
const worldRepository = new WorldRepository()
|
|
|
|
let world = await worldRepository.getFirst()
|
|
if (!world) world = new World()
|
|
|
|
//left them in here because the
|
|
await world
|
|
.setRainPercentage(this.weatherState.rainPercentage)
|
|
.setIsRainEnabled(this.weatherState.rainPercentage > 0)
|
|
.setFogDensity(this.weatherState.fogDensity)
|
|
.setIsFogEnabled(this.weatherState.fogDensity > 0)
|
|
.save()
|
|
} catch (error) {
|
|
this.logError('save', error)
|
|
}
|
|
}
|
|
|
|
private getRandomNumber(min: number, max: number): number {
|
|
return Math.floor(Math.random() * (max - min + 1)) + min
|
|
}
|
|
|
|
private logError(operation: string, error: unknown): void {
|
|
this.logger.error(`Failed to ${operation} weather: ${error instanceof Error ? error.message : String(error)}`)
|
|
}
|
|
}
|
|
|
|
export default new WeatherManager()
|