More teleport improvements

This commit is contained in:
2025-02-16 18:54:20 +01:00
parent 1191e6bf55
commit 4cf87536ce
3 changed files with 90 additions and 70 deletions

View File

@ -21,72 +21,25 @@ class CharacterTeleportService {
private readonly logger = Logger.type(LoggerType.GAME)
public async teleportCharacter(characterId: UUID, options: TeleportOptions): Promise<boolean> {
const mapRepository = new MapRepository()
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 false
}
if (options.isInitialJoin && !options.character) {
this.logger.error('Initial join requires character data')
return false
}
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`)
return null
})()
if (!mapCharacter) return false
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 mapCharacter
.getCharacter()
.setPositionX(options.targetX)
.setPositionY(options.targetY)
.setRotation(options.rotation ?? 0)
.setMap(targetMap.getMap())
.save()
await this.updateCharacterPosition(mapCharacter, options, targetMap)
// If the current map is the target map and we are not joining, send move event
// Handle same map teleport
if (currentMapId === options.targetMapId && !options.isInitialJoin) {
// If the current map is the target map, send move event
CharacterMoveService.broadcastMovement(mapCharacter.character, false)
return true
}
// Handle current map cleanup
if (currentMapId && currentMap) {
socket.leave(currentMapId)
await currentMap.removeCharacter(characterId)
io.in(currentMapId).emit(SocketEvent.MAP_CHARACTER_LEAVE, characterId)
}
// Join new map
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(options.targetMapId).emit(SocketEvent.MAP_CHARACTER_JOIN, mapCharacter)
socket.emit(SocketEvent.MAP_CHARACTER_TELEPORT, {
mapId: options.targetMapId,
characters: targetMap.getCharactersInMap()
})
// Handle map transition
await this.handleMapTransition(socket, io, currentMapId, currentMap, options.targetMapId, targetMap, characterId, mapCharacter)
return true
} catch (error) {
@ -94,6 +47,64 @@ class CharacterTeleportService {
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()