forked from noxious/server
138 lines
5.1 KiB
TypeScript
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)
|
|
}
|
|
}
|
|
}
|