Merge remote-tracking branch 'origin/main' into feature/#362-final-depth-sort-fix
# Conflicts: # src/entities/base/mapObject.ts # src/events/gameMaster/assetManager/mapObject/update.ts
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
import { BaseEvent } from '@/application/base/baseEvent'
|
||||
import { SocketEvent } from '@/application/enums'
|
||||
import { CharacterGender, SocketEvent } from '@/application/enums'
|
||||
import { CharacterHair } from '@/entities/characterHair'
|
||||
import SpriteRepository from '@/repositories/spriteRepository'
|
||||
|
||||
export default class CharacterHairCreateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
@ -11,8 +12,17 @@ export default class CharacterHairCreateEvent extends BaseEvent {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
// Get first sprite
|
||||
const spriteRepository = new SpriteRepository()
|
||||
const firstSprite = await spriteRepository.getFirst()
|
||||
|
||||
if (!firstSprite) {
|
||||
this.sendNotificationAndLog('No sprites found')
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
const newCharacterHair = new CharacterHair()
|
||||
await newCharacterHair.setName('New hair').save()
|
||||
await newCharacterHair.setName('New hair').setGender(CharacterGender.MALE).setSprite(firstSprite).save()
|
||||
|
||||
return callback(true)
|
||||
} catch (error) {
|
||||
|
@ -8,6 +8,7 @@ type Payload = {
|
||||
id: UUID
|
||||
name: string
|
||||
gender: CharacterGender
|
||||
color: string
|
||||
isSelectable: boolean
|
||||
spriteId: UUID
|
||||
}
|
||||
@ -29,7 +30,7 @@ export default class CharacterHairUpdateEvent extends BaseEvent {
|
||||
const characterHair = await characterHairRepository.getById(data.id)
|
||||
if (!characterHair) return callback(false)
|
||||
|
||||
await characterHair.setName(data.name).setGender(data.gender).setIsSelectable(data.isSelectable).setSprite(sprite).setUpdatedAt(new Date()).save()
|
||||
await characterHair.setName(data.name).setGender(data.gender).setColor(data.color).setIsSelectable(data.isSelectable).setSprite(sprite).setUpdatedAt(new Date()).save()
|
||||
|
||||
return callback(true)
|
||||
} catch (error) {
|
||||
|
@ -14,7 +14,10 @@ export default class ItemCreateEvent extends BaseEvent {
|
||||
|
||||
const spriteRepository = new SpriteRepository()
|
||||
const sprite = await spriteRepository.getFirst()
|
||||
if (!sprite) return callback(false)
|
||||
if (!sprite) {
|
||||
this.sendNotificationAndLog('No sprites found')
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
const newItem = new Item()
|
||||
await newItem.setName('New Item').setItemType(ItemType.WEAPON).setStackable(false).setRarity(ItemRarity.COMMON).setSprite(sprite).save()
|
||||
|
@ -8,6 +8,7 @@ type Payload = {
|
||||
name: string
|
||||
tags: string[]
|
||||
depthOffsets: number[]
|
||||
pivotPoints: { x: number; y: number }[]
|
||||
originX: number
|
||||
originY: number
|
||||
frameRate: number
|
||||
@ -32,6 +33,7 @@ export default class MapObjectUpdateEvent extends BaseEvent {
|
||||
if (data.name !== undefined) mapObject.name = data.name
|
||||
if (data.tags !== undefined) mapObject.tags = data.tags
|
||||
if (data.depthOffsets !== undefined) mapObject.depthOffsets = data.depthOffsets
|
||||
if (data.pivotPoints !== undefined) mapObject.pivotPoints = data.pivotPoints
|
||||
if (data.originX !== undefined) mapObject.originX = data.originX
|
||||
if (data.originY !== undefined) mapObject.originY = data.originY
|
||||
if (data.frameRate !== undefined) mapObject.frameRate = data.frameRate
|
||||
|
@ -2,6 +2,7 @@ import { BaseEvent } from '@/application/base/baseEvent'
|
||||
import { SocketEvent } from '@/application/enums'
|
||||
import type { UUID } from '@/application/types'
|
||||
import { Sprite } from '@/entities/sprite'
|
||||
import { SpriteAction } from '@/entities/spriteAction'
|
||||
import SpriteRepository from '@/repositories/spriteRepository'
|
||||
|
||||
interface CopyPayload {
|
||||
@ -29,7 +30,21 @@ export default class SpriteCopyEvent extends BaseEvent {
|
||||
await spriteRepository.getEntityManager().populate(sourceSprite, ['spriteActions'])
|
||||
|
||||
const newSprite = new Sprite()
|
||||
await newSprite.setName(`${sourceSprite.getName()} (Copy)`).setSpriteActions(sourceSprite.getSpriteActions()).save()
|
||||
await newSprite.setName(`${sourceSprite.getName()} (Copy)`).save()
|
||||
|
||||
for (const spriteAction of sourceSprite.getSpriteActions()) {
|
||||
const newSpriteAction = new SpriteAction()
|
||||
await newSpriteAction
|
||||
.setSprite(newSprite)
|
||||
.setAction(spriteAction.getAction())
|
||||
.setSprites(spriteAction.getSprites() ?? [])
|
||||
.setOriginX(spriteAction.getOriginX())
|
||||
.setOriginY(spriteAction.getOriginY())
|
||||
.setFrameWidth(spriteAction.getFrameWidth())
|
||||
.setFrameHeight(spriteAction.getFrameHeight())
|
||||
.setFrameRate(spriteAction.getFrameRate())
|
||||
.save()
|
||||
}
|
||||
|
||||
return callback(true)
|
||||
} catch (error) {
|
||||
|
@ -14,76 +14,103 @@ interface SpriteImage {
|
||||
}
|
||||
}
|
||||
|
||||
interface ImageDimensions {
|
||||
width: number
|
||||
height: number
|
||||
offsetX: number
|
||||
offsetY: number
|
||||
interface SpriteActionData {
|
||||
action: string
|
||||
sprites: SpriteImage[]
|
||||
originX: number
|
||||
originY: number
|
||||
frameRate: number
|
||||
}
|
||||
|
||||
interface EffectiveDimensions {
|
||||
width: number
|
||||
height: number
|
||||
top: number
|
||||
bottom: number
|
||||
}
|
||||
|
||||
type Payload = {
|
||||
interface UpdateSpritePayload {
|
||||
id: UUID
|
||||
name: string
|
||||
spriteActions: Array<{
|
||||
action: string
|
||||
sprites: SpriteImage[]
|
||||
originX: number
|
||||
originY: number
|
||||
frameRate: number
|
||||
}>
|
||||
spriteActions: SpriteActionData[]
|
||||
}
|
||||
|
||||
export default class SpriteUpdateEvent extends BaseEvent {
|
||||
private readonly spriteRepository: SpriteRepository = new SpriteRepository()
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on(SocketEvent.GM_SPRITE_UPDATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise<void> {
|
||||
private async handleEvent(data: UpdateSpritePayload, callback: (success: boolean) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
const spriteRepository = new SpriteRepository()
|
||||
const sprite = await spriteRepository.getById(data.id)
|
||||
if (!sprite) return callback(false)
|
||||
|
||||
await spriteRepository.getEntityManager().populate(sprite, ['spriteActions'])
|
||||
|
||||
// Update sprite in database
|
||||
await sprite.setName(data.name).save()
|
||||
|
||||
// First verify all sprite sheets can be generated
|
||||
for (const actionData of data.spriteActions) {
|
||||
if (!(await this.generateSpriteSheet(actionData.sprites, sprite.getId(), actionData.action))) {
|
||||
return callback(false)
|
||||
}
|
||||
// Validate request and permissions
|
||||
if (!(await this.isCharacterGM())) {
|
||||
callback(false)
|
||||
return
|
||||
}
|
||||
|
||||
// Get and validate sprite
|
||||
const sprite = await this.spriteRepository.getById(data.id)
|
||||
if (!sprite) {
|
||||
callback(false)
|
||||
return
|
||||
}
|
||||
await this.spriteRepository.getEntityManager().populate(sprite, ['spriteActions'])
|
||||
|
||||
// Update sprite name
|
||||
await sprite.setName(data.name).setUpdatedAt(new Date()).save()
|
||||
|
||||
// Process all sprite actions
|
||||
const success = await this.processAllSpriteActions(data.spriteActions, sprite)
|
||||
callback(success)
|
||||
} catch (error) {
|
||||
console.error(`Error updating sprite ${data.id}:`, error)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
|
||||
private async processAllSpriteActions(actionsData: SpriteActionData[], sprite: any): Promise<boolean> {
|
||||
try {
|
||||
// Remove existing actions
|
||||
const existingActions = sprite.getSpriteActions()
|
||||
|
||||
// Remove existing actions only after confirming sprite sheets generated successfully
|
||||
for (const existingAction of existingActions) {
|
||||
await spriteRepository.getEntityManager().removeAndFlush(existingAction)
|
||||
await this.spriteRepository.getEntityManager().removeAndFlush(existingAction)
|
||||
}
|
||||
|
||||
// Create new actions
|
||||
for (const actionData of data.spriteActions) {
|
||||
// Process images and calculate dimensions
|
||||
const imageData = await Promise.all(actionData.sprites.map((sprite) => this.processImage(sprite)))
|
||||
const effectiveDimensions = imageData.map((dimensions) => this.calculateEffectiveDimensions(dimensions))
|
||||
// First pass: find the global maximum dimensions across all actions
|
||||
let globalMaxWidth = 0
|
||||
let globalMaxHeight = 0
|
||||
|
||||
// Calculate total height needed for the sprite sheet
|
||||
const maxHeight = Math.max(...effectiveDimensions.map((d) => d.height))
|
||||
const maxTop = Math.max(...effectiveDimensions.map((d) => d.top))
|
||||
const maxBottom = Math.max(...effectiveDimensions.map((d) => d.bottom))
|
||||
const totalHeight = maxHeight + maxTop + maxBottom
|
||||
// Extract all image metadata to find global maximums
|
||||
for (const actionData of actionsData) {
|
||||
if (actionData.sprites.length === 0) continue
|
||||
|
||||
const imagesData = await Promise.all(
|
||||
actionData.sprites.map(async (sprite) => {
|
||||
const base64Data = sprite.url.split(';base64,').pop()
|
||||
if (!base64Data) throw new Error('Invalid base64 image')
|
||||
const buffer = Buffer.from(base64Data, 'base64')
|
||||
const metadata = await sharp(buffer).metadata()
|
||||
|
||||
return {
|
||||
width: metadata.width || 0,
|
||||
height: metadata.height || 0
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
// Update global maximums with this action's maximums
|
||||
const actionMaxWidth = Math.max(...imagesData.map((data) => data.width), 0)
|
||||
const actionMaxHeight = Math.max(...imagesData.map((data) => data.height), 0)
|
||||
|
||||
globalMaxWidth = Math.max(globalMaxWidth, actionMaxWidth)
|
||||
globalMaxHeight = Math.max(globalMaxHeight, actionMaxHeight)
|
||||
}
|
||||
|
||||
// Process each action using the global maximum dimensions
|
||||
for (const actionData of actionsData) {
|
||||
if (actionData.sprites.length === 0) continue
|
||||
|
||||
// Generate and save the sprite sheet using global dimensions
|
||||
const frameDimensions = await this.generateAndSaveSpriteSheet(actionData.sprites, sprite.getId(), actionData.action, globalMaxWidth, globalMaxHeight)
|
||||
|
||||
if (!frameDimensions) return false
|
||||
|
||||
// Create and save sprite action
|
||||
const spriteAction = new SpriteAction()
|
||||
spriteAction.setSprite(sprite)
|
||||
sprite.getSpriteActions().add(spriteAction)
|
||||
@ -93,73 +120,85 @@ export default class SpriteUpdateEvent extends BaseEvent {
|
||||
.setSprites(actionData.sprites)
|
||||
.setOriginX(actionData.originX)
|
||||
.setOriginY(actionData.originY)
|
||||
.setFrameWidth(await this.calculateMaxWidth(actionData.sprites))
|
||||
.setFrameHeight(totalHeight)
|
||||
.setFrameWidth(frameDimensions.frameWidth)
|
||||
.setFrameHeight(frameDimensions.frameHeight)
|
||||
.setFrameRate(actionData.frameRate)
|
||||
|
||||
await spriteRepository.getEntityManager().persistAndFlush(spriteAction)
|
||||
await this.spriteRepository.getEntityManager().persistAndFlush(spriteAction)
|
||||
}
|
||||
|
||||
return callback(true)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error(`Error updating sprite ${data.id}:`, error)
|
||||
return callback(false)
|
||||
console.error('Error processing sprite actions:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private async generateSpriteSheet(sprites: SpriteImage[], spriteId: string, action: string): Promise<boolean> {
|
||||
private async generateAndSaveSpriteSheet(sprites: SpriteImage[], spriteId: string, action: string, maxWidth: number, maxHeight: number): Promise<{ frameWidth: number; frameHeight: number } | null> {
|
||||
try {
|
||||
if (!sprites.length) return true
|
||||
if (sprites.length === 0) return { frameWidth: 0, frameHeight: 0 }
|
||||
|
||||
// Process all images and get their dimensions
|
||||
const imageData = await Promise.all(sprites.map((sprite) => this.processImage(sprite)))
|
||||
const effectiveDimensions = imageData.map((dimensions) => this.calculateEffectiveDimensions(dimensions))
|
||||
// Extract image data
|
||||
const imagesData = await Promise.all(
|
||||
sprites.map(async (sprite) => {
|
||||
const base64Data = sprite.url.split(';base64,').pop()
|
||||
if (!base64Data) throw new Error('Invalid base64 image')
|
||||
const buffer = Buffer.from(base64Data, 'base64')
|
||||
const metadata = await sharp(buffer).metadata()
|
||||
|
||||
// Calculate maximum dimensions
|
||||
const maxWidth = Math.max(...effectiveDimensions.map((d) => d.width))
|
||||
const maxHeight = Math.max(...effectiveDimensions.map((d) => d.height))
|
||||
const maxTop = Math.max(...effectiveDimensions.map((d) => d.top))
|
||||
const maxBottom = Math.max(...effectiveDimensions.map((d) => d.bottom))
|
||||
return {
|
||||
buffer,
|
||||
width: metadata.width || 0,
|
||||
height: metadata.height || 0
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
// Calculate total height needed
|
||||
const totalHeight = maxHeight + maxTop + maxBottom
|
||||
// Skip creation if any image has invalid dimensions
|
||||
if (imagesData.some((data) => data.width === 0 || data.height === 0)) {
|
||||
console.error('One or more sprites have invalid dimensions')
|
||||
return null
|
||||
}
|
||||
|
||||
// Process images and create sprite sheet
|
||||
const processedImages = await Promise.all(
|
||||
sprites.map(async (sprite, index) => {
|
||||
const { width, height, offsetX, offsetY } = await this.processImage(sprite)
|
||||
const uri = sprite.url.split(';base64,').pop()
|
||||
if (!uri) throw new Error('Invalid base64 image')
|
||||
const buffer = Buffer.from(uri, 'base64')
|
||||
// Create frames of uniform size with the original sprites centered
|
||||
const uniformFrames = await Promise.all(
|
||||
imagesData.map(async (imageData) => {
|
||||
// Calculate centering offsets to position the sprite in the middle of the frame
|
||||
const xOffset = Math.floor((maxWidth - imageData.width) / 2)
|
||||
const yOffset = Math.floor((maxHeight - imageData.height) / 2)
|
||||
|
||||
// Create individual frame
|
||||
const left = offsetX >= 0 ? offsetX : 0
|
||||
const verticalOffset = totalHeight - height - (offsetY >= 0 ? offsetY : 0)
|
||||
// Create a uniform-sized frame with the sprite centered
|
||||
return sharp({
|
||||
create: {
|
||||
width: maxWidth,
|
||||
height: totalHeight,
|
||||
height: maxHeight,
|
||||
channels: 4,
|
||||
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
||||
}
|
||||
})
|
||||
.composite([{ input: buffer, left, top: verticalOffset }])
|
||||
.composite([
|
||||
{
|
||||
input: imageData.buffer,
|
||||
left: xOffset,
|
||||
top: yOffset
|
||||
}
|
||||
])
|
||||
.png()
|
||||
.toBuffer()
|
||||
})
|
||||
)
|
||||
|
||||
// Combine frames into sprite sheet
|
||||
// Create the sprite sheet with uniform frames
|
||||
const spriteSheet = await sharp({
|
||||
create: {
|
||||
width: maxWidth * sprites.length,
|
||||
height: totalHeight,
|
||||
width: maxWidth * uniformFrames.length,
|
||||
height: maxHeight,
|
||||
channels: 4,
|
||||
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
||||
}
|
||||
})
|
||||
.composite(
|
||||
processedImages.map((buffer, index) => ({
|
||||
uniformFrames.map((buffer, index) => ({
|
||||
input: buffer,
|
||||
left: index * maxWidth,
|
||||
top: 0
|
||||
@ -168,50 +207,19 @@ export default class SpriteUpdateEvent extends BaseEvent {
|
||||
.png()
|
||||
.toBuffer()
|
||||
|
||||
// Ensure directory exists
|
||||
// Save sprite sheet
|
||||
const dir = `public/sprites/${spriteId}`
|
||||
await fs.promises.mkdir(dir, { recursive: true })
|
||||
|
||||
// Save the sprite sheet
|
||||
await fs.promises.writeFile(`${dir}/${action}.png`, spriteSheet)
|
||||
|
||||
return true
|
||||
// Return the uniform frame dimensions (now global maximum dimensions)
|
||||
return {
|
||||
frameWidth: maxWidth,
|
||||
frameHeight: maxHeight
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error generating sprite sheet:', error)
|
||||
return false
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private async processImage(sprite: SpriteImage): Promise<ImageDimensions> {
|
||||
const uri = sprite.url.split(';base64,').pop()
|
||||
if (!uri) throw new Error('Invalid base64 image')
|
||||
const buffer = Buffer.from(uri, 'base64')
|
||||
const metadata = await sharp(buffer).metadata()
|
||||
return {
|
||||
width: metadata.width ?? 0,
|
||||
height: metadata.height ?? 0,
|
||||
offsetX: sprite.offset?.x ?? 0,
|
||||
offsetY: sprite.offset?.y ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
private calculateEffectiveDimensions(imageDimensions: ImageDimensions): EffectiveDimensions {
|
||||
return {
|
||||
width: imageDimensions.width + Math.abs(imageDimensions.offsetX),
|
||||
height: imageDimensions.height + Math.abs(imageDimensions.offsetY),
|
||||
top: imageDimensions.offsetY >= 0 ? imageDimensions.offsetY : 0,
|
||||
bottom: imageDimensions.offsetY < 0 ? Math.abs(imageDimensions.offsetY) : 0
|
||||
}
|
||||
}
|
||||
|
||||
private async calculateMaxWidth(sprites: SpriteImage[]): Promise<number> {
|
||||
if (!sprites.length) return 0
|
||||
|
||||
// Process all images and get their dimensions
|
||||
const imageData = await Promise.all(sprites.map((sprite) => this.processImage(sprite)))
|
||||
const effectiveDimensions = imageData.map((dimensions) => this.calculateEffectiveDimensions(dimensions))
|
||||
|
||||
// Calculate maximum width needed
|
||||
return Math.max(...effectiveDimensions.map((d) => d.width))
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { BaseEvent } from '@/application/base/baseEvent'
|
||||
import { SocketEvent } from '@/application/enums'
|
||||
import type { UUID } from '@/application/types'
|
||||
import { Map } from '@/entities/map'
|
||||
import { type MapEditorMapT } from '@/entities/map'
|
||||
import MapRepository from '@/repositories/mapRepository'
|
||||
|
||||
interface IPayload {
|
||||
@ -13,7 +13,7 @@ export default class MapRequestEvent extends BaseEvent {
|
||||
this.socket.on(SocketEvent.GM_MAP_REQUEST, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: Map | null) => void): Promise<void> {
|
||||
private async handleEvent(data: IPayload, callback: (response: MapEditorMapT | null) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
@ -34,9 +34,7 @@ export default class MapRequestEvent extends BaseEvent {
|
||||
|
||||
await mapRepository.getEntityManager().populate(map, mapRepository.POPULATE_MAP_EDITOR as any)
|
||||
|
||||
// Remove map.mapEventTiles.teleport.toMap and add map.mapEventTiles.teleport.toMapId
|
||||
|
||||
return callback(map)
|
||||
return callback(await map.mapEditorObject())
|
||||
} catch (error: any) {
|
||||
this.logger.error('gm:map:request error', error.message)
|
||||
return callback(null)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { BaseEvent } from '@/application/base/baseEvent'
|
||||
import { MapEventTileType, SocketEvent } from '@/application/enums'
|
||||
import type { UUID } from '@/application/types'
|
||||
import { Map } from '@/entities/map'
|
||||
import { type MapEditorMapT } from '@/entities/map'
|
||||
import { MapEffect } from '@/entities/mapEffect'
|
||||
import { MapEventTile } from '@/entities/mapEventTile'
|
||||
import { MapEventTileTeleport } from '@/entities/mapEventTileTeleport'
|
||||
@ -21,7 +21,7 @@ interface IPayload {
|
||||
positionX: number
|
||||
positionY: number
|
||||
teleport?: {
|
||||
toMapId: string
|
||||
toMap: string
|
||||
toPositionX: number
|
||||
toPositionY: number
|
||||
toRotation: number
|
||||
@ -36,7 +36,7 @@ export default class MapUpdateEvent extends BaseEvent {
|
||||
this.socket.on(SocketEvent.GM_MAP_UPDATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: Map | null) => void): Promise<void> {
|
||||
private async handleEvent(data: IPayload, callback: (response: MapEditorMapT | null) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
@ -80,17 +80,17 @@ export default class MapUpdateEvent extends BaseEvent {
|
||||
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 toMap = await mapRepository.getById(tile.teleport.toMapId as UUID)
|
||||
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(tile.teleport.toPositionX)
|
||||
.setToPositionY(tile.teleport.toPositionY)
|
||||
.setToRotation(tile.teleport.toRotation)
|
||||
.setToPositionX(eventTile.teleport.toPositionX)
|
||||
.setToPositionY(eventTile.teleport.toPositionY)
|
||||
.setToRotation(eventTile.teleport.toRotation)
|
||||
|
||||
mapEventTile.setTeleport(teleport)
|
||||
}
|
||||
@ -128,9 +128,9 @@ export default class MapUpdateEvent extends BaseEvent {
|
||||
mapManager.unloadMap(data.mapId)
|
||||
await mapManager.loadMap(map)
|
||||
|
||||
return callback(map)
|
||||
return callback(await map.mapEditorObject())
|
||||
} catch (error: any) {
|
||||
this.emitError(`gm:map:update error: ${error instanceof Error ? error.message + error.stack : String(error)}`)
|
||||
this.sendNotificationAndLog(`gm:map:update error: ${error instanceof Error ? error.message + error.stack : String(error)}`)
|
||||
return callback(null)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user