import type { UUID } from'@/application/types' import { BaseEvent } from'@/application/base/baseEvent' import { SocketEvent } from'@/application/enums' import { MapEventTileType } from'@/application/enums' import { Map } from'@/entities/map' import { MapEffect } from'@/entities/mapEffect' import { MapEventTile } from'@/entities/mapEventTile' import { MapEventTileTeleport } from'@/entities/mapEventTileTeleport' import { PlacedMapObject } from'@/entities/placedMapObject' import mapManager from'@/managers/mapManager' import MapRepository from'@/repositories/mapRepository' interface IPayload { mapId: UUID name: string width: number height: number tiles: string[][] pvp: boolean mapEventTiles: { type: MapEventTileType positionX: number positionY: number teleport?: { toMap: Map toPositionX: number toPositionY: number toRotation: number } }[] mapEffects: MapEffect[] placedMapObjects: PlacedMapObject[] } export default class MapUpdateEvent extends BaseEvent { public listen(): void { this.socket.on(SocketEvent.GM_MAP_UPDATE, this.handleEvent.bind(this)) } private async handleEvent(data: IPayload, callback: (response: Map | null) => void): Promise { try { if (!(await this.isCharacterGM())) return const character = await this.getCharacter() this.logger.info(`User ${character!.getId()} has updated map via map editor.`) if (!data.mapId) { this.logger.info(`User ${character!.getId()} tried to update map but did not provide a map id.`) return callback(null) } const mapRepository = new MapRepository() let map = await mapRepository.getById(data.mapId) if (!map) { this.logger.info(`User ${character!.getId()} tried to update map ${data.mapId} but it does not exist.`) return callback(null) } await mapRepository.getEntityManager().populate(map, mapRepository.POPULATE_MAP_EDITOR as any) // Validation logic remains the same if (data.tiles.length > data.height) { data.tiles = data.tiles.slice(0, data.height) } for (let i = 0; i < data.tiles.length; i++) { const row = data.tiles[i] if (row !== undefined && row.length > data.width) { data.tiles[i] = row.slice(0, data.width) } } // Remove map event tiles and placed map objects that are out of bounds data.mapEventTiles = data.mapEventTiles.filter((tile) => tile.positionX >= 0 && tile.positionX < data.width && tile.positionY >= 0 && tile.positionY < data.height) data.placedMapObjects = data.placedMapObjects.filter((obj) => obj.positionX >= 0 && obj.positionX < data.width && obj.positionY >= 0 && obj.positionY < data.height) // Clear existing collections map.getMapEventTiles().removeAll() map.getPlacedMapObjects().removeAll() map.getMapEffects().removeAll() // Create and add new map event tiles for (const tile of data.mapEventTiles) { const mapEventTile = new MapEventTile().setType(tile.type).setPositionX(tile.positionX).setPositionY(tile.positionY).setMap(map) if (tile.teleport) { const teleport = new MapEventTileTeleport() .setToMap((await mapRepository.getById(tile.teleport.toMap.id))!) .setToPositionX(tile.teleport.toPositionX) .setToPositionY(tile.teleport.toPositionY) .setToRotation(tile.teleport.toRotation) mapEventTile.setTeleport(teleport) } map.mapEventTiles.add(mapEventTile) } // Create and add new map objects for (const object of data.placedMapObjects) { const mapObject = new PlacedMapObject().setMapObject(object.mapObject).setIsRotated(object.isRotated).setPositionX(object.positionX).setPositionY(object.positionY).setMap(map) map.placedMapObjects.add(mapObject) } // Create and add new map effects for (const effect of data.mapEffects) { const mapEffect = new MapEffect().setEffect(effect.effect).setStrength(effect.strength).setMap(map) map.mapEffects.add(mapEffect) } // Update map properties await map.setName(data.name).setWidth(data.width).setHeight(data.height).setTiles(data.tiles).setPvp(data.pvp).setUpdatedAt(new Date()).save() // Reload map from database to get fresh data map = await mapRepository.getById(data.mapId) await mapRepository.getEntityManager().populate(map!, mapRepository.POPULATE_MAP_EDITOR as any) if (!map) { this.logger.info(`User ${character!.getId()} tried to update map ${data.mapId} but it does not exist after update.`) return callback(null) } // Reload map for players mapManager.unloadMap(data.mapId) await mapManager.loadMap(map) return callback(map) } catch (error: any) { this.emitError(`gm:map:update error: ${error instanceof Error ? error.message + error.stack : String(error)}`) return callback(null) } } }