From c4a42066abe424dc6c32eb2c5d1302f35083948d Mon Sep 17 00:00:00 2001 From: Dennis Postma Date: Tue, 5 Nov 2024 23:15:56 +0100 Subject: [PATCH] #184: Added commands to toggle rain / fog, command bug fix, minor improvements --- src/managers/weatherManager.ts | 30 ++++++++++- .../chat/gameMaster/alertCommand.ts | 20 +++++--- .../chat/gameMaster/teleportCommand.ts | 18 +++++-- .../chat/gameMaster/toggleFogCommand.ts | 51 +++++++++++++++++++ .../chat/gameMaster/toggleRainCommand.ts | 51 +++++++++++++++++++ src/utilities/chat.ts | 2 +- 6 files changed, 160 insertions(+), 12 deletions(-) create mode 100644 src/socketEvents/chat/gameMaster/toggleFogCommand.ts create mode 100644 src/socketEvents/chat/gameMaster/toggleRainCommand.ts diff --git a/src/managers/weatherManager.ts b/src/managers/weatherManager.ts index 4de93e4..f4bfcac 100644 --- a/src/managers/weatherManager.ts +++ b/src/managers/weatherManager.ts @@ -31,6 +31,32 @@ class WeatherManager { appLogger.info('Weather manager loaded') } + public async toggleRain(): Promise { + this.weatherState.isRainEnabled = !this.weatherState.isRainEnabled + this.weatherState.rainPercentage = this.weatherState.isRainEnabled + ? Math.floor(Math.random() * 50) + 50 // 50-100% + : 0 + + // Save weather + await this.saveWeather() + + // Emit weather + this.emitWeather() + } + + public async toggleFog(): Promise { + this.weatherState.isFogEnabled = !this.weatherState.isFogEnabled + this.weatherState.fogDensity = this.weatherState.isFogEnabled + ? Math.random() * 0.7 + 0.3 // 0.3-1.0 + : 0 + + // Save weather + await this.saveWeather() + + // Emit weather + this.emitWeather() + } + private async loadWeather(): Promise { try { this.weatherState.isRainEnabled = await readJsonValue(this.getWorldFilePath(), 'isRainEnabled') @@ -50,7 +76,9 @@ class WeatherManager { this.intervalId = setInterval(() => { this.updateWeather() this.emitWeather() - this.saveWeather() + this.saveWeather().catch((error) => { + appLogger.error(`Failed to save weather: ${error instanceof Error ? error.message : String(error)}`) + }) }, WeatherManager.UPDATE_INTERVAL) } diff --git a/src/socketEvents/chat/gameMaster/alertCommand.ts b/src/socketEvents/chat/gameMaster/alertCommand.ts index 7c7c9c1..ede3552 100644 --- a/src/socketEvents/chat/gameMaster/alertCommand.ts +++ b/src/socketEvents/chat/gameMaster/alertCommand.ts @@ -24,16 +24,24 @@ export default class AlertCommandEvent { return } - const args = getArgs('alert', data.message) - - if (!args) { + // Check if character exists + const character = await CharacterRepository.getByUserAndId(this.socket.user?.id as number, this.socket.characterId as number) + if (!character) { + gameLogger.error('chat:alert_command error', 'Character not found') callback(false) return } - const character = await CharacterRepository.getByUserAndId(this.socket.user?.id as number, this.socket.characterId as number) - if (!character) { - gameLogger.error('chat:alert_command error', 'Character not found') + // Check if the user is the GM + if (character.role !== 'gm') { + gameLogger.info(`User ${character.id} tried to set time but is not a game master.`) + callback(false) + return + } + + const args = getArgs('alert', data.message) + + if (!args) { callback(false) return } diff --git a/src/socketEvents/chat/gameMaster/teleportCommand.ts b/src/socketEvents/chat/gameMaster/teleportCommand.ts index 1c0b0a6..e9bcef7 100644 --- a/src/socketEvents/chat/gameMaster/teleportCommand.ts +++ b/src/socketEvents/chat/gameMaster/teleportCommand.ts @@ -1,9 +1,10 @@ import { Server } from 'socket.io' -import { TSocket } from '../../../utilities/types' +import { ExtendedCharacter, TSocket } from '../../../utilities/types' import { getArgs, isCommand } from '../../../utilities/chat' import ZoneRepository from '../../../repositories/zoneRepository' import CharacterManager from '../../../managers/characterManager' -import { gameMasterLogger } from '../../../utilities/logger' +import { gameLogger, gameMasterLogger } from '../../../utilities/logger' +import CharacterRepository from '../../../repositories/characterRepository' type TypePayload = { message: string @@ -21,9 +22,18 @@ export default class TeleportCommandEvent { private async handleTeleportCommand(data: TypePayload, callback: (response: boolean) => void): Promise { try { - const character = CharacterManager.getCharacterFromSocket(this.socket) + // Check if character exists + const character = await CharacterRepository.getByUserAndId(this.socket.user?.id as number, this.socket.characterId as number) as ExtendedCharacter if (!character) { - this.socket.emit('notification', { title: 'Server message', message: 'Character not found' }) + gameLogger.error('chat:alert_command error', 'Character not found') + callback(false) + return + } + + // Check if the user is the GM + if (character.role !== 'gm') { + gameLogger.info(`User ${character.id} tried to set time but is not a game master.`) + callback(false) return } diff --git a/src/socketEvents/chat/gameMaster/toggleFogCommand.ts b/src/socketEvents/chat/gameMaster/toggleFogCommand.ts new file mode 100644 index 0000000..f891843 --- /dev/null +++ b/src/socketEvents/chat/gameMaster/toggleFogCommand.ts @@ -0,0 +1,51 @@ +import { Server } from 'socket.io' +import { TSocket } from '../../../utilities/types' +import { isCommand } from '../../../utilities/chat' +import CharacterRepository from '../../../repositories/characterRepository' +import { gameLogger } from '../../../utilities/logger' +import WeatherManager from '../../../managers/weatherManager' + +type TypePayload = { + message: string +} + +export default class ToggleFogCommand { + constructor( + private readonly io: Server, + private readonly socket: TSocket + ) {} + + public listen(): void { + this.socket.on('chat:send_message', this.handleAlertCommand.bind(this)) + } + + private async handleAlertCommand(data: TypePayload, callback: (response: boolean) => void): Promise { + try { + if (!isCommand(data.message, 'fog')) { + return + } + + // Check if character exists + const character = await CharacterRepository.getByUserAndId(this.socket.user?.id as number, this.socket.characterId as number) + if (!character) { + gameLogger.error('chat:alert_command error', 'Character not found') + callback(false) + return + } + + // Check if the user is the GM + if (character.role !== 'gm') { + gameLogger.info(`User ${character.id} tried to set time but is not a game master.`) + callback(false) + return + } + + await WeatherManager.toggleFog() + + callback(true) + } catch (error: any) { + gameLogger.error('command error', error.message) + callback(false) + } + } +} diff --git a/src/socketEvents/chat/gameMaster/toggleRainCommand.ts b/src/socketEvents/chat/gameMaster/toggleRainCommand.ts new file mode 100644 index 0000000..5599c07 --- /dev/null +++ b/src/socketEvents/chat/gameMaster/toggleRainCommand.ts @@ -0,0 +1,51 @@ +import { Server } from 'socket.io' +import { TSocket } from '../../../utilities/types' +import { isCommand } from '../../../utilities/chat' +import CharacterRepository from '../../../repositories/characterRepository' +import { gameLogger } from '../../../utilities/logger' +import WeatherManager from '../../../managers/weatherManager' + +type TypePayload = { + message: string +} + +export default class ToggleRainCommand { + constructor( + private readonly io: Server, + private readonly socket: TSocket + ) {} + + public listen(): void { + this.socket.on('chat:send_message', this.handleAlertCommand.bind(this)) + } + + private async handleAlertCommand(data: TypePayload, callback: (response: boolean) => void): Promise { + try { + if (!isCommand(data.message, 'rain')) { + return + } + + // Check if character exists + const character = await CharacterRepository.getByUserAndId(this.socket.user?.id as number, this.socket.characterId as number) + if (!character) { + gameLogger.error('chat:alert_command error', 'Character not found') + callback(false) + return + } + + // Check if the user is the GM + if (character.role !== 'gm') { + gameLogger.info(`User ${character.id} tried to set time but is not a game master.`) + callback(false) + return + } + + await WeatherManager.toggleRain() + + callback(true) + } catch (error: any) { + gameLogger.error('command error', error.message) + callback(false) + } + } +} diff --git a/src/utilities/chat.ts b/src/utilities/chat.ts index 599bee9..416b89f 100644 --- a/src/utilities/chat.ts +++ b/src/utilities/chat.ts @@ -1,6 +1,6 @@ export function isCommand(message: string, command?: string) { if (command) { - return message.startsWith(`/${command} `) + return message === `/${command}` || message.startsWith(`/${command} `) } return message.startsWith('/') }