Almost finalised refactoring

This commit is contained in:
2025-01-03 14:35:02 +01:00
parent fecdf222d7
commit a40b71140a
35 changed files with 257 additions and 410 deletions

View File

@ -11,8 +11,13 @@ export default class characterHairListEvent extends BaseEvent {
}
private async handleEvent(data: IPayload, callback: (response: CharacterHair[]) => void): Promise<void> {
const items: CharacterHair[] = await characterHairRepository.getAllSelectable()
await Database.getEntityManager().populate(items, ['sprite'])
callback(items)
try {
const items: CharacterHair[] = await characterHairRepository.getAllSelectable()
await Database.getEntityManager().populate(items, ['sprite'])
return callback(items)
} catch (error) {
this.logger.error('character:hair:list error', error)
return callback([])
}
}
}

View File

@ -15,30 +15,14 @@ export default class CharacterConnectEvent extends BaseEvent {
this.socket.on('character:connect', this.handleEvent.bind(this))
}
/**
* Handle character connect event
* @TODO:
* 1. Check if character is already connected
* 2. Update character hair if provided
* 3. Emit character connect event
* 4. Let other clients know of new character
* @param data
* @param callback
* @private
*/
private async handleEvent(data: CharacterConnectPayload, callback: (response: any) => void): Promise<void> {
if (!this.socket.userId) {
this.emitError('User not authenticated')
return
}
try {
if (await this.checkForActiveCharacters()) {
this.emitError('You are already connected to another character')
return
}
const character = await CharacterRepository.getByUserAndId(this.socket.userId, data.characterId)
const character = await CharacterRepository.getByUserAndId(this.socket.userId!, data.characterId)
if (!character) {
this.emitError('Character not found or does not belong to this user')
@ -57,8 +41,8 @@ export default class CharacterConnectEvent extends BaseEvent {
// Emit character connect event
callback({ character })
// wait 300 ms, @TODO: Find a better way to do this
await new Promise((resolve) => setTimeout(resolve, 100))
// wait 300 ms, @TODO: Find a better way to do this, race condition
await new Promise((resolve) => setTimeout(resolve, 500))
await TeleportService.teleportCharacter(character.id, {
targetMapId: character.map.id,

View File

@ -9,7 +9,6 @@ type TypePayload = {
}
type TypeResponse = {
map: Map
characters: Character[]
}
@ -20,11 +19,7 @@ export default class CharacterDeleteEvent extends BaseEvent {
private async handleEvent(data: TypePayload, callback: (response: TypeResponse) => void): Promise<any> {
try {
const character = await CharacterRepository.getByUserAndId(this.socket.userId!, data.characterId)
if (character) {
await character.delete()
}
await (await CharacterRepository.getByUserAndId(this.socket.userId!, data.characterId))?.delete()
const characters: Character[] = await CharacterRepository.getByUserId(this.socket.userId!)
this.socket.emit('character:list', characters)

View File

@ -1,5 +1,4 @@
import { BaseEvent } from '#application/base/baseEvent'
import Database from '#application/database'
import { Character } from '#entities/character'
import CharacterRepository from '#repositories/characterRepository'
@ -10,9 +9,7 @@ export default class CharacterListEvent extends BaseEvent {
private async handleEvent(data: any): Promise<void> {
try {
const characters: Character[] = await CharacterRepository.getByUserId(this.socket.userId!)
await Database.getEntityManager().populate(characters, ['characterType', 'characterHair'])
let characters: Character[] = await CharacterRepository.getByUserId(this.socket.userId!, ['characterType', 'characterHair'])
this.socket.emit('character:list', characters)
} catch (error: any) {
this.logger.error('character:list error', error.message)

View File

@ -1,9 +1,9 @@
import { BaseEvent } from '#application/base/baseEvent'
import CharacterHairRepository from '#repositories/characterHairRepository'
import characterRepository from '#repositories/characterRepository'
import { UUID } from '#application/types'
interface IPayload {
id: number
id: UUID
}
export default class characterHairDeleteEvent extends BaseEvent {
@ -12,20 +12,13 @@ export default class characterHairDeleteEvent extends BaseEvent {
}
private async handleEvent(data: IPayload, callback: (response: boolean) => void): Promise<void> {
const character = await characterRepository.getById(this.socket.characterId as number)
if (!character) return callback(false)
if (character.role !== 'gm') {
return callback(false)
}
try {
const characterHair = await CharacterHairRepository.getById(data.id)
if (characterHair) {
await characterHair.delete()
}
if (!(await this.isCharacterGM())) return
callback(true)
const characterHair = await CharacterHairRepository.getById(data.id)
await (await CharacterHairRepository.getById(data.id))?.delete()
return callback(true)
} catch (error) {
this.logger.error(`Error deleting character type ${data.id}: ${error instanceof Error ? error.message : String(error)}`)
callback(false)

View File

@ -1,7 +1,6 @@
import { BaseEvent } from '#application/base/baseEvent'
import { CharacterHair } from '#entities/characterHair'
import characterHairRepository from '#repositories/characterHairRepository'
import characterRepository from '#repositories/characterRepository'
interface IPayload {}
@ -11,19 +10,14 @@ export default class characterHairListEvent extends BaseEvent {
}
private async handleEvent(data: IPayload, callback: (response: CharacterHair[]) => void): Promise<void> {
const character = await characterRepository.getById(this.socket.characterId as number)
if (!character) {
this.logger.error('gm:characterHair:list error', 'Character not found')
try {
if (!(await this.isCharacterGM())) return
const items = await characterHairRepository.getAll()
return callback(items)
} catch (error) {
this.logger.error('gm:characterHair:list error', error)
return callback([])
}
if (character.role !== 'gm') {
this.logger.info(`User ${character.id} tried to list character hair but is not a game master.`)
return callback([])
}
// get all objects
const items = await characterHairRepository.getAll()
callback(items)
}
}

View File

@ -6,7 +6,7 @@ import characterRepository from '#repositories/characterRepository'
import SpriteRepository from '#repositories/spriteRepository'
type Payload = {
id: number
id: UUID
name: string
gender: CharacterGender
isSelectable: boolean
@ -19,21 +19,17 @@ export default class CharacterHairUpdateEvent extends BaseEvent {
}
private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise<void> {
const character = await characterRepository.getById(this.socket.characterId as number)
if (!character) return callback(false)
if (character.role !== 'gm') {
return callback(false)
}
try {
if (!(await this.isCharacterGM())) return
const sprite = await SpriteRepository.getById(data.spriteId)
const characterHair = await CharacterHairRepository.getById(data.id)
if (characterHair) {
await characterHair.setName(data.name).setGender(data.gender).setIsSelectable(data.isSelectable).setSprite(sprite!).update()
if (!characterHair) {
return callback(false)
}
await characterHair.setName(data.name).setGender(data.gender).setIsSelectable(data.isSelectable).setSprite(sprite!).update()
return callback(true)
} catch (error) {
this.logger.error(`Error updating character hair: ${error instanceof Error ? error.message : String(error)}`)

View File

@ -1,41 +1,22 @@
import { CharacterGender, CharacterRace } from '@prisma/client'
import { Server } from 'socket.io'
import prisma from '#application/prisma'
import { TSocket } from '#application/types'
import characterRepository from '#repositories/characterRepository'
export default class CharacterTypeCreateEvent {
constructor(
private readonly io: Server,
private readonly socket: TSocket
) {}
import { BaseEvent } from '#application/base/baseEvent'
import { CharacterType } from '#entities/characterType'
export default class CharacterTypeCreateEvent extends BaseEvent {
public listen(): void {
this.socket.on('gm:characterType:create', this.handleEvent.bind(this))
}
private async handleEvent(data: undefined, callback: (response: boolean, characterType?: any) => void): Promise<void> {
try {
const character = await characterRepository.getById(this.socket.characterId as number)
if (!character) return callback(false)
if (!(await this.isCharacterGM())) return
if (character.role !== 'gm') {
return callback(false)
}
const newCharacterType = new CharacterType()
await newCharacterType.setName('New character type').save()
const newCharacterType = await prisma.characterType.create({
data: {
name: 'New character type',
gender: CharacterGender.MALE,
race: CharacterRace.HUMAN
}
})
callback(true, newCharacterType)
return callback(true, newCharacterType)
} catch (error) {
console.error('Error creating character type:', error)
callback(false)
return callback(false)
}
}
}

View File

@ -1,41 +1,28 @@
import { Server } from 'socket.io'
import { gameMasterLogger } from '#application/logger'
import { TSocket } from '#application/types'
import characterRepository from '#repositories/characterRepository'
import { UUID } from '#application/types'
import CharacterTypeRepository from '#repositories/characterTypeRepository'
import { BaseEvent } from '#application/base/baseEvent'
interface IPayload {
id: number
id: UUID
}
export default class CharacterTypeDeleteEvent {
constructor(
private readonly io: Server,
private readonly socket: TSocket
) {}
export default class CharacterTypeDeleteEvent extends BaseEvent {
public listen(): void {
this.socket.on('gm:characterType:remove', this.handleEvent.bind(this))
}
private async handleEvent(data: IPayload, callback: (response: boolean) => void): Promise<void> {
const character = await characterRepository.getById(this.socket.characterId!)
if (!character) return callback(false)
if (character.role !== 'gm') {
return callback(false)
}
try {
if (!(await this.isCharacterGM())) return
const characterType = await CharacterTypeRepository.getById(data.id)
if (!characterType) return callback(false)
await characterType.delete()
callback(true)
return callback(true)
} catch (error) {
gameMasterLogger.error(`Error deleting character type ${data.id}: ${error instanceof Error ? error.message : String(error)}`)
callback(false)
this.logger.error(`Error deleting character type ${data.id}: ${error instanceof Error ? error.message : String(error)}`)
return callback(false)
}
}
}

View File

@ -1,37 +1,23 @@
import { CharacterType } from '@prisma/client'
import { Server } from 'socket.io'
import { gameMasterLogger } from '#application/logger'
import { TSocket } from '#application/types'
import characterRepository from '#repositories/characterRepository'
import CharacterTypeRepository from '#repositories/characterTypeRepository'
import { BaseEvent } from '#application/base/baseEvent'
import { CharacterType } from '#entities/characterType'
interface IPayload {}
export default class CharacterTypeListEvent {
constructor(
private readonly io: Server,
private readonly socket: TSocket
) {}
export default class CharacterTypeListEvent extends BaseEvent {
public listen(): void {
this.socket.on('gm:characterType:list', this.handleEvent.bind(this))
}
private async handleEvent(data: IPayload, callback: (response: CharacterType[]) => void): Promise<void> {
const character = await characterRepository.getById(this.socket.characterId as number)
if (!character) {
gameMasterLogger.error('gm:characterType:list error', 'Character not found')
try {
if (!(await this.isCharacterGM())) return
const items = await CharacterTypeRepository.getAll()
return callback(items)
} catch (error) {
this.logger.error('gm:characterType:list error', error)
return callback([])
}
if (character.role !== 'gm') {
gameMasterLogger.info(`User ${character.id} tried to list character types but is not a game master.`)
return callback([])
}
// get all objects
const items = await CharacterTypeRepository.getAll()
callback(items)
}
}

View File

@ -1,14 +1,15 @@
import ObjectRepository from '#repositories/mapObjectRepository'
import { BaseEvent } from '#application/base/baseEvent'
import { MapObject } from '#entities/mapObject'
interface IPayload {}
export default class ObjectListEvent extends BaseEvent{
export default class MapObjectListEvent extends BaseEvent {
public listen(): void {
this.socket.on('gm:object:list', this.handleEvent.bind(this))
this.socket.on('gm:mapObject:list', this.handleEvent.bind(this))
}
private async handleEvent(data: IPayload, callback: (response: Object[]) => void): Promise<void> {
private async handleEvent(data: IPayload, callback: (response: MapObject[]) => void): Promise<void> {
if (!(await this.isCharacterGM())) return
// get all objects

View File

@ -0,0 +1,38 @@
import fs from 'fs'
import Storage from '#application/storage'
import { BaseEvent } from '#application/base/baseEvent'
import MapObjectRepository from '#repositories/mapObjectRepository'
import { UUID } from '#application/types'
interface IPayload {
mapObjectId: UUID
}
export default class MapObjectRemoveEvent extends BaseEvent {
public listen(): void {
this.socket.on('gm:mapObject:remove', this.handleEvent.bind(this))
}
private async handleEvent(data: IPayload, callback: (response: boolean) => void): Promise<void> {
if (!(await this.isCharacterGM())) return
try {
// remove the tile from the disk
const finalFilePath = Storage.getPublicPath('map_objects', data.mapObjectId + '.png')
fs.unlink(finalFilePath, async (err) => {
if (err) {
this.logger.error(`Error deleting object ${data.mapObjectId}: ${err.message}`)
callback(false)
return
}
await (await MapObjectRepository.getById(data.mapObjectId))?.delete()
return callback(true)
})
} catch (error) {
this.logger.error(`Error deleting object ${data.mapObjectId}: ${error instanceof Error ? error.message : String(error)}`)
return callback(false)
}
}
}

View File

@ -0,0 +1,46 @@
import { UUID } from '#application/types'
import { BaseEvent } from '#application/base/baseEvent'
import MapObjectRepository from '#repositories/mapObjectRepository'
type Payload = {
id: UUID
name: string
tags: string[]
originX: number
originY: number
isAnimated: boolean
frameRate: number
frameWidth: number
frameHeight: number
}
export default class MapObjectUpdateEvent extends BaseEvent {
public listen(): void {
this.socket.on('gm:mapObject:update', this.handleEvent.bind(this))
}
private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise<void> {
try {
if (!(await this.isCharacterGM())) return
const mapObject = await MapObjectRepository.getById(data.id)
if (!mapObject) return callback(false)
await mapObject
.setName(data.name)
.setTags(data.tags)
.setOriginX(data.originX)
.setOriginY(data.originY)
.setIsAnimated(data.isAnimated)
.setFrameRate(data.frameRate)
.setFrameWidth(data.frameWidth)
.setFrameHeight(data.frameHeight)
.update()
return callback(true)
} catch (error) {
console.error(error)
return callback(false)
}
}
}

View File

@ -0,0 +1,53 @@
import fs from 'fs/promises'
import { writeFile } from 'node:fs/promises'
import sharp from 'sharp'
import Storage from '#application/storage'
import { BaseEvent } from '#application/base/baseEvent'
import { MapObject } from '#entities/mapObject'
interface IObjectData {
[key: string]: Buffer
}
export default class MapObjectUploadEvent extends BaseEvent {
public listen(): void {
this.socket.on('gm:mapObject:upload', this.handleEvent.bind(this))
}
private async handleEvent(data: IObjectData, callback: (response: boolean) => void): Promise<void> {
try {
if (!(await this.isCharacterGM())) return
const public_folder = Storage.getPublicPath('map_objects')
// Ensure the folder exists
await fs.mkdir(public_folder, { recursive: true })
const uploadPromises = Object.entries(data).map(async ([key, objectData]) => {
// Get image dimensions
const metadata = await sharp(objectData).metadata()
const width = metadata.width || 0
const height = metadata.height || 0
// Create new map object and save it to database
const mapObject = new MapObject()
await mapObject.setName(key).setTags([]).setOriginX(0).setOriginY(0).setFrameWidth(width).setFrameHeight(height).save()
// Save image to disk
const uuid = mapObject.getId()
const filename = `${uuid}.png`
const finalFilePath = Storage.getPublicPath('map_objects', filename)
await writeFile(finalFilePath, objectData)
this.logger.info('gm:mapObject:upload', `Object ${key} uploaded with id ${uuid}`)
})
await Promise.all(uploadPromises)
return callback(true)
} catch (error: any) {
this.logger.error('gm:mapObject:upload error', error.message)
return callback(false)
}
}
}

View File

@ -1,59 +0,0 @@
import fs from 'fs'
import { Server } from 'socket.io'
import { gameLogger, gameMasterLogger } from '#application/logger'
import prisma from '#application/prisma'
import Storage from '#application/storage'
import { TSocket } from '#application/types'
import characterRepository from '#repositories/characterRepository'
interface IPayload {
object: string
}
export default class ObjectRemoveEvent {
constructor(
private readonly io: Server,
private readonly socket: TSocket
) {}
public listen(): void {
this.socket.on('gm:object:remove', this.handleEvent.bind(this))
}
private async handleEvent(data: IPayload, callback: (response: boolean) => void): Promise<void> {
const character = await characterRepository.getById(this.socket.characterId as number)
if (!character) return callback(false)
if (character.role !== 'gm') {
return callback(false)
}
try {
await prisma.object.delete({
where: {
id: data.object
}
})
// get root path
const public_folder = Storage.getPublicPath('objects')
// remove the tile from the disk
const finalFilePath = Storage.getPublicPath('objects', data.object + '.png')
fs.unlink(finalFilePath, (err) => {
if (err) {
gameMasterLogger.error(`Error deleting object ${data.object}: ${err.message}`)
callback(false)
return
}
callback(true)
})
} catch (error) {
gameLogger.error(`Error deleting object ${data.object}: ${error instanceof Error ? error.message : String(error)}`)
callback(false)
}
}
}

View File

@ -1,59 +0,0 @@
import { Server } from 'socket.io'
import prisma from '#application/prisma'
import { TSocket } from '#application/types'
import characterRepository from '#repositories/characterRepository'
type Payload = {
id: string
name: string
tags: string[]
originX: number
originY: number
isAnimated: boolean
frameRate: number
frameWidth: number
frameHeight: number
}
export default class ObjectUpdateEvent {
constructor(
private readonly io: Server,
private readonly socket: TSocket
) {}
public listen(): void {
this.socket.on('gm:object:update', this.handleEvent.bind(this))
}
private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise<void> {
const character = await characterRepository.getById(this.socket.characterId as number)
if (!character) return callback(false)
if (character.role !== 'gm') {
return callback(false)
}
try {
const object = await prisma.object.update({
where: {
id: data.id
},
data: {
name: data.name,
tags: data.tags,
originX: data.originX,
originY: data.originY,
isAnimated: data.isAnimated,
frameRate: data.frameRate,
frameWidth: data.frameWidth,
frameHeight: data.frameHeight
}
})
callback(true)
} catch (error) {
console.error(error)
callback(false)
}
}
}

View File

@ -1,73 +0,0 @@
import fs from 'fs/promises'
import { writeFile } from 'node:fs/promises'
import sharp from 'sharp'
import { Server } from 'socket.io'
import { gameMasterLogger } from '#application/logger'
import prisma from '#application/prisma'
import Storage from '#application/storage'
import { TSocket } from '#application/types'
import characterRepository from '#repositories/characterRepository'
interface IObjectData {
[key: string]: Buffer
}
export default class ObjectUploadEvent {
constructor(
private readonly io: Server,
private readonly socket: TSocket
) {}
public listen(): void {
this.socket.on('gm:object:upload', this.handleEvent.bind(this))
}
private async handleEvent(data: IObjectData, callback: (response: boolean) => void): Promise<void> {
try {
const character = await characterRepository.getById(this.socket.characterId as number)
if (!character) return callback(false)
if (character.role !== 'gm') {
return callback(false)
}
const public_folder = Storage.getPublicPath('objects')
// Ensure the folder exists
await fs.mkdir(public_folder, { recursive: true })
const uploadPromises = Object.entries(data).map(async ([key, objectData]) => {
// Get image dimensions
const metadata = await sharp(objectData).metadata()
const width = metadata.width || 0
const height = metadata.height || 0
const object = await prisma.object.create({
data: {
name: key,
tags: [],
originX: 0,
originY: 0,
frameWidth: width,
frameHeight: height
}
})
const uuid = object.id
const filename = `${uuid}.png`
const finalFilePath = Storage.getPublicPath('objects', filename)
await writeFile(finalFilePath, objectData)
gameMasterLogger.info('gm:object:upload', `Object ${key} uploaded with id ${uuid}`)
})
await Promise.all(uploadPromises)
callback(true)
} catch (error: any) {
gameMasterLogger.error('gm:object:upload error', error.message)
callback(false)
}
}
}

View File

@ -10,7 +10,7 @@ type Payload = {
export default class MapCreateEvent extends BaseEvent {
public listen(): void {
this.socket.on('gm:map_editor:map:create', this.handleEvent.bind(this))
this.socket.on('gm:map:create', this.handleEvent.bind(this))
}
private async handleEvent(data: Payload, callback: (response: Map[]) => void): Promise<void> {
@ -30,7 +30,7 @@ export default class MapCreateEvent extends BaseEvent {
const mapList = await MapRepository.getAll()
return callback(mapList)
} catch (error: any) {
this.logger.error('gm:map_editor:map:create error', error.message)
this.logger.error('gm:map:create error', error.message)
this.socket.emit('notification', { message: 'Failed to create map.' })
return callback([])
}

View File

@ -8,7 +8,7 @@ type Payload = {
export default class MapDeleteEvent extends BaseEvent {
public listen(): void {
this.socket.on('gm:map_editor:map:delete', this.handleEvent.bind(this))
this.socket.on('gm:map:delete', this.handleEvent.bind(this))
}
private async handleEvent(data: Payload, callback: (response: boolean) => void): Promise<void> {
@ -22,7 +22,7 @@ export default class MapDeleteEvent extends BaseEvent {
this.logger.info(`Map ${data.mapId} deleted successfully.`)
return callback(true)
} catch (error: unknown) {
this.logger.error('gm:map_editor:map:delete error', error)
this.logger.error('gm:map:delete error', error)
return callback(false)
}
}

View File

@ -6,7 +6,7 @@ interface IPayload {}
export default class MapListEvent extends BaseEvent {
public listen(): void {
this.socket.on('gm:map_editor:map:list', this.handleEvent.bind(this))
this.socket.on('gm:map:list', this.handleEvent.bind(this))
}
private async handleEvent(data: IPayload, callback: (response: Map[]) => void): Promise<void> {
@ -18,7 +18,7 @@ export default class MapListEvent extends BaseEvent {
const maps = await MapRepository.getAll()
return callback(maps)
} catch (error: any) {
this.logger.error('gm:map_editor:map:list error', error.message)
this.logger.error('gm:map:list error', error.message)
return callback([])
}
}

View File

@ -2,6 +2,7 @@ import { BaseEvent } from '#application/base/baseEvent'
import { UUID } from '#application/types'
import { Map } from '#entities/map'
import MapRepository from '#repositories/mapRepository'
import Database from '#application/database'
interface IPayload {
mapId: UUID
@ -9,7 +10,7 @@ interface IPayload {
export default class MapRequestEvent extends BaseEvent {
public listen(): void {
this.socket.on('gm:map_editor:map:request', this.handleEvent.bind(this))
this.socket.on('gm:map:request', this.handleEvent.bind(this))
}
private async handleEvent(data: IPayload, callback: (response: Map | null) => void): Promise<void> {
@ -25,14 +26,18 @@ export default class MapRequestEvent extends BaseEvent {
const map = await MapRepository.getById(data.mapId)
if (!map) {
this.logger.info(`User ${(await this.getCharacter())!.getId()} tried to request map ${data.mapId} but it does not exist.`)
return callback(null)
}
console.log(map)
await Database.getEntityManager().populate(map, ['mapEventTiles', 'placedMapObjects'])
return callback(map)
} catch (error: any) {
this.logger.error('gm:map_editor:map:request error', error.message)
this.logger.error('gm:map:request error', error.message)
return callback(null)
}
}

View File

@ -5,9 +5,9 @@ import { Map } from '#entities/map'
import { MapEffect } from '#entities/mapEffect'
import { MapEventTile } from '#entities/mapEventTile'
import { MapEventTileTeleport } from '#entities/mapEventTileTeleport'
import { MapObject } from '#entities/mapObject'
import mapManager from '#managers/mapManager'
import MapRepository from '#repositories/mapRepository'
import { PlacedMapObject } from '#entities/placedMapObject'
interface IPayload {
mapId: UUID
@ -31,12 +31,12 @@ interface IPayload {
effect: string
strength: number
}[]
mapObjects: MapObject[]
placedMapObjects: PlacedMapObject[]
}
export default class MapUpdateEvent extends BaseEvent {
public listen(): void {
this.socket.on('gm:map_editor:map:update', this.handleEvent.bind(this))
this.socket.on('gm:map:update', this.handleEvent.bind(this))
}
private async handleEvent(data: IPayload, callback: (response: Map | null) => void): Promise<void> {
@ -70,11 +70,11 @@ export default class MapUpdateEvent extends BaseEvent {
data.mapEventTiles = data.mapEventTiles.filter((tile) => tile.positionX >= 0 && tile.positionX < data.width && tile.positionY >= 0 && tile.positionY < data.height)
data.mapObjects = data.mapObjects.filter((obj) => obj.positionX >= 0 && obj.positionX < data.width && obj.positionY >= 0 && obj.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.mapEventTiles.removeAll()
map.mapObjects.removeAll()
map.placedMapObjects.removeAll()
map.mapEffects.removeAll()
// Create and add new map event tiles
@ -95,16 +95,14 @@ export default class MapUpdateEvent extends BaseEvent {
}
// Create and add new map objects
for (const object of data.mapObjects) {
const mapObject = new MapObject().setMapObject(object.mapObject).setDepth(object.depth).setIsRotated(object.isRotated).setPositionX(object.positionX).setPositionY(object.positionY).setMap(map)
map.mapObjects.add(mapObject)
for (const object of data.placedMapObjects) {
const mapObject = new PlacedMapObject().setMapObject(object.mapObject).setDepth(object.depth).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)
}
@ -125,7 +123,7 @@ export default class MapUpdateEvent extends BaseEvent {
return callback(map)
} catch (error: any) {
this.logger.error(`gm:map_editor:map:update error: ${error instanceof Error ? error.message : String(error)}`)
this.logger.error(`gm:mapObject:update error: ${error instanceof Error ? error.message : String(error)}`)
return callback(null)
}
}