Disconnect fix, move improvements, baseEvent improvement
This commit is contained in:
parent
e40a56825a
commit
deac2892fb
@ -28,6 +28,7 @@ export abstract class BaseEvent {
|
||||
}
|
||||
|
||||
protected async getCharacter(): Promise<Character | null> {
|
||||
if (!this.socket.characterId) return null
|
||||
const characterRepository = new CharacterRepository()
|
||||
return characterRepository.getById(this.socket.characterId)
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import MapManager from '@/managers/mapManager'
|
||||
|
||||
export default class DisconnectEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on(SocketEvent.DISCONNECT, this.handleEvent.bind(this))
|
||||
this.socket.on('disconnect', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(): Promise<void> {
|
||||
@ -16,7 +16,7 @@ export default class DisconnectEvent extends BaseEvent {
|
||||
|
||||
this.io.emit(SocketEvent.USER_DISCONNECT, this.socket.userId)
|
||||
|
||||
const mapCharacter = MapManager.getCharacterById(this.socket.characterId)
|
||||
const mapCharacter = MapManager.getCharacterById(this.socket.characterId!)
|
||||
if (!mapCharacter) {
|
||||
this.logger.info('User disconnected but had no character set')
|
||||
return
|
||||
|
@ -9,54 +9,59 @@ import TeleportService from '@/services/characterTeleportService'
|
||||
|
||||
export default class CharacterMove extends BaseEvent {
|
||||
private readonly characterService = CharacterService
|
||||
private readonly MOVEMENT_THROTTLE = 230 // Minimum time between movement requests
|
||||
private readonly STEP_DELAY = 150 // Milliseconds between each tile movement
|
||||
private readonly THROTTLE_DELAY = 230 // Minimum time between movement requests
|
||||
private movementTimeout: NodeJS.Timeout | null = null
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on(SocketEvent.MAP_CHARACTER_MOVE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent({ positionX, positionY }: { positionX: number; positionY: number }): Promise<void> {
|
||||
const mapCharacter = MapManager.getCharacterById(this.socket.characterId)
|
||||
if (!mapCharacter?.getCharacter()) {
|
||||
this.logger.error('map:character:move error: Character not found or not initialized')
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isThrottled(`movement_${this.socket.characterId}`, this.MOVEMENT_THROTTLE)) {
|
||||
// Only cancel current movement if the new target is different
|
||||
if (mapCharacter.isMoving && (Math.floor(positionX) !== Math.floor(mapCharacter.character.positionX) || Math.floor(positionY) !== Math.floor(mapCharacter.character.positionY))) {
|
||||
mapCharacter.isMoving = false
|
||||
mapCharacter.currentPath = null
|
||||
// this.finalizeMovement(mapCharacter)
|
||||
try {
|
||||
const mapCharacter = MapManager.getCharacterById(this.socket.characterId!)
|
||||
if (!mapCharacter?.getCharacter()) {
|
||||
this.logger.error('map:character:move error: Character not found or not initialized')
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// If already moving, cancel current movement
|
||||
if (mapCharacter.isMoving && mapCharacter.currentPath && mapCharacter.currentPath.length > 2) {
|
||||
// Cancel any ongoing movement
|
||||
this.cancelCurrentMovement(mapCharacter)
|
||||
|
||||
// Throttle rapid movement requests
|
||||
if (this.isThrottled(`movement_${this.socket.characterId}`, this.THROTTLE_DELAY)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Calculate path to target position
|
||||
const path = await this.characterService.calculatePath(mapCharacter.character, Math.floor(positionX), Math.floor(positionY))
|
||||
|
||||
if (!path?.length) {
|
||||
this.io.in(mapCharacter.character.map.id).emit(SocketEvent.MAP_CHARACTER_MOVEERROR, 'No valid path found')
|
||||
return
|
||||
}
|
||||
|
||||
// Start new movement
|
||||
mapCharacter.isMoving = true
|
||||
mapCharacter.currentPath = path
|
||||
await this.moveAlongPath(mapCharacter)
|
||||
} catch (error: any) {
|
||||
this.logger.error('map:character:move error: ' + error.message)
|
||||
}
|
||||
}
|
||||
|
||||
private cancelCurrentMovement(mapCharacter: MapCharacter): void {
|
||||
if (mapCharacter.isMoving) {
|
||||
mapCharacter.isMoving = false
|
||||
mapCharacter.currentPath = null
|
||||
}
|
||||
|
||||
// Validate target position is within reasonable range
|
||||
const currentX = mapCharacter.character.positionX
|
||||
const currentY = mapCharacter.character.positionY
|
||||
const distance = Math.sqrt(Math.pow(positionX - currentX, 2) + Math.pow(positionY - currentY, 2))
|
||||
|
||||
const path = await this.characterService.calculatePath(mapCharacter.character, positionX, positionY)
|
||||
if (!path?.length) {
|
||||
this.io.in(mapCharacter.character.map.id).emit(SocketEvent.MAP_CHARACTER_MOVEERROR, 'No valid path found')
|
||||
return
|
||||
}
|
||||
|
||||
// Start new movement
|
||||
mapCharacter.isMoving = true
|
||||
mapCharacter.currentPath = path
|
||||
await this.moveAlongPath(mapCharacter, path)
|
||||
}
|
||||
|
||||
private async moveAlongPath(mapCharacter: MapCharacter, path: Array<{ positionX: number; positionY: number }>): Promise<void> {
|
||||
private async moveAlongPath(mapCharacter: MapCharacter): Promise<void> {
|
||||
const character = mapCharacter.getCharacter()
|
||||
const path = mapCharacter.currentPath
|
||||
|
||||
if (!path?.length) return
|
||||
|
||||
try {
|
||||
for (let i = 0; i < path.length - 1; i++) {
|
||||
@ -64,47 +69,42 @@ export default class CharacterMove extends BaseEvent {
|
||||
return
|
||||
}
|
||||
|
||||
const [start, end] = [path[i], path[i + 1]]
|
||||
const [currentTile, nextTile] = [path[i], path[i + 1]]
|
||||
|
||||
if (!start || !end) {
|
||||
this.logger.error('Invalid path step detected')
|
||||
if (!currentTile || !nextTile) {
|
||||
this.logger.error('Invalid movement step detected')
|
||||
break
|
||||
}
|
||||
|
||||
if (i !== 0) {
|
||||
await this.characterService.applyMovementDelay()
|
||||
}
|
||||
|
||||
// Validate each step
|
||||
if (Math.abs(end.positionX - start.positionX) > 1 || Math.abs(end.positionY - start.positionY) > 1) {
|
||||
this.logger.error('Invalid path step detected')
|
||||
// Validate step
|
||||
if (!this.isValidStep(currentTile, nextTile)) {
|
||||
this.logger.error('Invalid movement step detected')
|
||||
break
|
||||
}
|
||||
|
||||
character.setRotation(CharacterService.calculateRotation(start.positionX, start.positionY, end.positionX, end.positionY))
|
||||
// Update character rotation
|
||||
character.setRotation(CharacterService.calculateRotation(currentTile.positionX, currentTile.positionY, nextTile.positionX, nextTile.positionY))
|
||||
|
||||
const mapEventTileRepository = new MapEventTileRepository()
|
||||
const mapEventTile = await mapEventTileRepository.getEventTileByMapIdAndPosition(character.getMap().getId(), Math.floor(end.positionX), Math.floor(end.positionY))
|
||||
|
||||
if (mapEventTile?.type === 'BLOCK') break
|
||||
if (mapEventTile?.type === 'TELEPORT' && mapEventTile.teleport) {
|
||||
await this.handleTeleportMapEventTile(mapEventTile as MapEventTileWithTeleport)
|
||||
return
|
||||
// Check for map events at the next tile
|
||||
const mapEventTile = await this.checkMapEvents(character, nextTile)
|
||||
if (mapEventTile) {
|
||||
if (mapEventTile.type === 'BLOCK') break
|
||||
if (mapEventTile.type === 'TELEPORT' && mapEventTile.teleport) {
|
||||
await this.handleTeleportMapEventTile(mapEventTile as MapEventTileWithTeleport)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Update position first
|
||||
character.setPositionX(end.positionX).setPositionY(end.positionY)
|
||||
// Move character to next tile
|
||||
character.setPositionX(nextTile.positionX).setPositionY(nextTile.positionY)
|
||||
|
||||
// Then emit with the same properties
|
||||
this.io.in(character.map.id).emit(SocketEvent.MAP_CHARACTER_MOVE, {
|
||||
characterId: character.id,
|
||||
positionX: character.getPositionX(),
|
||||
positionY: character.getPositionY(),
|
||||
rotation: character.getRotation(),
|
||||
isMoving: true
|
||||
})
|
||||
// Broadcast movement
|
||||
this.broadcastMovement(character, true)
|
||||
|
||||
await this.characterService.applyMovementDelay()
|
||||
// Apply movement delay between steps
|
||||
await new Promise((resolve) => setTimeout(resolve, this.STEP_DELAY))
|
||||
if (i < path.length - 2) {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (mapCharacter.isMoving && mapCharacter.currentPath === path) {
|
||||
@ -113,25 +113,52 @@ export default class CharacterMove extends BaseEvent {
|
||||
}
|
||||
}
|
||||
|
||||
private isValidStep(current: { positionX: number; positionY: number }, next: { positionX: number; positionY: number }): boolean {
|
||||
return Math.abs(next.positionX - current.positionX) <= 1 && Math.abs(next.positionY - current.positionY) <= 1
|
||||
}
|
||||
|
||||
private async checkMapEvents(character: any, nextTile: { positionX: number; positionY: number }) {
|
||||
const mapEventTileRepository = new MapEventTileRepository()
|
||||
return mapEventTileRepository.getEventTileByMapIdAndPosition(character.getMap().getId(), Math.floor(nextTile.positionX), Math.floor(nextTile.positionY))
|
||||
}
|
||||
|
||||
private async handleTeleportMapEventTile(mapEventTile: MapEventTileWithTeleport): Promise<void> {
|
||||
if (mapEventTile.getTeleport()) {
|
||||
await TeleportService.teleportCharacter(this.socket.characterId, {
|
||||
targetMapId: mapEventTile.getTeleport()!.getToMap().getId(),
|
||||
targetX: mapEventTile.getTeleport()!.getToPositionX(),
|
||||
targetY: mapEventTile.getTeleport()!.getToPositionY(),
|
||||
rotation: mapEventTile.getTeleport()!.getToRotation()
|
||||
const teleport = mapEventTile.getTeleport()
|
||||
if (teleport) {
|
||||
await TeleportService.teleportCharacter(this.socket.characterId!, {
|
||||
targetMapId: teleport.getToMap().getId(),
|
||||
targetX: teleport.getToPositionX(),
|
||||
targetY: teleport.getToPositionY(),
|
||||
rotation: teleport.getToRotation()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private finalizeMovement(mapCharacter: MapCharacter): void {
|
||||
mapCharacter.isMoving = false
|
||||
this.io.in(mapCharacter.character.map.id).emit(SocketEvent.MAP_CHARACTER_MOVE, {
|
||||
characterId: mapCharacter.character.id,
|
||||
positionX: mapCharacter.character.positionX,
|
||||
positionY: mapCharacter.character.positionY,
|
||||
rotation: mapCharacter.character.rotation,
|
||||
isMoving: mapCharacter.isMoving
|
||||
private broadcastMovement(character: any, isMoving: boolean): void {
|
||||
this.io.in(character.map.id).emit(SocketEvent.MAP_CHARACTER_MOVE, {
|
||||
characterId: character.id,
|
||||
positionX: character.getPositionX(),
|
||||
positionY: character.getPositionY(),
|
||||
rotation: character.getRotation(),
|
||||
isMoving
|
||||
})
|
||||
}
|
||||
|
||||
private finalizeMovement(mapCharacter: MapCharacter): void {
|
||||
// Clear any existing timeout
|
||||
if (this.movementTimeout) {
|
||||
clearTimeout(this.movementTimeout)
|
||||
}
|
||||
|
||||
// Set new timeout
|
||||
this.movementTimeout = setTimeout(() => {
|
||||
// Only finalize if there are no pending movements
|
||||
if (mapCharacter.currentPath === null) {
|
||||
mapCharacter.isMoving = false
|
||||
this.broadcastMovement(mapCharacter.character, false)
|
||||
}
|
||||
}, this.STEP_DELAY)
|
||||
|
||||
mapCharacter.currentPath = null
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user