From 21f4c5328f351d2fb1b8925aea0d84a2abfc834e Mon Sep 17 00:00:00 2001 From: Dennis Postma Date: Sat, 4 Jan 2025 20:11:34 +0100 Subject: [PATCH] Converted more events --- src/application/base/baseEntity.ts | 6 +-- src/application/base/baseEvent.ts | 3 +- src/events/character/connect.ts | 4 +- .../assetManager/characterHair/update.ts | 2 +- .../assetManager/characterType/delete.ts | 3 +- .../gameMaster/assetManager/item/delete.ts | 41 +++++++------------ .../gameMaster/assetManager/item/list.ts | 38 ++++++----------- .../gameMaster/assetManager/mapObject/list.ts | 16 ++++++-- .../assetManager/mapObject/remove.ts | 6 +-- .../assetManager/mapObject/update.ts | 6 ++- .../assetManager/mapObject/upload.ts | 2 +- .../gameMaster/assetManager/sprite/copy.ts | 7 +++- .../gameMaster/assetManager/sprite/delete.ts | 8 ++-- .../gameMaster/assetManager/sprite/list.ts | 16 ++++++-- .../gameMaster/assetManager/tile/delete.ts | 8 ++-- .../gameMaster/assetManager/tile/list.ts | 14 +++++-- .../gameMaster/assetManager/tile/update.ts | 15 +++++-- src/events/gameMaster/mapEditor/update.ts | 2 +- src/models/mapCharacter.ts | 2 +- src/repositories/itemRepository.ts | 14 +++---- src/services/teleportService.ts | 2 +- 21 files changed, 113 insertions(+), 102 deletions(-) diff --git a/src/application/base/baseEntity.ts b/src/application/base/baseEntity.ts index 24f651e..6505f6e 100644 --- a/src/application/base/baseEntity.ts +++ b/src/application/base/baseEntity.ts @@ -14,15 +14,11 @@ export abstract class BaseEntity { return this.execute('persist', 'save entity') } - async update(): Promise { - return this.execute('merge', 'update entity') - } - async delete(): Promise { return this.execute('remove', 'remove entity') } - private async execute(method: 'persist' | 'merge' | 'remove', actionDescription: string): Promise { + private async execute(method: 'persist' | 'remove', actionDescription: string): Promise { try { const em = this.getEntityManager() diff --git a/src/application/base/baseEvent.ts b/src/application/base/baseEvent.ts index 22dc524..bb623c3 100644 --- a/src/application/base/baseEvent.ts +++ b/src/application/base/baseEvent.ts @@ -14,7 +14,8 @@ export abstract class BaseEvent { ) {} protected async getCharacter(): Promise { - return CharacterRepository.getById(this.socket.characterId!) + const characterRepository = new CharacterRepository() + return characterRepository.getById(this.socket.characterId!) } protected async isCharacterGM(): Promise { diff --git a/src/events/character/connect.ts b/src/events/character/connect.ts index 239e001..bfb5dd0 100644 --- a/src/events/character/connect.ts +++ b/src/events/character/connect.ts @@ -41,14 +41,14 @@ export default class CharacterConnectEvent extends BaseEvent { // Set character hair if (data.characterHairId !== undefined && data.characterHairId !== null) { const characterHair = await this.characterHairRepository.getById(data.characterHairId) - await character.setCharacterHair(characterHair).update() + await character.setCharacterHair(characterHair).save() } // Emit character connect event callback({ character }) // wait 300 ms, @TODO: Find a better way to do this, race condition - await new Promise((resolve) => setTimeout(resolve, 1000)) + await new Promise((resolve) => setTimeout(resolve, 500)) await TeleportService.teleportCharacter(character.id, { targetMapId: character.map.id, diff --git a/src/events/gameMaster/assetManager/characterHair/update.ts b/src/events/gameMaster/assetManager/characterHair/update.ts index dad4b66..88253b7 100644 --- a/src/events/gameMaster/assetManager/characterHair/update.ts +++ b/src/events/gameMaster/assetManager/characterHair/update.ts @@ -29,7 +29,7 @@ export default class CharacterHairUpdateEvent extends BaseEvent { return callback(false) } - await characterHair.setName(data.name).setGender(data.gender).setIsSelectable(data.isSelectable).setSprite(sprite).update() + await characterHair.setName(data.name).setGender(data.gender).setIsSelectable(data.isSelectable).setSprite(sprite).save() return callback(true) } catch (error) { this.logger.error(`Error updating character hair: ${error instanceof Error ? error.message : String(error)}`) diff --git a/src/events/gameMaster/assetManager/characterType/delete.ts b/src/events/gameMaster/assetManager/characterType/delete.ts index d466267..c959670 100644 --- a/src/events/gameMaster/assetManager/characterType/delete.ts +++ b/src/events/gameMaster/assetManager/characterType/delete.ts @@ -15,7 +15,8 @@ export default class CharacterTypeDeleteEvent extends BaseEvent { try { if (!(await this.isCharacterGM())) return - const characterType = await CharacterTypeRepository.getById(data.id) + const characterTypeRepository = new CharacterTypeRepository() + const characterType = await characterTypeRepository.getById(data.id) if (!characterType) return callback(false) await characterType.delete() diff --git a/src/events/gameMaster/assetManager/item/delete.ts b/src/events/gameMaster/assetManager/item/delete.ts index 62f1e39..0a65713 100644 --- a/src/events/gameMaster/assetManager/item/delete.ts +++ b/src/events/gameMaster/assetManager/item/delete.ts @@ -1,41 +1,30 @@ -import { Server } from 'socket.io' - -import { gameMasterLogger } from '#application/logger' -import prisma from '#application/prisma' -import { TSocket } from '#application/types' -import characterRepository from '#repositories/characterRepository' +import { BaseEvent } from '#application/base/baseEvent' +import { UUID } from '#application/types' +import ItemRepository from '#repositories/itemRepository' interface IPayload { - id: string + id: UUID } -export default class ItemDeleteEvent { - constructor( - private readonly io: Server, - private readonly socket: TSocket - ) {} - +export default class ItemDeleteEvent extends BaseEvent { public listen(): void { this.socket.on('gm:item:remove', this.handleEvent.bind(this)) } private async handleEvent(data: IPayload, callback: (response: boolean) => void): Promise { - 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.item.delete({ - where: { id: data.id } - }) + if (!(await this.isCharacterGM())) return - callback(true) + const itemRepository = new ItemRepository() + const item = await itemRepository.getById(data.id) + if (!item) return callback(false) + + await item.delete() + + return callback(true) } catch (error) { - gameMasterLogger.error(`Error deleting item ${data.id}: ${error instanceof Error ? error.message : String(error)}`) - callback(false) + this.logger.error(`Error deleting item ${data.id}: ${error instanceof Error ? error.message : String(error)}`) + return callback(false) } } } diff --git a/src/events/gameMaster/assetManager/item/list.ts b/src/events/gameMaster/assetManager/item/list.ts index e36b242..3ac957a 100644 --- a/src/events/gameMaster/assetManager/item/list.ts +++ b/src/events/gameMaster/assetManager/item/list.ts @@ -1,37 +1,25 @@ -import { Item } from '@prisma/client' -import { Server } from 'socket.io' - -import { gameMasterLogger } from '#application/logger' -import { TSocket } from '#application/types' -import characterRepository from '#repositories/characterRepository' -import itemRepository from '#repositories/itemRepository' +import { BaseEvent } from '#application/base/baseEvent' +import { Item } from '#entities/item' +import ItemRepository from '#repositories/itemRepository' interface IPayload {} -export default class ItemListEvent { - constructor( - private readonly io: Server, - private readonly socket: TSocket - ) {} - +export default class ItemListEvent extends BaseEvent { public listen(): void { this.socket.on('gm:item:list', this.handleEvent.bind(this)) } private async handleEvent(data: IPayload, callback: (response: Item[]) => void): Promise { - const character = await characterRepository.getById(this.socket.characterId as number) - if (!character) { - gameMasterLogger.error('gm:item:list error', 'Character not found') + try { + if (!(await this.isCharacterGM())) return + + const itemRepository = new ItemRepository() + + const items = await itemRepository.getAll() + return callback(items) + } catch (error) { + this.logger.error('gm:item:list error', error) return callback([]) } - - if (character.role !== 'gm') { - gameMasterLogger.info(`User ${character.id} tried to list items but is not a game master.`) - return callback([]) - } - - // get all items - const items = await itemRepository.getAll() - callback(items) } } diff --git a/src/events/gameMaster/assetManager/mapObject/list.ts b/src/events/gameMaster/assetManager/mapObject/list.ts index 1ae0f54..b6d7084 100644 --- a/src/events/gameMaster/assetManager/mapObject/list.ts +++ b/src/events/gameMaster/assetManager/mapObject/list.ts @@ -1,6 +1,7 @@ import { BaseEvent } from '#application/base/baseEvent' import { MapObject } from '#entities/mapObject' import ObjectRepository from '#repositories/mapObjectRepository' +import MapObjectRepository from '#repositories/mapObjectRepository' interface IPayload {} @@ -10,10 +11,17 @@ export default class MapObjectListEvent extends BaseEvent { } private async handleEvent(data: IPayload, callback: (response: MapObject[]) => void): Promise { - if (!(await this.isCharacterGM())) return + try { + if (!(await this.isCharacterGM())) return - // get all objects - const objects = await ObjectRepository.getAll() - return callback(objects) + // Get all map objects + const mapObjectRepository = new MapObjectRepository() + const mapObjects = await mapObjectRepository.getAll() + + return callback(mapObjects) + } catch (error) { + this.logger.error('gm:mapObject:list error', error) + return callback([]) + } } } diff --git a/src/events/gameMaster/assetManager/mapObject/remove.ts b/src/events/gameMaster/assetManager/mapObject/remove.ts index b394d49..6feff49 100644 --- a/src/events/gameMaster/assetManager/mapObject/remove.ts +++ b/src/events/gameMaster/assetManager/mapObject/remove.ts @@ -15,9 +15,8 @@ export default class MapObjectRemoveEvent extends BaseEvent { } private async handleEvent(data: IPayload, callback: (response: boolean) => void): Promise { - if (!(await this.isCharacterGM())) return - try { + if (!(await this.isCharacterGM())) return // remove the tile from the disk const finalFilePath = Storage.getPublicPath('map_objects', data.mapObjectId + '.png') fs.unlink(finalFilePath, async (err) => { @@ -27,7 +26,8 @@ export default class MapObjectRemoveEvent extends BaseEvent { return } - await (await MapObjectRepository.getById(data.mapObjectId))?.delete() + const mapObjectRepository = new MapObjectRepository() + await (await mapObjectRepository.getById(data.mapObjectId))?.delete() return callback(true) }) diff --git a/src/events/gameMaster/assetManager/mapObject/update.ts b/src/events/gameMaster/assetManager/mapObject/update.ts index d27ee86..9f01dbc 100644 --- a/src/events/gameMaster/assetManager/mapObject/update.ts +++ b/src/events/gameMaster/assetManager/mapObject/update.ts @@ -23,10 +23,12 @@ export default class MapObjectUpdateEvent extends BaseEvent { try { if (!(await this.isCharacterGM())) return - const mapObject = await MapObjectRepository.getById(data.id) + const mapObjectRepository = new MapObjectRepository() + + 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() + 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).save() return callback(true) } catch (error) { diff --git a/src/events/gameMaster/assetManager/mapObject/upload.ts b/src/events/gameMaster/assetManager/mapObject/upload.ts index 94ee017..2308def 100644 --- a/src/events/gameMaster/assetManager/mapObject/upload.ts +++ b/src/events/gameMaster/assetManager/mapObject/upload.ts @@ -33,7 +33,7 @@ export default class MapObjectUploadEvent extends BaseEvent { // 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() + await mapObject.setName('New map object').setTags([]).setOriginX(0).setOriginY(0).setFrameWidth(width).setFrameHeight(height).save() // Save image to disk const uuid = mapObject.getId() diff --git a/src/events/gameMaster/assetManager/sprite/copy.ts b/src/events/gameMaster/assetManager/sprite/copy.ts index 5565944..9ba4c48 100644 --- a/src/events/gameMaster/assetManager/sprite/copy.ts +++ b/src/events/gameMaster/assetManager/sprite/copy.ts @@ -1,7 +1,6 @@ import { BaseEvent } from '#application/base/baseEvent' import { UUID } from '#application/types' import { Sprite } from '#entities/sprite' -import CharacterRepository from '#repositories/characterRepository' import SpriteRepository from '#repositories/spriteRepository' interface CopyPayload { @@ -17,12 +16,16 @@ export default class SpriteCopyEvent extends BaseEvent { try { if (!(await this.isCharacterGM())) return - const sourceSprite = await SpriteRepository.getById(payload.id) + const spriteRepository = new SpriteRepository() + const sourceSprite = await spriteRepository.getById(payload.id) if (!sourceSprite) { throw new Error('Source sprite not found') } + // Populate source sprite with spriteActions + await spriteRepository.getEntityManager().populate(sourceSprite, ['spriteActions']) + const newSprite = new Sprite() await newSprite.setName(`${sourceSprite.getName()} (Copy)`).setSpriteActions(sourceSprite.getSpriteActions()).save() diff --git a/src/events/gameMaster/assetManager/sprite/delete.ts b/src/events/gameMaster/assetManager/sprite/delete.ts index ae792d0..7de40b5 100644 --- a/src/events/gameMaster/assetManager/sprite/delete.ts +++ b/src/events/gameMaster/assetManager/sprite/delete.ts @@ -15,11 +15,13 @@ export default class GMSpriteDeleteEvent extends BaseEvent { } private async handleEvent(data: Payload, callback: (response: boolean) => void): Promise { - if (!(await this.isCharacterGM())) return - try { + if (!(await this.isCharacterGM())) return + await this.deleteSpriteFolder(data.id) - await (await SpriteRepository.getById(data.id))?.delete() + + const spriteRepository = new SpriteRepository() + await (await spriteRepository.getById(data.id))?.delete() this.logger.info(`Sprite ${data.id} deleted.`) callback(true) diff --git a/src/events/gameMaster/assetManager/sprite/list.ts b/src/events/gameMaster/assetManager/sprite/list.ts index 75879fd..9965962 100644 --- a/src/events/gameMaster/assetManager/sprite/list.ts +++ b/src/events/gameMaster/assetManager/sprite/list.ts @@ -11,10 +11,18 @@ export default class SpriteListEvent extends BaseEvent { } private async handleEvent(data: IPayload, callback: (response: Sprite[]) => void): Promise { - if (!(await this.isCharacterGM())) return + try { + if (!(await this.isCharacterGM())) return - // get all sprites - const sprites = await SpriteRepository.getAll(['*']) - callback(sprites) + // Get all sprites + const spriteRepository = new SpriteRepository() + const sprites = await spriteRepository.getAll() + await spriteRepository.getEntityManager().populate(sprites, ['spriteActions']) + + return callback(sprites) + } catch (error) { + this.logger.error('gm:sprite:list error', error) + return callback([]) + } } } diff --git a/src/events/gameMaster/assetManager/tile/delete.ts b/src/events/gameMaster/assetManager/tile/delete.ts index 99ed68e..b371341 100644 --- a/src/events/gameMaster/assetManager/tile/delete.ts +++ b/src/events/gameMaster/assetManager/tile/delete.ts @@ -15,13 +15,15 @@ export default class GMTileDeleteEvent extends BaseEvent { } private async handleEvent(data: Payload, callback: (response: boolean) => void): Promise { - if (!(await this.isCharacterGM())) return - try { + if (!(await this.isCharacterGM())) return + this.logger.info(`Deleting tile ${data.id}`) await this.deleteTileFile(data.id) - await (await TileRepository.getById(data.id))?.delete() + + const tileRepository = new TileRepository() + await (await tileRepository.getById(data.id))?.delete() this.logger.info(`Tile ${data.id} deleted successfully.`) return callback(true) diff --git a/src/events/gameMaster/assetManager/tile/list.ts b/src/events/gameMaster/assetManager/tile/list.ts index f9d26fd..c68e231 100644 --- a/src/events/gameMaster/assetManager/tile/list.ts +++ b/src/events/gameMaster/assetManager/tile/list.ts @@ -10,10 +10,16 @@ export default class TileListEven extends BaseEvent { } private async handleEvent(data: IPayload, callback: (response: Tile[]) => void): Promise { - if (!(await this.isCharacterGM())) return + try { + if (!(await this.isCharacterGM())) return - // get all tiles - const tiles = await TileRepository.getAll() - return callback(tiles) + // Get all tiles + const tileRepository = new TileRepository() + const tiles = await tileRepository.getAll() + return callback(tiles) + } catch (error) { + this.logger.error('gm:tile:list error', error) + return callback([]) + } } } diff --git a/src/events/gameMaster/assetManager/tile/update.ts b/src/events/gameMaster/assetManager/tile/update.ts index 6a04e45..6c27afc 100644 --- a/src/events/gameMaster/assetManager/tile/update.ts +++ b/src/events/gameMaster/assetManager/tile/update.ts @@ -14,13 +14,20 @@ export default class TileUpdateEvent extends BaseEvent { } private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise { - if (!(await this.isCharacterGM())) return - try { - const tile = await TileRepository.getById(data.id) + if (!(await this.isCharacterGM())) return + + const tileRepository = new TileRepository() + + const tile = await tileRepository.getById(data.id) if (!tile) return callback(false) - await tile.setName(data.name).setTags(data.tags).update() + console.log(tile) + + await tile.setName(data.name).setTags(data.tags).save() + + console.log(tile) + return callback(true) } catch (error) { return callback(false) diff --git a/src/events/gameMaster/mapEditor/update.ts b/src/events/gameMaster/mapEditor/update.ts index 6012bbe..35e5d45 100644 --- a/src/events/gameMaster/mapEditor/update.ts +++ b/src/events/gameMaster/mapEditor/update.ts @@ -107,7 +107,7 @@ export default class MapUpdateEvent extends BaseEvent { } // Update map properties - await map.setName(data.name).setWidth(data.width).setHeight(data.height).setTiles(data.tiles).setPvp(data.pvp).setUpdatedAt(new Date()).update() + 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) diff --git a/src/models/mapCharacter.ts b/src/models/mapCharacter.ts index 27b65af..7ef02a8 100644 --- a/src/models/mapCharacter.ts +++ b/src/models/mapCharacter.ts @@ -16,7 +16,7 @@ class MapCharacter { } public async savePosition() { - await this.character.setPositionX(this.character.positionX).setPositionY(this.character.positionY).setRotation(this.character.rotation).setMap(this.character.map).update() + await this.character.setPositionX(this.character.positionX).setPositionY(this.character.positionY).setRotation(this.character.rotation).setMap(this.character.map).save() } public async teleport(mapId: number, targetX: number, targetY: number): Promise { diff --git a/src/repositories/itemRepository.ts b/src/repositories/itemRepository.ts index 9869675..75aff00 100644 --- a/src/repositories/itemRepository.ts +++ b/src/repositories/itemRepository.ts @@ -3,7 +3,7 @@ import { UUID } from '#application/types' import { Item } from '#entities/item' class ItemRepository extends BaseRepository { - async getById(id: UUID): Promise { + async getById(id: UUID): Promise { try { const repository = this.getEntityManager().getRepository(Item) return await repository.findOne({ id }) @@ -13,25 +13,23 @@ class ItemRepository extends BaseRepository { } } - async getByIds(ids: UUID[]): Promise { + async getByIds(ids: UUID[]): Promise { try { const repository = this.getEntityManager().getRepository(Item) - return await repository.find({ - id: ids - }) + return await repository.find({ id: ids }) } catch (error: any) { this.logger.error(`Failed to get items by IDs: ${error instanceof Error ? error.message : String(error)}`) - return null + return [] } } - async getAll(): Promise { + async getAll(): Promise { try { const repository = this.getEntityManager().getRepository(Item) return await repository.findAll() } catch (error: any) { this.logger.error(`Failed to get all items: ${error instanceof Error ? error.message : String(error)}`) - return null + return [] } } } diff --git a/src/services/teleportService.ts b/src/services/teleportService.ts index b59367a..33995f2 100644 --- a/src/services/teleportService.ts +++ b/src/services/teleportService.ts @@ -56,7 +56,7 @@ class TeleportService { } // Update character position and map - await mapCharacter.character.setPositionX(targetX).setPositionY(targetY).setRotation(rotation).setMap(targetMap.getMap()).update() + await mapCharacter.character.setPositionX(targetX).setPositionY(targetY).setRotation(rotation).setMap(targetMap.getMap()).save() // Join new map socket.join(targetMapId)