forked from noxious/server
112 lines
4.1 KiB
TypeScript
112 lines
4.1 KiB
TypeScript
import { Server } from 'socket.io'
|
|
import { TSocket, ZoneEventTileWithTeleport } from '#application/types'
|
|
import { CharacterService } from '#services/characterService'
|
|
import { ZoneEventTileService } from '#services/zoneEventTileService'
|
|
import Rotation from '#application/character/rotation'
|
|
import { gameLogger } from '#application/logger'
|
|
import ZoneManager from '#managers/zoneManager'
|
|
import ZoneCharacter from '#models/zoneCharacter'
|
|
import zoneEventTileRepository from '#repositories/zoneEventTileRepository'
|
|
|
|
export default class CharacterMove {
|
|
private readonly characterService = new CharacterService()
|
|
private readonly zoneEventTileService = new ZoneEventTileService()
|
|
|
|
constructor(
|
|
private readonly io: Server,
|
|
private readonly socket: TSocket
|
|
) {}
|
|
|
|
public listen(): void {
|
|
this.socket.on('character:move', this.handleCharacterMove.bind(this))
|
|
}
|
|
|
|
private async handleCharacterMove({ positionX, positionY }: { positionX: number; positionY: number }): Promise<void> {
|
|
const zoneCharacter = ZoneManager.getCharacter(this.socket.characterId!)
|
|
if (!zoneCharacter?.character) {
|
|
gameLogger.error('character:move error', 'Character not found or not initialized')
|
|
return
|
|
}
|
|
|
|
// If already moving, cancel current movement and wait for it to fully stop
|
|
if (zoneCharacter.isMoving) {
|
|
zoneCharacter.isMoving = false
|
|
await new Promise((resolve) => setTimeout(resolve, 100))
|
|
}
|
|
|
|
const path = await this.characterService.calculatePath(zoneCharacter.character, positionX, positionY)
|
|
if (!path) {
|
|
this.io.in(zoneCharacter.character.zone!.id.toString()).emit('character:moveError', 'No valid path found')
|
|
return
|
|
}
|
|
|
|
// Start new movement
|
|
zoneCharacter.isMoving = true
|
|
zoneCharacter.currentPath = path // Add this property to ZoneCharacter class
|
|
await this.moveAlongPath(zoneCharacter, path)
|
|
}
|
|
|
|
private async moveAlongPath(zoneCharacter: ZoneCharacter, path: Array<{ x: number; y: number }>): Promise<void> {
|
|
const { character } = zoneCharacter
|
|
|
|
for (let i = 0; i < path.length - 1; i++) {
|
|
if (!zoneCharacter.isMoving || zoneCharacter.currentPath !== path) {
|
|
return
|
|
}
|
|
|
|
const [start, end] = [path[i], path[i + 1]]
|
|
character.rotation = Rotation.calculate(start.x, start.y, end.x, end.y)
|
|
|
|
const zoneEventTile = await zoneEventTileRepository.getEventTileByZoneIdAndPosition(character.zone!.id, Math.floor(end.x), Math.floor(end.y))
|
|
|
|
if (zoneEventTile?.type === 'BLOCK') break
|
|
if (zoneEventTile?.type === 'TELEPORT' && zoneEventTile.teleport) {
|
|
await this.handleZoneEventTile(zoneEventTile as ZoneEventTileWithTeleport)
|
|
break
|
|
}
|
|
|
|
// Update position first
|
|
character.positionX = end.x
|
|
character.positionY = end.y
|
|
|
|
// Then emit with the same properties
|
|
this.io.in(character.zone!.id.toString()).emit('character:move', {
|
|
id: character.id,
|
|
positionX: character.positionX,
|
|
positionY: character.positionY,
|
|
rotation: character.rotation,
|
|
isMoving: true
|
|
})
|
|
|
|
await this.characterService.applyMovementDelay()
|
|
}
|
|
|
|
if (zoneCharacter.isMoving && zoneCharacter.currentPath === path) {
|
|
this.finalizeMovement(zoneCharacter)
|
|
}
|
|
}
|
|
|
|
private async handleZoneEventTile(zoneEventTile: ZoneEventTileWithTeleport): Promise<void> {
|
|
const zoneCharacter = ZoneManager.getCharacter(this.socket.characterId!)
|
|
if (!zoneCharacter) {
|
|
gameLogger.error('character:move error', 'Character not found')
|
|
return
|
|
}
|
|
|
|
if (zoneEventTile.teleport) {
|
|
await this.zoneEventTileService.handleTeleport(this.io, this.socket, zoneCharacter.character, zoneEventTile.teleport)
|
|
}
|
|
}
|
|
|
|
private finalizeMovement(zoneCharacter: ZoneCharacter): void {
|
|
zoneCharacter.isMoving = false
|
|
this.io.in(zoneCharacter.character.zone!.id.toString()).emit('character:move', {
|
|
id: zoneCharacter.character.id,
|
|
positionX: zoneCharacter.character.positionX,
|
|
positionY: zoneCharacter.character.positionY,
|
|
rotation: zoneCharacter.character.rotation,
|
|
isMoving: false
|
|
})
|
|
}
|
|
}
|