#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 CharacterManager from './managers/characterManager'
|
||||||
import QueueManager from './managers/queueManager'
|
import QueueManager from './managers/queueManager'
|
||||||
import DateManager from './managers/dateManager'
|
import DateManager from './managers/dateManager'
|
||||||
|
import WeatherManager from './managers/weatherManager'
|
||||||
|
|
||||||
export class Server {
|
export class Server {
|
||||||
private readonly app: Application
|
private readonly app: Application
|
||||||
@ -72,6 +73,9 @@ export class Server {
|
|||||||
// Load date manager
|
// Load date manager
|
||||||
await DateManager.boot(this.io)
|
await DateManager.boot(this.io)
|
||||||
|
|
||||||
|
// Load weather manager
|
||||||
|
await WeatherManager.boot(this.io)
|
||||||
|
|
||||||
// Load zoneEditor manager
|
// Load zoneEditor manager
|
||||||
await ZoneManager.boot()
|
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