From 358aa795e439134c6d7df62fc030f830e5d5ad50 Mon Sep 17 00:00:00 2001 From: Dennis Postma Date: Sat, 7 Sep 2024 22:28:36 +0200 Subject: [PATCH] Fixes for teleporting between zones --- src/events/zone/characterJoin.ts | 4 +-- src/events/zone/characterLeave.ts | 2 +- src/events/zone/characterMoveEvent.ts | 33 +++++++++++++------- src/managers/zoneManager.ts | 27 +++++++++++++++++ src/services/zoneEventTileService.ts | 43 ++++++++++++++++++--------- 5 files changed, 81 insertions(+), 28 deletions(-) diff --git a/src/events/zone/characterJoin.ts b/src/events/zone/characterJoin.ts index a115e97..b1801f7 100644 --- a/src/events/zone/characterJoin.ts +++ b/src/events/zone/characterJoin.ts @@ -20,7 +20,7 @@ interface IResponse { * @param io */ export default function (socket: TSocket, io: Server) { - socket.on('zone:characterJoin', async (data: IPayload, callback: (response: IResponse) => void) => { + socket.on('zone:character:join', async (data: IPayload, callback: (response: IResponse) => void) => { try { console.log(`---User ${socket.character?.id} has requested zone.`) @@ -46,7 +46,7 @@ export default function (socket: TSocket, io: Server) { socket.join(zone.id.toString()) // let other clients know of new character - io.to(zone.id.toString()).emit('zone:characterJoin', socket.character) + io.to(zone.id.toString()).emit('zone:character:join', socket.character) // add character to zone manager ZoneManager.addCharacterToZone(zone.id, socket.character as Character) diff --git a/src/events/zone/characterLeave.ts b/src/events/zone/characterLeave.ts index 4881720..0a69239 100644 --- a/src/events/zone/characterLeave.ts +++ b/src/events/zone/characterLeave.ts @@ -10,7 +10,7 @@ import { Character, Zone } from '@prisma/client' * @param io */ export default function (socket: TSocket, io: Server) { - socket.on('zone:characterLeave', async () => { + socket.on('zone:character:leave', async () => { console.log(`---Socket ${socket.character?.id} has leaved zone.`) if (!socket.character) { diff --git a/src/events/zone/characterMoveEvent.ts b/src/events/zone/characterMoveEvent.ts index 2cbaf1a..f3e7d2a 100644 --- a/src/events/zone/characterMoveEvent.ts +++ b/src/events/zone/characterMoveEvent.ts @@ -9,7 +9,7 @@ import Rotation from '../../utilities/character/rotation' import logger from '../../utilities/logger' type ZoneEventTileWithTeleport = ZoneEventTile & { - teleport: ZoneEventTileTeleport | null + teleport: ZoneEventTileTeleport } export default class CharacterMoveEvent { @@ -62,25 +62,36 @@ export default class CharacterMoveEvent { const zoneEventTile = await prisma.zoneEventTile.findFirst({ where: { zoneId: character.zoneId, - type: 'TELEPORT', positionX: Math.floor(end.x), positionY: Math.floor(end.y) - }, - include: { teleport: true } - }) as ZoneEventTileWithTeleport | null + } + }); if (zoneEventTile) { - await this.handleZoneEventTile(zoneEventTile) - break + if (zoneEventTile.type === 'BLOCK') { + break; + } + + if (zoneEventTile.type === 'TELEPORT') { + const teleportTile = await prisma.zoneEventTile.findFirst({ + where: { id: zoneEventTile.id }, + include: { teleport: true } + }) as ZoneEventTileWithTeleport; + + if (teleportTile) { + await this.handleZoneEventTile(teleportTile); + break; + } + } } - await this.characterMoveService.updatePosition(character, end) - this.io.in(character.zoneId.toString()).emit('character:move', character) + await this.characterMoveService.updatePosition(character, end); + this.io.in(character.zoneId.toString()).emit('character:move', character); - await this.characterMoveService.applyMovementDelay() + await this.characterMoveService.applyMovementDelay(); } - this.finalizeMovement(character) + this.finalizeMovement(character); } private async handleZoneEventTile(zoneEventTile: ZoneEventTileWithTeleport): Promise { diff --git a/src/managers/zoneManager.ts b/src/managers/zoneManager.ts index 8dbd542..3f7bfe2 100644 --- a/src/managers/zoneManager.ts +++ b/src/managers/zoneManager.ts @@ -148,6 +148,33 @@ class ZoneManager { return grid } + + public async moveCharacterBetweenZones(oldZoneId: number, newZoneId: number, character: Character): Promise { + // Find the old and new zones + const oldZone = this.loadedZones.find(zone => zone.zone.id === oldZoneId); + const newZone = this.loadedZones.find(zone => zone.zone.id === newZoneId); + + if (!oldZone || !newZone) { + logger.error(`Unable to move character ${character.id}: zones not found`); + return; + } + + // Remove character from old zone + oldZone.characters = oldZone.characters.filter(c => c.id !== character.id); + + // Check if the new position is walkable + if (this.isPositionWalkable(newZoneId, character.positionX, character.positionY)) { + newZone.characters.push(character); + } else { + // Set position to 0,0 if not walkable + logger.warn(`Position (${character.positionX}, ${character.positionY}) is not walkable in zone ${newZoneId}. Moving character to (0,0).`); + character.positionX = 0; + character.positionY = 0; + newZone.characters.push(character); + } + + logger.info(`Character ${character.id} moved from zone ${oldZoneId} to zone ${newZoneId}`); + } } export default new ZoneManager() diff --git a/src/services/zoneEventTileService.ts b/src/services/zoneEventTileService.ts index aa4d6fb..2afefb9 100644 --- a/src/services/zoneEventTileService.ts +++ b/src/services/zoneEventTileService.ts @@ -7,29 +7,44 @@ import { Server } from 'socket.io' export class ZoneEventTileService { public async handleTeleport(io: Server, socket: TSocket, character: ExtendedCharacter, teleport: ZoneEventTileTeleport): Promise { - if (teleport.toZoneId === character.zoneId) return + if (teleport.toZoneId === character.zoneId) return; - const zone = await ZoneRepository.getById(teleport.toZoneId) - if (!zone) return + const zone = await ZoneRepository.getById(teleport.toZoneId); + if (!zone) return; - const oldZoneId = character.zoneId - const newZoneId = teleport.toZoneId + const oldZoneId = character.zoneId; + const newZoneId = teleport.toZoneId; - character.zoneId = teleport.toZoneId - character.positionX = teleport.toPositionX - character.positionY = teleport.toPositionY + // Update character in database + await prisma.character.update({ + where: { id: character.id }, + data: { + zoneId: newZoneId, + positionX: teleport.toPositionX, + positionY: teleport.toPositionY + } + }); - socket.leave(character.zoneId.toString()) - socket.join(teleport.toZoneId.toString()) + // Update local character object + character.zoneId = newZoneId; + character.positionX = teleport.toPositionX; + character.positionY = teleport.toPositionY; - io.to(oldZoneId.toString()).emit('zone:character:leave', character); + // Atomic operation in ZoneManager + await ZoneManager.moveCharacterBetweenZones(oldZoneId, newZoneId, character as Character); + + // Emit events + io.to(oldZoneId.toString()).emit('zone:character:leave', character.id); io.to(newZoneId.toString()).emit('zone:character:join', character); - ZoneManager.removeCharacterFromZone(oldZoneId, character as Character); - ZoneManager.addCharacterToZone(newZoneId, character as Character); + // Update socket rooms + socket.leave(oldZoneId.toString()); + socket.join(newZoneId.toString()); + + // Send teleport information to the client socket.emit('zone:teleport', { zone, characters: ZoneManager.getCharactersInZone(zone.id) - }) + }); } }