Added socketManager and moved logic into it where appropiate

This commit is contained in:
Dennis Postma 2024-12-29 02:35:50 +01:00
parent cb6fcbcb8e
commit ce073a67af
6 changed files with 97 additions and 70 deletions

View File

@ -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 { export enum ItemType {
WEAPON = 'WEAPON', WEAPON = 'WEAPON',
HELMET = 'HELMET', HELMET = 'HELMET',

View File

@ -44,8 +44,6 @@ export default class CharacterConnectEvent extends BaseEvent {
return return
} }
await Database.getEntityManager().populate(character, ['zone'])
// Set character id // Set character id
this.socket.characterId = character.id this.socket.characterId = character.id
@ -56,13 +54,9 @@ export default class CharacterConnectEvent extends BaseEvent {
} }
// Emit character connect event // Emit character connect event
callback({ callback({ character })
character,
zone: character.zone,
characters: ZoneManager.getZoneById(character.zone!.id)?.getCharactersInZone()
})
} catch (error) { } catch (error) {
this.handleError('Failed to connect character', error) // @TODO : Make global error handler this.handleError('Failed to connect character', error)
} }
} }

View File

@ -11,13 +11,13 @@ export default class CharacterMove extends BaseEvent {
private readonly zoneEventTileService = ZoneEventTileService private readonly zoneEventTileService = ZoneEventTileService
public listen(): void { 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<void> { private async handleEvent({ positionX, positionY }: { positionX: number; positionY: number }): Promise<void> {
const zoneCharacter = ZoneManager.getCharacterById(this.socket.characterId!) const zoneCharacter = ZoneManager.getCharacterById(this.socket.characterId!)
if (!zoneCharacter?.character) { 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 return
} }
@ -29,7 +29,7 @@ export default class CharacterMove extends BaseEvent {
const path = await this.characterService.calculatePath(zoneCharacter.character, positionX, positionY) const path = await this.characterService.calculatePath(zoneCharacter.character, positionX, positionY)
if (!path) { 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 return
} }
@ -63,7 +63,7 @@ export default class CharacterMove extends BaseEvent {
character.positionY = end.y character.positionY = end.y
// Then emit with the same properties // 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, id: character.id,
positionX: character.positionX, positionX: character.positionX,
positionY: character.positionY, positionY: character.positionY,
@ -82,7 +82,7 @@ export default class CharacterMove extends BaseEvent {
private async handleZoneEventTile(zoneEventTile: ZoneEventTileWithTeleport): Promise<void> { private async handleZoneEventTile(zoneEventTile: ZoneEventTileWithTeleport): Promise<void> {
const zoneCharacter = ZoneManager.getCharacterById(this.socket.characterId!) const zoneCharacter = ZoneManager.getCharacterById(this.socket.characterId!)
if (!zoneCharacter) { if (!zoneCharacter) {
this.logger.error('character:move error: Character not found') this.logger.error('zone:character:move error: Character not found')
return return
} }
@ -93,7 +93,7 @@ export default class CharacterMove extends BaseEvent {
private finalizeMovement(zoneCharacter: ZoneCharacter): void { private finalizeMovement(zoneCharacter: ZoneCharacter): void {
zoneCharacter.isMoving = false 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, id: zoneCharacter.character.id,
positionX: zoneCharacter.character.positionX, positionX: zoneCharacter.character.positionX,
positionY: zoneCharacter.character.positionY, positionY: zoneCharacter.character.positionY,

View File

@ -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()

View File

@ -1,6 +1,4 @@
import fs from 'fs'
import { createServer as httpServer, Server as HTTPServer } from 'http' import { createServer as httpServer, Server as HTTPServer } from 'http'
import { pathToFileURL } from 'url'
import cors from 'cors' import cors from 'cors'
import express, { Application } from 'express' import express, { Application } from 'express'
@ -9,12 +7,11 @@ import { Server as SocketServer } from 'socket.io'
import config from '#application/config' import config from '#application/config'
import Database from '#application/database' import Database from '#application/database'
import Logger, { LoggerType } from '#application/logger' import Logger, { LoggerType } from '#application/logger'
import { getAppPath } from '#application/storage'
import { TSocket } from '#application/types'
import ConsoleManager from '#managers/consoleManager' import ConsoleManager from '#managers/consoleManager'
import DateManager from '#managers/dateManager' import DateManager from '#managers/dateManager'
import HttpManager from '#managers/httpManager' import HttpManager from '#managers/httpManager'
import QueueManager from '#managers/queueManager' import QueueManager from '#managers/queueManager'
import SocketManager from '#managers/socketManager'
import UserManager from '#managers/userManager' import UserManager from '#managers/userManager'
import WeatherManager from '#managers/weatherManager' import WeatherManager from '#managers/weatherManager'
import ZoneManager from '#managers/zoneManager' import ZoneManager from '#managers/zoneManager'
@ -87,57 +84,8 @@ export class Server {
// Load console manager // Load console manager
await ConsoleManager.boot(this.io) await ConsoleManager.boot(this.io)
// Listen for socket connections // Load socket manager
this.io.on('connection', this.handleConnection.bind(this)) await SocketManager.boot(this.io)
}
/**
* 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)}`)
}
} }
} }

View File

@ -27,7 +27,7 @@ class CharacterService extends BaseService {
const grid = await zone?.getGrid() const grid = await zone?.getGrid()
if (!grid?.length) { 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 return null
} }