From ce073a67afc1b8840ed41820afa264fffded129d Mon Sep 17 00:00:00 2001 From: Dennis Postma Date: Sun, 29 Dec 2024 02:35:50 +0100 Subject: [PATCH] Added socketManager and moved logic into it where appropiate --- src/application/enums.ts | 16 ++++++++ src/events/character/connect.ts | 10 +---- src/events/zone/characterMove.ts | 12 +++--- src/managers/socketManager.ts | 69 ++++++++++++++++++++++++++++++++ src/server.ts | 58 ++------------------------- src/services/characterService.ts | 2 +- 6 files changed, 97 insertions(+), 70 deletions(-) create mode 100644 src/managers/socketManager.ts diff --git a/src/application/enums.ts b/src/application/enums.ts index b738954..d347a4c 100644 --- a/src/application/enums.ts +++ b/src/application/enums.ts @@ -1,3 +1,19 @@ +export enum SocketEvent { + CHARACTER_CONNECT = 1, + CHARACTER_MOVE = 2, + CHARACTER_MOVE_ERROR = 3, + CHARACTER_TELEPORT = 4, + ZONE_CHARACTER_LEAVE = 5, + ZONE_CHARACTER_JOIN = 6, + ZONE_CHARACTER_LIST = 7, + ZONE_CHARACTER_DELETE = 8, + ZONE_CHARACTER_CREATE = 9, + ZONE_CHARACTER_UPDATE = 10, + ZONE_CHARACTER_HAIR_UPDATE = 11, + ZONE_CHARACTER_HAIR_LIST = 12, + ZONE_CHARACTER_TELEPORT = 13 +} + export enum ItemType { WEAPON = 'WEAPON', HELMET = 'HELMET', diff --git a/src/events/character/connect.ts b/src/events/character/connect.ts index 2b363ce..fd1622f 100644 --- a/src/events/character/connect.ts +++ b/src/events/character/connect.ts @@ -44,8 +44,6 @@ export default class CharacterConnectEvent extends BaseEvent { return } - await Database.getEntityManager().populate(character, ['zone']) - // Set character id this.socket.characterId = character.id @@ -56,13 +54,9 @@ export default class CharacterConnectEvent extends BaseEvent { } // Emit character connect event - callback({ - character, - zone: character.zone, - characters: ZoneManager.getZoneById(character.zone!.id)?.getCharactersInZone() - }) + callback({ character }) } catch (error) { - this.handleError('Failed to connect character', error) // @TODO : Make global error handler + this.handleError('Failed to connect character', error) } } diff --git a/src/events/zone/characterMove.ts b/src/events/zone/characterMove.ts index 2a90592..acc4c02 100644 --- a/src/events/zone/characterMove.ts +++ b/src/events/zone/characterMove.ts @@ -11,13 +11,13 @@ export default class CharacterMove extends BaseEvent { private readonly zoneEventTileService = ZoneEventTileService public listen(): void { - this.socket.on('character:move', this.handleEvent.bind(this)) + this.socket.on('zone:character:move', this.handleEvent.bind(this)) } private async handleEvent({ positionX, positionY }: { positionX: number; positionY: number }): Promise { const zoneCharacter = ZoneManager.getCharacterById(this.socket.characterId!) if (!zoneCharacter?.character) { - this.logger.error('character:move error: Character not found or not initialized') + this.logger.error('zone:character:move error: Character not found or not initialized') return } @@ -29,7 +29,7 @@ export default class CharacterMove extends BaseEvent { const path = await this.characterService.calculatePath(zoneCharacter.character, positionX, positionY) if (!path) { - this.io.in(zoneCharacter.character.zone!.id.toString()).emit('character:moveError', 'No valid path found') + this.io.in(zoneCharacter.character.zone!.id.toString()).emit('zone:character:moveError', 'No valid path found') return } @@ -63,7 +63,7 @@ export default class CharacterMove extends BaseEvent { character.positionY = end.y // Then emit with the same properties - this.io.in(character.zone!.id.toString()).emit('character:move', { + this.io.in(character.zone!.id.toString()).emit('zone:character:move', { id: character.id, positionX: character.positionX, positionY: character.positionY, @@ -82,7 +82,7 @@ export default class CharacterMove extends BaseEvent { private async handleZoneEventTile(zoneEventTile: ZoneEventTileWithTeleport): Promise { const zoneCharacter = ZoneManager.getCharacterById(this.socket.characterId!) if (!zoneCharacter) { - this.logger.error('character:move error: Character not found') + this.logger.error('zone:character:move error: Character not found') return } @@ -93,7 +93,7 @@ export default class CharacterMove extends BaseEvent { private finalizeMovement(zoneCharacter: ZoneCharacter): void { zoneCharacter.isMoving = false - this.io.in(zoneCharacter.character.zone!.id.toString()).emit('character:move', { + this.io.in(zoneCharacter.character.zone!.id.toString()).emit('zone:character:move', { id: zoneCharacter.character.id, positionX: zoneCharacter.character.positionX, positionY: zoneCharacter.character.positionY, diff --git a/src/managers/socketManager.ts b/src/managers/socketManager.ts new file mode 100644 index 0000000..3f12f4b --- /dev/null +++ b/src/managers/socketManager.ts @@ -0,0 +1,69 @@ +import fs from 'fs' +import { pathToFileURL } from 'url' + +import { Server as SocketServer } from 'socket.io' + +import Logger, { LoggerType } from '#application/logger' +import { getAppPath } from '#application/storage' +import { TSocket } from '#application/types' + +class SocketManager { + private io: any + private logger = Logger.type(LoggerType.APP) + + public async boot(io: SocketServer) { + this.io = io + io.on('connection', this.handleConnection.bind(this)) + } + + /** + * Handle socket connection + * @param socket + * @private + */ + private async handleConnection(socket: TSocket) { + try { + await this.loadEventHandlers('events', '', socket) + } catch (error: any) { + this.logger.error(`Failed to load event handlers: ${error.message}`) + } + } + + private async loadEventHandlers(baseDir: string, subDir: string, socket: TSocket) { + try { + const fullDir = getAppPath(baseDir, subDir) + const files = await fs.promises.readdir(fullDir, { withFileTypes: true }) + + for (const file of files) { + const filePath = getAppPath(baseDir, subDir, file.name) + + if (file.isDirectory()) { + await this.loadEventHandlers(baseDir, `${subDir}/${file.name}`, socket) + continue + } + + if (!file.isFile() || (!file.name.endsWith('.ts') && !file.name.endsWith('.js'))) { + continue + } + + try { + const module = await import(pathToFileURL(filePath).href) + if (typeof module.default !== 'function') { + this.logger.warn(`Unrecognized export in ${file.name}`) + continue + } + + const EventClass = module.default + const eventInstance = new EventClass(this.io, socket) + eventInstance.listen() + } catch (error) { + this.logger.error(`Error loading event handler ${file.name}: ${error instanceof Error ? error.message : String(error)}`) + } + } + } catch (error) { + this.logger.error(`Error reading directory: ${error instanceof Error ? error.message : String(error)}`) + } + } +} + +export default new SocketManager() diff --git a/src/server.ts b/src/server.ts index 0ed30f8..3786f9d 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,6 +1,4 @@ -import fs from 'fs' import { createServer as httpServer, Server as HTTPServer } from 'http' -import { pathToFileURL } from 'url' import cors from 'cors' import express, { Application } from 'express' @@ -9,12 +7,11 @@ import { Server as SocketServer } from 'socket.io' import config from '#application/config' import Database from '#application/database' import Logger, { LoggerType } from '#application/logger' -import { getAppPath } from '#application/storage' -import { TSocket } from '#application/types' import ConsoleManager from '#managers/consoleManager' import DateManager from '#managers/dateManager' import HttpManager from '#managers/httpManager' import QueueManager from '#managers/queueManager' +import SocketManager from '#managers/socketManager' import UserManager from '#managers/userManager' import WeatherManager from '#managers/weatherManager' import ZoneManager from '#managers/zoneManager' @@ -87,57 +84,8 @@ export class Server { // Load console manager await ConsoleManager.boot(this.io) - // Listen for socket connections - this.io.on('connection', this.handleConnection.bind(this)) - } - - /** - * Handle socket connection - * @param socket - * @private - */ - private async handleConnection(socket: TSocket) { - try { - await this.loadEventHandlers('events', '', socket) - } catch (error: any) { - this.logger.error(`Failed to load event handlers: ${error.message}`) - } - } - - private async loadEventHandlers(baseDir: string, subDir: string, socket: TSocket) { - try { - const fullDir = getAppPath(baseDir, subDir) - const files = await fs.promises.readdir(fullDir, { withFileTypes: true }) - - for (const file of files) { - const filePath = getAppPath(baseDir, subDir, file.name) - - if (file.isDirectory()) { - await this.loadEventHandlers(baseDir, `${subDir}/${file.name}`, socket) - continue - } - - if (!file.isFile() || (!file.name.endsWith('.ts') && !file.name.endsWith('.js'))) { - continue - } - - try { - const module = await import(pathToFileURL(filePath).href) - if (typeof module.default !== 'function') { - this.logger.warn(`Unrecognized export in ${file.name}`) - continue - } - - const EventClass = module.default - const eventInstance = new EventClass(this.io, socket) - eventInstance.listen() - } catch (error) { - this.logger.error(`Error loading event handler ${file.name}: ${error instanceof Error ? error.message : String(error)}`) - } - } - } catch (error) { - this.logger.error(`Error reading directory: ${error instanceof Error ? error.message : String(error)}`) - } + // Load socket manager + await SocketManager.boot(this.io) } } diff --git a/src/services/characterService.ts b/src/services/characterService.ts index d01334c..dc48af9 100644 --- a/src/services/characterService.ts +++ b/src/services/characterService.ts @@ -27,7 +27,7 @@ class CharacterService extends BaseService { const grid = await zone?.getGrid() if (!grid?.length) { - this.logger.error('character:move error: Grid not found or empty') + this.logger.error('zone:character:move error: Grid not found or empty') return null }