forked from noxious/server
128 lines
3.8 KiB
TypeScript
128 lines
3.8 KiB
TypeScript
import { Server } from 'socket.io'
|
|
import { appLogger } from '../utilities/logger'
|
|
import worldService from '../services/worldService'
|
|
import worldRepository from '../repositories/worldRepository'
|
|
|
|
interface WeatherState {
|
|
isRainEnabled: boolean
|
|
rainPercentage: number
|
|
isFogEnabled: boolean
|
|
fogDensity: number
|
|
}
|
|
|
|
class WeatherManager {
|
|
private static readonly UPDATE_INTERVAL = 60000 // Check weather every minute
|
|
private static readonly RAIN_CHANCE = 0.2 // 20% chance of rain
|
|
private static readonly FOG_CHANCE = 0.15 // 15% chance of fog
|
|
|
|
private io: Server | null = null
|
|
private intervalId: NodeJS.Timeout | null = null
|
|
private weatherState: WeatherState = {
|
|
isRainEnabled: false,
|
|
rainPercentage: 0,
|
|
isFogEnabled: false,
|
|
fogDensity: 0
|
|
}
|
|
|
|
public async boot(io: Server): Promise<void> {
|
|
this.io = io
|
|
await this.loadWeather()
|
|
this.startWeatherLoop()
|
|
appLogger.info('Weather manager loaded')
|
|
}
|
|
|
|
public async toggleRain(): Promise<void> {
|
|
this.weatherState.isRainEnabled = !this.weatherState.isRainEnabled
|
|
this.weatherState.rainPercentage = this.weatherState.isRainEnabled
|
|
? Math.floor(Math.random() * 50) + 50 // 50-100%
|
|
: 0
|
|
|
|
await this.saveWeather()
|
|
this.emitWeather()
|
|
}
|
|
|
|
public async toggleFog(): Promise<void> {
|
|
this.weatherState.isFogEnabled = !this.weatherState.isFogEnabled
|
|
this.weatherState.fogDensity = this.weatherState.isFogEnabled
|
|
? Math.floor((Math.random() * 0.7 + 0.3) * 100) // Convert 0.3-1.0 to 30-100
|
|
: 0
|
|
|
|
await this.saveWeather()
|
|
this.emitWeather()
|
|
}
|
|
|
|
private async loadWeather(): Promise<void> {
|
|
try {
|
|
const world = await worldRepository.getFirst()
|
|
|
|
if (world) {
|
|
this.weatherState = {
|
|
isRainEnabled: world.isRainEnabled,
|
|
rainPercentage: world.rainPercentage,
|
|
isFogEnabled: world.isFogEnabled,
|
|
fogDensity: world.fogDensity
|
|
}
|
|
}
|
|
} catch (error) {
|
|
appLogger.error(`Failed to load weather: ${error instanceof Error ? error.message : String(error)}`)
|
|
}
|
|
}
|
|
|
|
public getWeatherState(): WeatherState {
|
|
return this.weatherState
|
|
}
|
|
|
|
private startWeatherLoop(): void {
|
|
this.intervalId = setInterval(async () => {
|
|
this.updateWeather()
|
|
this.emitWeather()
|
|
await this.saveWeather().catch((error) => {
|
|
appLogger.error(`Failed to save weather: ${error instanceof Error ? error.message : String(error)}`)
|
|
})
|
|
}, WeatherManager.UPDATE_INTERVAL)
|
|
}
|
|
|
|
private updateWeather(): void {
|
|
// Update rain
|
|
if (Math.random() < WeatherManager.RAIN_CHANCE) {
|
|
this.weatherState.isRainEnabled = !this.weatherState.isRainEnabled
|
|
this.weatherState.rainPercentage = this.weatherState.isRainEnabled
|
|
? Math.floor(Math.random() * 50) + 50 // 50-100%
|
|
: 0
|
|
}
|
|
|
|
// Update fog
|
|
if (Math.random() < WeatherManager.FOG_CHANCE) {
|
|
this.weatherState.isFogEnabled = !this.weatherState.isFogEnabled
|
|
this.weatherState.fogDensity = this.weatherState.isFogEnabled
|
|
? Math.floor((Math.random() * 0.7 + 0.3) * 100) // Convert 0.3-1.0 to 30-100
|
|
: 0
|
|
}
|
|
}
|
|
|
|
private emitWeather(): void {
|
|
this.io?.emit('weather', this.weatherState)
|
|
}
|
|
|
|
private async saveWeather(): Promise<void> {
|
|
try {
|
|
await worldService.update({
|
|
isRainEnabled: this.weatherState.isRainEnabled,
|
|
rainPercentage: this.weatherState.rainPercentage,
|
|
isFogEnabled: this.weatherState.isFogEnabled,
|
|
fogDensity: this.weatherState.fogDensity
|
|
})
|
|
} catch (error) {
|
|
appLogger.error(`Failed to save weather: ${error instanceof Error ? error.message : String(error)}`)
|
|
}
|
|
}
|
|
|
|
public cleanup(): void {
|
|
if (this.intervalId) {
|
|
clearInterval(this.intervalId)
|
|
}
|
|
}
|
|
}
|
|
|
|
export default new WeatherManager()
|