1
0
forked from noxious/server

138 lines
5.1 KiB
TypeScript

import { BaseEvent } from '@/application/base/baseEvent'
import { MapEventTileType, SocketEvent } from '@/application/enums'
import type { UUID } from '@/application/types'
import { type MapEditorMapT } 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: string
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: MapEditorMapT | null) => void): Promise<void> {
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 eventTile of data.mapEventTiles) {
const mapEventTile = new MapEventTile().setMap(map).setType(eventTile.type).setPositionX(eventTile.positionX).setPositionY(eventTile.positionY)
if (eventTile.teleport) {
const toMap = await mapRepository.getById(eventTile.teleport.toMap as UUID)
if (!toMap) continue
const teleport = new MapEventTileTeleport()
.setMapEventTile(mapEventTile)
.setToMap(toMap)
.setToPositionX(eventTile.teleport.toPositionX)
.setToPositionY(eventTile.teleport.toPositionY)
.setToRotation(eventTile.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(await map.mapEditorObject())
} catch (error: any) {
this.sendNotificationAndLog(`gm:map:update error: ${error instanceof Error ? error.message + error.stack : String(error)}`)
return callback(null)
}
}
}