111 lines
4.1 KiB
TypeScript
111 lines
4.1 KiB
TypeScript
import { SocketEvent } from '@/application/enums'
|
|
import Logger, { LoggerType } from '@/application/logger'
|
|
import type { UUID } from '@/application/types'
|
|
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'
|
|
import CharacterMoveService from '@/services/characterMoveService'
|
|
|
|
interface TeleportOptions {
|
|
targetMapId: UUID
|
|
targetX: number
|
|
targetY: number
|
|
rotation?: number
|
|
isInitialJoin?: boolean
|
|
character?: Character
|
|
}
|
|
|
|
class CharacterTeleportService {
|
|
private readonly logger = Logger.type(LoggerType.GAME)
|
|
|
|
public async teleportCharacter(characterId: UUID, options: TeleportOptions): Promise<boolean> {
|
|
try {
|
|
const { socket, targetMap, mapCharacter } = await this.validateTeleportRequest(characterId, options)
|
|
if (!socket || !targetMap || !mapCharacter) return false
|
|
|
|
const currentMapId = mapCharacter.character.map.id
|
|
const currentMap = MapManager.getMapById(currentMapId)
|
|
const io = SocketManager.getIO()
|
|
|
|
// Update character position and map
|
|
await this.updateCharacterPosition(mapCharacter, options, targetMap)
|
|
|
|
// Handle same map teleport
|
|
if (currentMapId === options.targetMapId && !options.isInitialJoin) {
|
|
CharacterMoveService.broadcastMovement(mapCharacter.character, false)
|
|
return true
|
|
}
|
|
|
|
// Handle map transition
|
|
await this.handleMapTransition(socket, io, currentMapId, currentMap, options.targetMapId, targetMap, characterId, mapCharacter)
|
|
|
|
return true
|
|
} catch (error) {
|
|
this.logger.error(`Teleport error for character ${characterId}: ${error}`)
|
|
return false
|
|
}
|
|
}
|
|
|
|
private async validateTeleportRequest(characterId: UUID, options: TeleportOptions) {
|
|
const socket = SocketManager.getSocketByCharacterId(characterId)
|
|
const targetMap = MapManager.getMapById(options.targetMapId)
|
|
|
|
if (!socket || !targetMap) {
|
|
this.logger.error(`Teleport failed - Missing socket or target map for character ${characterId}`)
|
|
return { socket: null, targetMap: null, mapCharacter: null }
|
|
}
|
|
|
|
if (options.isInitialJoin && !options.character) {
|
|
this.logger.error('Initial join requires character data')
|
|
return { socket, targetMap, mapCharacter: null }
|
|
}
|
|
|
|
const existingCharacter = !options.isInitialJoin && MapManager.getCharacterById(characterId)
|
|
const mapCharacter = options.isInitialJoin ? new MapCharacter(options.character!) : existingCharacter || null
|
|
|
|
if (!mapCharacter) {
|
|
this.logger.error(`Teleport failed - Character ${characterId} not found in MapManager`)
|
|
}
|
|
|
|
return { socket, targetMap, mapCharacter }
|
|
}
|
|
|
|
private async updateCharacterPosition(mapCharacter: MapCharacter, options: TeleportOptions, targetMap: any) {
|
|
await mapCharacter
|
|
.getCharacter()
|
|
.setPositionX(options.targetX)
|
|
.setPositionY(options.targetY)
|
|
.setRotation(options.rotation ?? 0)
|
|
.setMap(targetMap.getMap())
|
|
.save()
|
|
}
|
|
|
|
private async handleMapTransition(socket: any, io: any, currentMapId: UUID | undefined, currentMap: any, targetMapId: UUID, targetMap: any, characterId: UUID, mapCharacter: MapCharacter) {
|
|
// Clean up current map
|
|
if (currentMapId && currentMap) {
|
|
socket.leave(currentMapId)
|
|
await currentMap.removeCharacter(characterId)
|
|
io.in(currentMapId).emit(SocketEvent.MAP_CHARACTER_LEAVE, characterId)
|
|
}
|
|
|
|
// Join new map
|
|
socket.join(targetMapId)
|
|
targetMap.addCharacter(mapCharacter.getCharacter())
|
|
|
|
const mapRepository = new MapRepository()
|
|
const map = await mapRepository.getById(targetMapId)
|
|
await mapRepository.getEntityManager().populate(map!, mapRepository.POPULATE_TELEPORT as any)
|
|
|
|
// Notify clients
|
|
io.in(targetMapId).emit(SocketEvent.MAP_CHARACTER_JOIN, mapCharacter)
|
|
socket.emit(SocketEvent.MAP_CHARACTER_TELEPORT, {
|
|
mapId: targetMapId,
|
|
characters: targetMap.getCharactersInMap()
|
|
})
|
|
}
|
|
}
|
|
|
|
export default new CharacterTeleportService()
|