From 39d793570d22812c0f23428116bced94555bbdb6 Mon Sep 17 00:00:00 2001 From: Dennis Postma Date: Wed, 19 Feb 2025 11:45:43 +0100 Subject: [PATCH] #244: Allow nickname changes --- src/application/base/baseEvent.ts | 5 +++-- src/application/zodTypes.ts | 13 +++++++++++++ src/events/character/connect.ts | 20 +++++++++++++++++++- src/events/character/create.ts | 2 +- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/application/base/baseEvent.ts b/src/application/base/baseEvent.ts index dc0efaa..e309089 100644 --- a/src/application/base/baseEvent.ts +++ b/src/application/base/baseEvent.ts @@ -46,14 +46,15 @@ export abstract class BaseEvent { } protected sendNotificationAndLog(message: string): void { + console.log(message) this.socket.emit(SocketEvent.NOTIFICATION, { title: 'Server message', message }) - this.logger.error('Base event error', `Player ${this.socket.userId}: ${message}`) + this.logger.error('Base event error' + `Player ${this.socket.userId}: ${message}`) } protected handleError(context: string, error: unknown): void { console.log(error) const errorMessage = error instanceof Error ? error.message : error && typeof error === 'object' && 'toString' in error ? error.toString() : String(error) this.socket.emit(SocketEvent.NOTIFICATION, { title: 'Server message', message: `Server error occured. Please contact the server administrator.` }) - this.logger.error('Base event error', errorMessage) + this.logger.error('Base event error: ' + errorMessage) } } diff --git a/src/application/zodTypes.ts b/src/application/zodTypes.ts index 7252173..a2010ab 100644 --- a/src/application/zodTypes.ts +++ b/src/application/zodTypes.ts @@ -58,3 +58,16 @@ export const ZCharacterCreate = z.object({ .max(255, { message: 'Name must be at most 255 characters long' }) .regex(/^[A-Za-z][A-Za-z0-9_-]*$/, { message: 'Name must start with a letter and can only contain letters, numbers, underscores, or dashes' }) }) + +export const ZCharacterConnect = z.object({ + characterId: z.string(), + characterHairId: z.string().optional(), + newNickname: z + .string() + .min(3, { message: 'Name must be at least 3 characters long' }) + .max(255, { message: 'Name must be at most 255 characters long' }) + .regex(/^[A-Za-z][A-Za-z0-9_-]*$/, { + message: 'Name must start with a letter and can only contain letters, numbers, underscores, or dashes' + }) + .optional() +}) diff --git a/src/events/character/connect.ts b/src/events/character/connect.ts index d9059dc..95d777d 100644 --- a/src/events/character/connect.ts +++ b/src/events/character/connect.ts @@ -1,6 +1,7 @@ import { BaseEvent } from '@/application/base/baseEvent' import { SocketEvent } from '@/application/enums' import type { UUID } from '@/application/types' +import { ZCharacterConnect } from '@/application/zodTypes' import MapManager from '@/managers/mapManager' import CharacterHairRepository from '@/repositories/characterHairRepository' import CharacterRepository from '@/repositories/characterRepository' @@ -9,6 +10,7 @@ import TeleportService from '@/services/characterTeleportService' interface CharacterConnectPayload { characterId: UUID characterHairId?: UUID + newNickname?: string } export default class CharacterConnectEvent extends BaseEvent { @@ -21,18 +23,34 @@ export default class CharacterConnectEvent extends BaseEvent { private async handleEvent(data: CharacterConnectPayload, callback: (response: any) => void): Promise { try { + const result = ZCharacterConnect.safeParse(data) + if (!result.success) { + this.sendNotificationAndLog(result.error?.errors[0]?.message ?? 'Invalid data') + return + } + if (await this.checkForActiveCharacters()) { this.sendNotificationAndLog('You are already connected to another character') return } - const character = await this.characterRepository.getByUserAndId(this.socket.userId!, data.characterId) + let character = await this.characterRepository.getByUserAndId(this.socket.userId!, data.characterId) if (!character) { this.sendNotificationAndLog('Character not found or does not belong to this user') return } + if (data.newNickname) { + const existingCharacter = await this.characterRepository.getByName(data.newNickname) + if (existingCharacter) { + this.sendNotificationAndLog('Nickname already in use: ' + data.newNickname) + return + } + + await character.setName(data.newNickname).save() + } + // Set character id this.socket.characterId = character.id diff --git a/src/events/character/create.ts b/src/events/character/create.ts index e4e9a42..1895c37 100644 --- a/src/events/character/create.ts +++ b/src/events/character/create.ts @@ -32,7 +32,7 @@ export default class CharacterCreateEvent extends BaseEvent { } private async createCharacter(data: z.infer): Promise { - const user = await this.userRepository.getById(this.socket.userId) + const user = await this.userRepository.getById(this.socket.userId!) if (!user) { throw new Error('You are not logged in') }