forked from noxious/server
#174: Refactor character manager into zoneManager for better DX, major refactor of time and weather system (data is stored in DB now instead of JSON file), npm update, npm format, many other improvements
This commit is contained in:
@ -1,77 +1,53 @@
|
||||
import { Server } from 'socket.io'
|
||||
import { TSocket, ExtendedCharacter } from '../../utilities/types'
|
||||
import { TSocket, ZoneEventTileWithTeleport } from '../../utilities/types'
|
||||
import { CharacterMoveService } from '../../services/character/characterMoveService'
|
||||
import { ZoneEventTileService } from '../../services/zoneEventTileService'
|
||||
import prisma from '../../utilities/prisma'
|
||||
import { ZoneEventTile, ZoneEventTileTeleport } from '@prisma/client'
|
||||
import Rotation from '../../utilities/character/rotation'
|
||||
import CharacterManager from '../../managers/characterManager'
|
||||
import { gameLogger } from '../../utilities/logger'
|
||||
import QueueManager from '../../managers/queueManager'
|
||||
|
||||
export type ZoneEventTileWithTeleport = ZoneEventTile & {
|
||||
teleport: ZoneEventTileTeleport
|
||||
}
|
||||
import ZoneManager from '../../managers/zoneManager'
|
||||
import ZoneCharacter from '../../models/zoneCharacter'
|
||||
|
||||
export default class CharacterMove {
|
||||
private characterMoveService: CharacterMoveService
|
||||
private zoneEventTileService: ZoneEventTileService
|
||||
private nextPath: { [index: number]: { x: number; y: number }[] } = []
|
||||
private currentZoneId: { [index: number]: number } = []
|
||||
private readonly characterMoveService = new CharacterMoveService()
|
||||
private readonly zoneEventTileService = new ZoneEventTileService()
|
||||
private nextPath = new Map<number, { x: number; y: number }[]>()
|
||||
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {
|
||||
this.characterMoveService = new CharacterMoveService()
|
||||
this.zoneEventTileService = new ZoneEventTileService()
|
||||
}
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('character:initMove', this.handleCharacterMove.bind(this))
|
||||
this.socket.on('character:move', this.handleCharacterMove.bind(this))
|
||||
}
|
||||
|
||||
private async handleCharacterMove({ positionX, positionY }: { positionX: number; positionY: number }): Promise<void> {
|
||||
let character = CharacterManager.getCharacterFromSocket(this.socket)
|
||||
if (!character) {
|
||||
gameLogger.error('character:move error', 'Character not found')
|
||||
const zoneCharacter = ZoneManager.getCharacter(this.socket.characterId!)
|
||||
if (!zoneCharacter?.character) {
|
||||
gameLogger.error('character:move error', 'Character not found or not initialized')
|
||||
return
|
||||
}
|
||||
|
||||
if (!character) {
|
||||
gameLogger.error('character:move error', 'character has not been initialized?')
|
||||
return
|
||||
}
|
||||
|
||||
const path = await this.characterMoveService.calculatePath(character, positionX, positionY)
|
||||
const path = await this.characterMoveService.calculatePath(zoneCharacter.character, positionX, positionY)
|
||||
if (!path) {
|
||||
this.io.in(character.zoneId.toString()).emit('character:moveError', 'No valid path found')
|
||||
this.io.in(zoneCharacter.character.zoneId.toString()).emit('character:moveError', 'No valid path found')
|
||||
return
|
||||
}
|
||||
|
||||
if (!character.isMoving && character.resetMovement) {
|
||||
character.resetMovement = false
|
||||
}
|
||||
if (character.isMoving && !character.resetMovement) {
|
||||
character.resetMovement = true
|
||||
this.nextPath[character.id] = path
|
||||
}
|
||||
if (!character.isMoving && !character.resetMovement) {
|
||||
character.isMoving = true
|
||||
this.currentZoneId[character.id] = character.zoneId
|
||||
await this.moveAlongPath(character, path)
|
||||
if (!zoneCharacter.isMoving) {
|
||||
zoneCharacter.isMoving = true
|
||||
await this.moveAlongPath(zoneCharacter, path)
|
||||
} else {
|
||||
this.nextPath.set(zoneCharacter.character.id, path)
|
||||
}
|
||||
}
|
||||
|
||||
private async moveAlongPath(character: ExtendedCharacter, path: Array<{ x: number; y: number }>): Promise<void> {
|
||||
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++) {
|
||||
const start = path[i]
|
||||
const end = path[i + 1]
|
||||
|
||||
if (CharacterManager.hasResetMovement(character)) {
|
||||
break
|
||||
}
|
||||
|
||||
const [start, end] = [path[i], path[i + 1]]
|
||||
character.rotation = Rotation.calculate(start.x, start.y, end.x, end.y)
|
||||
|
||||
const zoneEventTile = await prisma.zoneEventTile.findFirst({
|
||||
@ -79,62 +55,44 @@ export default class CharacterMove {
|
||||
zoneId: character.zoneId,
|
||||
positionX: Math.floor(end.x),
|
||||
positionY: Math.floor(end.y)
|
||||
}
|
||||
},
|
||||
include: { teleport: true }
|
||||
})
|
||||
|
||||
if (zoneEventTile) {
|
||||
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
|
||||
}
|
||||
}
|
||||
if (zoneEventTile?.type === 'BLOCK') break
|
||||
if (zoneEventTile?.type === 'TELEPORT' && zoneEventTile.teleport) {
|
||||
await this.handleZoneEventTile(zoneEventTile as ZoneEventTileWithTeleport)
|
||||
break
|
||||
}
|
||||
|
||||
this.characterMoveService.updatePosition(character, end)
|
||||
this.io.in(character.zoneId.toString()).emit('character:move', character)
|
||||
|
||||
this.io.in(character.zoneId.toString()).emit('character:move', zoneCharacter)
|
||||
await this.characterMoveService.applyMovementDelay()
|
||||
}
|
||||
|
||||
if (CharacterManager.hasResetMovement(character)) {
|
||||
character.resetMovement = false
|
||||
if (this.currentZoneId[character.id] === character.zoneId) {
|
||||
await this.moveAlongPath(character, this.nextPath[character.id])
|
||||
} else {
|
||||
delete this.currentZoneId[character.id]
|
||||
character.isMoving = false
|
||||
}
|
||||
const nextPath = this.nextPath.get(character.id)
|
||||
if (nextPath) {
|
||||
this.nextPath.delete(character.id)
|
||||
await this.moveAlongPath(zoneCharacter, nextPath)
|
||||
} else {
|
||||
this.finalizeMovement(character)
|
||||
this.finalizeMovement(zoneCharacter)
|
||||
}
|
||||
}
|
||||
|
||||
private async handleZoneEventTile(zoneEventTile: ZoneEventTileWithTeleport): Promise<void> {
|
||||
const character = CharacterManager.getCharacterFromSocket(this.socket)
|
||||
if (!character) {
|
||||
const zoneCharacter = ZoneManager.getCharacter(this.socket.characterId!)
|
||||
if (!zoneCharacter) {
|
||||
gameLogger.error('character:move error', 'Character not found')
|
||||
return
|
||||
}
|
||||
|
||||
const teleport = zoneEventTile.teleport
|
||||
if (teleport) {
|
||||
await this.zoneEventTileService.handleTeleport(this.io, this.socket, character, teleport)
|
||||
return
|
||||
if (zoneEventTile.teleport) {
|
||||
await this.zoneEventTileService.handleTeleport(this.io, this.socket, zoneCharacter.character, zoneEventTile.teleport)
|
||||
}
|
||||
}
|
||||
|
||||
private finalizeMovement(character: ExtendedCharacter): void {
|
||||
character.isMoving = false
|
||||
this.io.in(character.zoneId.toString()).emit('character:move', character)
|
||||
private finalizeMovement(zoneCharacter: ZoneCharacter): void {
|
||||
zoneCharacter.isMoving = false
|
||||
this.io.in(zoneCharacter.character.zoneId.toString()).emit('character:move', zoneCharacter)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user