forked from noxious/server
#184: Added weather manager that periodically changes the weather in-game and emits this to players
This commit is contained in:
parent
3a566dae5a
commit
ae0241fecb
@ -0,0 +1,98 @@
|
||||
import { Server } from 'socket.io'
|
||||
import { appLogger } from '../utilities/logger'
|
||||
import { getRootPath } from '../utilities/storage'
|
||||
import { readJsonValue, setJsonValue } from '../utilities/json'
|
||||
|
||||
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')
|
||||
}
|
||||
|
||||
private async loadWeather(): Promise<void> {
|
||||
try {
|
||||
this.weatherState.isRainEnabled = await readJsonValue<boolean>(this.getWorldFilePath(), 'isRainEnabled')
|
||||
this.weatherState.rainPercentage = await readJsonValue<number>(this.getWorldFilePath(), 'rainPercentage')
|
||||
this.weatherState.isFogEnabled = await readJsonValue<boolean>(this.getWorldFilePath(), 'isFogEnabled')
|
||||
this.weatherState.fogDensity = await readJsonValue<number>(this.getWorldFilePath(), 'fogDensity')
|
||||
} catch (error) {
|
||||
appLogger.error(`Failed to load weather: ${error instanceof Error ? error.message : String(error)}`)
|
||||
}
|
||||
}
|
||||
|
||||
public async getWeatherState(): Promise<WeatherState> {
|
||||
return this.weatherState
|
||||
}
|
||||
|
||||
private startWeatherLoop(): void {
|
||||
this.intervalId = setInterval(() => {
|
||||
this.updateWeather()
|
||||
this.emitWeather()
|
||||
this.saveWeather()
|
||||
}, 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.random() * 0.7 + 0.3 // 0.3-1.0
|
||||
: 0
|
||||
}
|
||||
}
|
||||
|
||||
private emitWeather(): void {
|
||||
this.io?.emit('weather', this.weatherState)
|
||||
}
|
||||
|
||||
private async saveWeather(): Promise<void> {
|
||||
try {
|
||||
const promises = [
|
||||
await setJsonValue(this.getWorldFilePath(), 'isRainEnabled', this.weatherState.isRainEnabled),
|
||||
await setJsonValue(this.getWorldFilePath(), 'rainPercentage', this.weatherState.rainPercentage),
|
||||
await setJsonValue(this.getWorldFilePath(), 'isFogEnabled', this.weatherState.isFogEnabled),
|
||||
await setJsonValue(this.getWorldFilePath(), 'fogDensity', this.weatherState.fogDensity)
|
||||
]
|
||||
await Promise.all(promises)
|
||||
} catch (error) {
|
||||
appLogger.error(`Failed to save weather: ${error instanceof Error ? error.message : String(error)}`)
|
||||
}
|
||||
}
|
||||
|
||||
private getWorldFilePath(): string {
|
||||
return getRootPath('data', 'world.json')
|
||||
}
|
||||
}
|
||||
|
||||
export default new WeatherManager()
|
@ -16,6 +16,7 @@ import CommandManager from './managers/commandManager'
|
||||
import CharacterManager from './managers/characterManager'
|
||||
import QueueManager from './managers/queueManager'
|
||||
import DateManager from './managers/dateManager'
|
||||
import WeatherManager from './managers/weatherManager'
|
||||
|
||||
export class Server {
|
||||
private readonly app: Application
|
||||
@ -72,6 +73,9 @@ export class Server {
|
||||
// Load date manager
|
||||
await DateManager.boot(this.io)
|
||||
|
||||
// Load weather manager
|
||||
await WeatherManager.boot(this.io)
|
||||
|
||||
// Load zoneEditor manager
|
||||
await ZoneManager.boot()
|
||||
|
||||
|
24
src/socketEvents/weather.ts
Normal file
24
src/socketEvents/weather.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { Server } from 'socket.io'
|
||||
import { TSocket } from '../utilities/types'
|
||||
import { gameLogger } from '../utilities/logger'
|
||||
import WeatherManager from '../managers/weatherManager'
|
||||
|
||||
export default class Weather {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('weather', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(): Promise<void> {
|
||||
try {
|
||||
const weather = await WeatherManager.getWeatherState()
|
||||
this.socket.emit('weather', weather)
|
||||
} catch (error: any) {
|
||||
gameLogger.error('error', error.message)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user