import { Character, Zone } from '@prisma/client' import ZoneRepository from '../repositories/zoneRepository' import ZoneService from '../services/zoneService' import zoneRepository from '../repositories/zoneRepository' import logger from '../utilities/logger' type TLoadedZone = { zone: Zone characters: Character[] grid: number[][] } class ZoneManager { private loadedZones: TLoadedZone[] = [] // Method to initialize zoneEditor manager public async boot() { if (!(await ZoneRepository.getById(1))) { const zoneService = new ZoneService() await zoneService.createDemoZone() } const zones = await ZoneRepository.getAll() for (const zone of zones) { await this.loadZone(zone) } logger.info('Zone manager loaded') } // Method to handle individual zoneEditor loading public async loadZone(zone: Zone) { const grid = await this.getGrid(zone.id) // Create the grid for the zoneEditor this.loadedZones.push({ zone, characters: [], grid }) logger.info(`Zone ID ${zone.id} loaded`) } // Method to handle individual zoneEditor unloading public unloadZone(zoneId: number) { this.loadedZones = this.loadedZones.filter((loadedZone) => { return loadedZone.zone.id !== zoneId }) logger.info(`Zone ID ${zoneId} unloaded`) } // Getter for loaded zones public getLoadedZones(): TLoadedZone[] { return this.loadedZones } // Check if position is walkable private isPositionWalkable(zoneId: number, x: number, y: number): boolean { const loadedZone = this.loadedZones.find((lz) => lz.zone.id === zoneId) if (!loadedZone) { console.log(`Zone ${zoneId} not found in loadedZones`) return false } if (!loadedZone.grid) { console.log(`Grid for zone ${zoneId} is undefined`) return false } if (!loadedZone.grid[y]) { console.log(`Row ${y} in grid for zone ${zoneId} is undefined`) return false } return loadedZone.grid[y][x] === 0 } public addCharacterToZone(zoneId: number, character: Character) { console.log(`Adding character ${character.id} to zone ${zoneId}`) console.log(`Character position: x=${character.positionX}, y=${character.positionY}`) const loadedZone = this.loadedZones.find((loadedZone) => { return loadedZone.zone.id === zoneId }) if (!loadedZone) { console.log(`Zone ${zoneId} not found in loadedZones`) return } if (this.isPositionWalkable(zoneId, character.positionX, character.positionY)) { loadedZone.characters.push(character) console.log(`Character ${character.id} added to zone ${zoneId}`) } else { // set position to 0,0 if not walkable console.log(`Position (${character.positionX}, ${character.positionY}) is not walkable in zone ${zoneId}`) character.positionX = 0 character.positionY = 0 loadedZone.characters.push(character) } } public removeCharacterFromZone(zoneId: number, character: Character) { const loadedZone = this.loadedZones.find((loadedZone) => { return loadedZone.zone.id === zoneId }) if (loadedZone) { loadedZone.characters = loadedZone.characters.filter((loadedCharacter) => { return loadedCharacter.id !== character.id }) } } public updateCharacterInZone(zoneId: number, character: Character) { const loadedZone = this.loadedZones.find((loadedZone) => { return loadedZone.zone.id === zoneId }) if (loadedZone) { const characterIndex = loadedZone.characters.findIndex((loadedCharacter) => { return loadedCharacter.id === character.id }) if (characterIndex !== -1) { loadedZone.characters[characterIndex] = character } } } public getCharactersInZone(zoneId: number): Character[] { const loadedZone = this.loadedZones.find((loadedZone) => { return loadedZone.zone.id === zoneId }) return loadedZone ? loadedZone.characters : [] } public async getGrid(zoneId: number): Promise { const zone = this.loadedZones.find((z) => z.zone.id === zoneId) if (zone) return zone.grid const loadedZone = await ZoneRepository.getById(zoneId) if (!loadedZone) return [] let grid: number[][] = Array.from({ length: loadedZone.height }, () => Array.from({ length: loadedZone.width }, () => 0)) const eventTiles = await zoneRepository.getEventTiles(zoneId) // Set the grid values based on the event tiles, these are strings eventTiles.forEach((eventTile) => { if (eventTile.type === 'BLOCK') { grid[eventTile.positionY][eventTile.positionX] = 1 } }) return grid } } export default new ZoneManager()