forked from noxious/server
New method for events + TP work
This commit is contained in:
@ -73,15 +73,17 @@ export default function (socket: TSocket, io: Server) {
|
||||
type: zoneEventTile.type,
|
||||
positionX: zoneEventTile.positionX,
|
||||
positionY: zoneEventTile.positionY,
|
||||
...(zoneEventTile.type === 'TELEPORT' && zoneEventTile.teleport ? {
|
||||
teleport: {
|
||||
create: {
|
||||
toZoneId: zoneEventTile.teleport.toZoneId,
|
||||
toPositionX: zoneEventTile.teleport.toPositionX,
|
||||
toPositionY: zoneEventTile.teleport.toPositionY
|
||||
...(zoneEventTile.type === 'TELEPORT' && zoneEventTile.teleport
|
||||
? {
|
||||
teleport: {
|
||||
create: {
|
||||
toZoneId: zoneEventTile.teleport.toZoneId,
|
||||
toPositionX: zoneEventTile.teleport.toPositionX,
|
||||
toPositionY: zoneEventTile.teleport.toPositionY
|
||||
}
|
||||
}
|
||||
}
|
||||
} : {})
|
||||
: {})
|
||||
}))
|
||||
},
|
||||
zoneObjects: {
|
||||
|
@ -24,7 +24,7 @@ export default function (socket: TSocket, io: Server) {
|
||||
try {
|
||||
console.log(`---User ${socket.character?.id} has requested zone.`)
|
||||
|
||||
if (!socket.character) return;
|
||||
if (!socket.character) return
|
||||
|
||||
if (!data.zoneId) {
|
||||
console.log(`---Zone id not provided.`)
|
||||
@ -55,7 +55,7 @@ export default function (socket: TSocket, io: Server) {
|
||||
callback({ zone, characters: ZoneManager.getCharactersInZone(zone.id) })
|
||||
} catch (error: any) {
|
||||
logger.error(`Error requesting zone: ${error.message}`)
|
||||
socket.disconnect();
|
||||
socket.disconnect()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,158 +0,0 @@
|
||||
import { Server } from 'socket.io';
|
||||
import { TSocket, ExtendedCharacter } from '../../utilities/types';
|
||||
import ZoneManager from '../../managers/zoneManager';
|
||||
import prisma from '../../utilities/prisma';
|
||||
import { AStar } from '../../utilities/player/aStar';
|
||||
import Rotation from '../../utilities/player/rotation';
|
||||
import ZoneRepository from '../../repositories/zoneRepository';
|
||||
import { Character } from '@prisma/client';
|
||||
|
||||
const moveTokens = new Map<number, symbol>();
|
||||
|
||||
export default function setupCharacterMove(socket: TSocket, io: Server) {
|
||||
socket.on('character:initMove', handleCharacterMove(socket, io));
|
||||
}
|
||||
|
||||
const handleCharacterMove = (socket: TSocket, io: Server) => async ({ positionX, positionY }: { positionX: number; positionY: number }) => {
|
||||
const { character } = socket;
|
||||
if (!character) return console.error('character:move error', 'Character not found');
|
||||
|
||||
const grid = await ZoneManager.getGrid(character.zoneId);
|
||||
if (!grid?.length) return console.error('character:move error', 'Grid not found or empty');
|
||||
|
||||
const start = { x: Math.floor(character.positionX), y: Math.floor(character.positionY) };
|
||||
const end = { x: Math.floor(positionX), y: Math.floor(positionY) };
|
||||
|
||||
if (isObstacle(end, grid)) return socket.emit('character:moveError', 'Destination is an obstacle');
|
||||
|
||||
const path = AStar.findPath(start, end, grid);
|
||||
if (!path.length) return socket.emit('character:moveError', 'No valid path found');
|
||||
|
||||
moveTokens.set(character.id, Symbol('moveToken'));
|
||||
character.isMoving = true;
|
||||
io.in(character.zoneId.toString()).emit('character:move', character);
|
||||
moveAlongPath(socket, io, path, grid).catch(console.error);
|
||||
};
|
||||
|
||||
async function moveAlongPath(socket: TSocket, io: Server, path: Array<{ x: number; y: number }>, grid: number[][]) {
|
||||
const { character } = socket;
|
||||
if (!character) return;
|
||||
|
||||
const moveToken = moveTokens.get(character.id);
|
||||
const stepDuration = 250;
|
||||
const updateInterval = 50;
|
||||
|
||||
for (let i = 0; i < path.length - 1; i++) {
|
||||
const startTime = Date.now();
|
||||
const start = path[i];
|
||||
const end = path[i + 1];
|
||||
|
||||
while (Date.now() - startTime < stepDuration) {
|
||||
if (moveTokens.get(character.id) !== moveToken) return;
|
||||
|
||||
const progress = (Date.now() - startTime) / stepDuration;
|
||||
const current = interpolatePosition(start, end, progress);
|
||||
|
||||
if (isObstacle(current, grid)) {
|
||||
await updateCharacterPosition(character, start, Rotation.calculate(start.x, start.y, end.x, end.y), socket, io);
|
||||
return;
|
||||
}
|
||||
|
||||
const tp = await prisma.zoneEventTile.findFirst({
|
||||
where: { zoneId: character.zoneId, type: 'TELEPORT', positionX: current.x, positionY: current.y },
|
||||
include: { teleport: true }
|
||||
});
|
||||
|
||||
if (tp?.teleport) {
|
||||
await handleTeleport(socket, io, character, tp.teleport, start, end);
|
||||
return;
|
||||
}
|
||||
|
||||
await updateCharacterPosition(character, current, Rotation.calculate(start.x, start.y, end.x, end.y), socket, io);
|
||||
await new Promise(resolve => setTimeout(resolve, updateInterval));
|
||||
}
|
||||
}
|
||||
|
||||
if (moveTokens.get(character.id) === moveToken) {
|
||||
await updateCharacterPosition(character, path[path.length - 1], character.rotation, socket, io);
|
||||
character.isMoving = false;
|
||||
moveTokens.delete(character.id);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleTeleport(socket: TSocket, io: Server, character: ExtendedCharacter, teleport: any, start: { x: number; y: number }, end: { x: number; y: number }) {
|
||||
if (teleport.toZoneId === character.zoneId) return;
|
||||
|
||||
const zone = await ZoneRepository.getById(teleport.toZoneId);
|
||||
if (!zone) return;
|
||||
|
||||
character.isMoving = false;
|
||||
character.zoneId = teleport.toZoneId;
|
||||
|
||||
moveTokens.delete(character.id);
|
||||
|
||||
socket.leave(character.zoneId.toString());
|
||||
socket.join(teleport.toZoneId.toString());
|
||||
|
||||
socket.emit('zone:teleport', { zone, characters: ZoneManager.getCharactersInZone(zone.id) });
|
||||
|
||||
await updateCharacterPosition(
|
||||
character,
|
||||
{ x: teleport.toPositionX, y: teleport.toPositionY },
|
||||
Rotation.calculate(start.x, start.y, end.x, end.y),
|
||||
socket,
|
||||
io,
|
||||
teleport.toZoneId
|
||||
);
|
||||
}
|
||||
|
||||
async function updateCharacterPosition(
|
||||
character: ExtendedCharacter,
|
||||
position: { x: number; y: number },
|
||||
rotation: number,
|
||||
socket: TSocket,
|
||||
io: Server,
|
||||
newZoneId?: number
|
||||
) {
|
||||
const oldZoneId = character.zoneId;
|
||||
|
||||
Object.assign(character, {
|
||||
positionX: position.x,
|
||||
positionY: position.y,
|
||||
rotation,
|
||||
zoneId: newZoneId || character.zoneId
|
||||
});
|
||||
|
||||
if (newZoneId && newZoneId !== oldZoneId) {
|
||||
io.to(oldZoneId.toString()).emit('zone:character:leave', character);
|
||||
io.to(newZoneId.toString()).emit('zone:character:join', character);
|
||||
ZoneManager.removeCharacterFromZone(oldZoneId, character as Character);
|
||||
ZoneManager.addCharacterToZone(newZoneId, character as Character);
|
||||
} else {
|
||||
ZoneManager.updateCharacterInZone(character.zoneId, character);
|
||||
}
|
||||
|
||||
await prisma.character.update({
|
||||
where: { id: character.id },
|
||||
data: {
|
||||
positionX: position.x,
|
||||
positionY: position.y,
|
||||
rotation,
|
||||
zoneId: character.zoneId
|
||||
}
|
||||
});
|
||||
|
||||
io.in(character.zoneId.toString()).emit('character:move', character);
|
||||
socket.emit('character:dataUpdated', character);
|
||||
}
|
||||
|
||||
const interpolatePosition = (start: { x: number; y: number }, end: { x: number; y: number }, progress: number) => ({
|
||||
x: start.x + (end.x - start.x) * progress,
|
||||
y: start.y + (end.y - start.y) * progress
|
||||
});
|
||||
|
||||
const isObstacle = ({ x, y }: { x: number; y: number }, grid: number[][]) => {
|
||||
const gridX = Math.floor(x);
|
||||
const gridY = Math.floor(y);
|
||||
return grid[gridY]?.[gridX] === 1 || grid[gridY]?.[Math.ceil(x)] === 1 || grid[Math.ceil(y)]?.[gridX] === 1 || grid[Math.ceil(y)]?.[Math.ceil(x)] === 1;
|
||||
};
|
70
src/events/zone/characterMoveEvent.ts
Normal file
70
src/events/zone/characterMoveEvent.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { Server } from 'socket.io'
|
||||
import { TSocket, ExtendedCharacter } from '../../utilities/types'
|
||||
import { CharacterMoveService } from '../../services/character/characterMoveService'
|
||||
import { TeleportService } from '../../services/character/teleportService'
|
||||
import { MovementValidator } from '../../services/character/movementValidator'
|
||||
import { SocketEmitter } from '../../utilities/socketEmitter'
|
||||
|
||||
export default class CharacterMoveEvent {
|
||||
private characterMoveService: CharacterMoveService
|
||||
private teleportService: TeleportService
|
||||
private movementValidator: MovementValidator
|
||||
private socketEmitter: SocketEmitter
|
||||
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {
|
||||
this.characterMoveService = new CharacterMoveService()
|
||||
this.teleportService = new TeleportService()
|
||||
this.movementValidator = new MovementValidator()
|
||||
this.socketEmitter = new SocketEmitter(io, socket)
|
||||
}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('character:initMove', this.handleCharacterMove.bind(this))
|
||||
}
|
||||
|
||||
private async handleCharacterMove({ positionX, positionY }: { positionX: number; positionY: number }): Promise<void> {
|
||||
const { character } = this.socket
|
||||
if (!character) {
|
||||
console.error('character:move error', 'Character not found')
|
||||
return
|
||||
}
|
||||
|
||||
const path = await this.characterMoveService.calculatePath(character, positionX, positionY)
|
||||
if (!path) {
|
||||
this.socketEmitter.emitMoveError('No valid path found')
|
||||
return
|
||||
}
|
||||
|
||||
await this.moveAlongPath(character, path)
|
||||
}
|
||||
|
||||
private async moveAlongPath(character: ExtendedCharacter, path: Array<{ x: number; y: number }>): Promise<void> {
|
||||
for (const position of path) {
|
||||
if (!(await this.movementValidator.isValidMove(character, position))) {
|
||||
break
|
||||
}
|
||||
|
||||
const teleport = await this.teleportService.checkForTeleport(character, position)
|
||||
if (teleport) {
|
||||
await this.characterMoveService.updatePosition(character, position, teleport.toZoneId)
|
||||
await this.teleportService.handleTeleport(this.socket, character, teleport)
|
||||
break
|
||||
}
|
||||
|
||||
await this.characterMoveService.updatePosition(character, position)
|
||||
this.socketEmitter.emitCharacterMove(character)
|
||||
|
||||
await this.characterMoveService.applyMovementDelay()
|
||||
}
|
||||
|
||||
this.finalizeMovement(character)
|
||||
}
|
||||
|
||||
private finalizeMovement(character: ExtendedCharacter): void {
|
||||
character.isMoving = false
|
||||
this.socketEmitter.emitCharacterMove(character)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user