diff --git a/src/entities/map.ts b/src/entities/map.ts index 2eddb52..4608c3b 100644 --- a/src/entities/map.ts +++ b/src/entities/map.ts @@ -2,11 +2,8 @@ import { randomUUID } from 'node:crypto' import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core' -import { Character } from './character' -import { Chat } from './chat' import { MapEffect } from './mapEffect' import { MapEventTile } from './mapEventTile' -import { MapEventTileTeleport } from './mapEventTileTeleport' import { BaseEntity } from '#application/base/baseEntity' import { UUID } from '#application/types' @@ -44,10 +41,7 @@ export class Map extends BaseEntity { @OneToMany(() => MapEventTile, (tile) => tile.map, { orphanRemoval: true }) mapEventTiles = new Collection(this) - @OneToMany(() => PlacedMapObject, (pmo) => pmo.map, { - name: 'placedMapObjects', - orphanRemoval: true - }) + @OneToMany(() => PlacedMapObject, (placedMapObject) => placedMapObject.map, { orphanRemoval: true }) placedMapObjects = new Collection(this) setId(id: UUID) { diff --git a/src/events/gameMaster/mapEditor/request.ts b/src/events/gameMaster/mapEditor/request.ts index d9211ef..c742d4c 100644 --- a/src/events/gameMaster/mapEditor/request.ts +++ b/src/events/gameMaster/mapEditor/request.ts @@ -25,15 +25,13 @@ export default class MapRequestEvent extends BaseEvent { const mapRepository = new MapRepository() const map = await mapRepository.getById(data.mapId) + await mapRepository.getEntityManager().populate(map!, mapRepository.POPULATE_MAP_EDITOR as any) if (!map) { this.logger.info(`User ${(await this.getCharacter())!.getId()} tried to request map ${data.mapId} but it does not exist.`) return callback(null) } - // Populate map with mapEventTiles and placedMapObjects - await mapRepository.getEntityManager().populate(map, ['mapEffects', 'mapEventTiles', 'placedMapObjects', 'placedMapObjects.mapObject']) - return callback(map) } catch (error: any) { this.logger.error('gm:map:request error', error.message) diff --git a/src/events/gameMaster/mapEditor/update.ts b/src/events/gameMaster/mapEditor/update.ts index ee56254..af3fec4 100644 --- a/src/events/gameMaster/mapEditor/update.ts +++ b/src/events/gameMaster/mapEditor/update.ts @@ -32,7 +32,6 @@ interface IPayload { } export default class MapUpdateEvent extends BaseEvent { - private readonly populateOptions = ['mapEventTiles', 'placedMapObjects', 'mapEffects']; public listen(): void { this.socket.on('gm:map:update', this.handleEvent.bind(this)) } @@ -57,8 +56,7 @@ export default class MapUpdateEvent extends BaseEvent { return callback(null) } - // @ts-ignore - await mapRepository.getEntityManager().populate(map, this.populateOptions) + await mapRepository.getEntityManager().populate(map, mapRepository.POPULATE_MAP_EDITOR as any) // Validation logic remains the same if (data.tiles.length > data.height) { @@ -122,9 +120,7 @@ export default class MapUpdateEvent extends BaseEvent { // Reload map from database to get fresh data map = await mapRepository.getById(data.mapId) - - // @ts-ignore - await mapRepository.getEntityManager().populate(map!, this.populateOptions) + 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.`) diff --git a/src/managers/mapManager.ts b/src/managers/mapManager.ts index ebafd22..564fdf5 100644 --- a/src/managers/mapManager.ts +++ b/src/managers/mapManager.ts @@ -12,6 +12,8 @@ class MapManager { public async boot(): Promise { const mapRepository = new MapRepository() const maps = await mapRepository.getAll() + await mapRepository.getEntityManager().populate(maps, mapRepository.POPULATE_ALL as never[]) + await Promise.all(maps.map((map) => this.loadMap(map))) this.logger.info(`Map manager loaded with ${Object.keys(this.maps).length} maps`) diff --git a/src/repositories/mapRepository.ts b/src/repositories/mapRepository.ts index 4bea1d1..92928da 100644 --- a/src/repositories/mapRepository.ts +++ b/src/repositories/mapRepository.ts @@ -2,9 +2,12 @@ import { BaseRepository } from '#application/base/baseRepository' import { UUID } from '#application/types' import { Map } from '#entities/map' import { MapEventTile } from '#entities/mapEventTile' -import { MapObject } from '#entities/mapObject' class MapRepository extends BaseRepository { + public readonly POPULATE_ALL = ['*'] + public readonly POPULATE_MAP_EDITOR = ['mapEventTiles', 'placedMapObjects', 'mapEffects'] + public readonly POPULATE_TELEPORT = ['placedMapObjects', 'mapEffects'] + async getFirst(): Promise { try { const repository = this.getEntityManager().getRepository(Map) diff --git a/src/services/chatService.ts b/src/services/chatService.ts index 4122a16..32c22b5 100644 --- a/src/services/chatService.ts +++ b/src/services/chatService.ts @@ -1,20 +1,20 @@ -import { Server } from 'socket.io' - import { BaseService } from '#application/base/baseService' -import { TSocket, UUID } from '#application/types' +import { UUID } from '#application/types' import { Chat } from '#entities/chat' import SocketManager from '#managers/socketManager' import CharacterRepository from '#repositories/characterRepository' -import ChatRepository from '#repositories/chatRepository' import MapRepository from '#repositories/mapRepository' class ChatService extends BaseService { async sendMapMessage(characterId: UUID, mapId: UUID, message: string): Promise { try { - const character = await CharacterRepository.getById(characterId) + const characterRepository = new CharacterRepository() + const mapRepository = new MapRepository() + + const character = await characterRepository.getById(characterId) if (!character) return false - const map = await MapRepository.getById(mapId) + const map = await mapRepository.getById(mapId) if (!map) return false const chat = new Chat() diff --git a/src/services/teleportService.ts b/src/services/teleportService.ts index 33995f2..6e2686b 100644 --- a/src/services/teleportService.ts +++ b/src/services/teleportService.ts @@ -4,6 +4,7 @@ import { Character } from '#entities/character' import MapManager from '#managers/mapManager' import SocketManager from '#managers/socketManager' import MapCharacter from '#models/mapCharacter' +import MapRepository from '#repositories/mapRepository' interface TeleportOptions { targetMapId: UUID @@ -18,24 +19,23 @@ class TeleportService { private readonly logger = Logger.type(LoggerType.GAME) public async teleportCharacter(characterId: UUID, options: TeleportOptions): Promise { - const { targetMapId, targetX, targetY, rotation = 0, isInitialJoin = false, character } = options - + const mapRepository = new MapRepository() const socket = SocketManager.getSocketByCharacterId(characterId) - const targetMap = MapManager.getMapById(targetMapId) + const targetMap = MapManager.getMapById(options.targetMapId) if (!socket || !targetMap) { this.logger.error(`Teleport failed - Missing socket or target map for character ${characterId}`) return false } - if (isInitialJoin && !character) { + if (options.isInitialJoin && !options.character) { this.logger.error('Initial join requires character data') return false } - const existingCharacter = !isInitialJoin && MapManager.getCharacterById(characterId) - const mapCharacter = isInitialJoin - ? new MapCharacter(character!) + const existingCharacter = !options.isInitialJoin && MapManager.getCharacterById(characterId) + const mapCharacter = options.isInitialJoin + ? new MapCharacter(options.character!) : existingCharacter || (() => { this.logger.error(`Teleport failed - Character ${characterId} not found in MapManager`) @@ -56,16 +56,19 @@ class TeleportService { } // Update character position and map - await mapCharacter.character.setPositionX(targetX).setPositionY(targetY).setRotation(rotation).setMap(targetMap.getMap()).save() + await mapCharacter.getCharacter().setPositionX(options.targetX).setPositionY(options.targetY).setRotation(options.rotation ?? 0).setMap(targetMap.getMap()).save() // Join new map - socket.join(targetMapId) - targetMap.addCharacter(mapCharacter.character) + socket.join(options.targetMapId) + targetMap.addCharacter(mapCharacter.getCharacter()) + + const map = await mapRepository.getById(options.targetMapId) + await mapRepository.getEntityManager().populate(map!, mapRepository.POPULATE_TELEPORT as any) // Notify clients - io.in(targetMapId).emit('map:character:join', mapCharacter) + io.in(options.targetMapId).emit('map:character:join', mapCharacter) socket.emit('map:character:teleport', { - map: targetMap.getMap(), + map: map, characters: targetMap.getCharactersInMap() })