forked from noxious/server
More teleport improvements
This commit is contained in:
parent
1191e6bf55
commit
4cf87536ce
@ -15,16 +15,20 @@ class MapManager {
|
|||||||
await mapRepository.getEntityManager().populate(maps, mapRepository.POPULATE_ALL as never[])
|
await mapRepository.getEntityManager().populate(maps, mapRepository.POPULATE_ALL as never[])
|
||||||
|
|
||||||
await Promise.all(maps.map((map) => this.loadMap(map)))
|
await Promise.all(maps.map((map) => this.loadMap(map)))
|
||||||
|
|
||||||
this.logger.info(`Map manager loaded with ${Object.keys(this.maps).length} maps`)
|
this.logger.info(`Map manager loaded with ${Object.keys(this.maps).length} maps`)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async loadMap(map: Map): Promise<void> {
|
public async loadMap(map: Map): Promise<LoadedMap> {
|
||||||
this.maps[map.id] = new LoadedMap(map)
|
const loadedMap = new LoadedMap(map)
|
||||||
|
this.maps[map.id] = loadedMap
|
||||||
this.logger.info(`Map ID ${map.id} loaded`)
|
this.logger.info(`Map ID ${map.id} loaded`)
|
||||||
|
return loadedMap
|
||||||
}
|
}
|
||||||
|
|
||||||
public unloadMap(mapId: UUID): void {
|
public unloadMap(mapId: UUID): void {
|
||||||
|
const map = this.maps[mapId]
|
||||||
|
if (!map) return
|
||||||
|
|
||||||
delete this.maps[mapId]
|
delete this.maps[mapId]
|
||||||
this.logger.info(`Map ID ${mapId} unloaded`)
|
this.logger.info(`Map ID ${mapId} unloaded`)
|
||||||
}
|
}
|
||||||
@ -38,11 +42,11 @@ class MapManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getCharacterById(characterId: UUID): MapCharacter | null {
|
public getCharacterById(characterId: UUID): MapCharacter | null {
|
||||||
return (
|
for (const map of Object.values(this.maps)) {
|
||||||
Object.values(this.maps)
|
const character = map.getCharacterById(characterId)
|
||||||
.flatMap((map) => map.getCharactersInMap())
|
if (character) return character
|
||||||
.find((char) => char.character.id === characterId) ?? null
|
}
|
||||||
)
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,18 +16,24 @@ class LoadedMap {
|
|||||||
return this.map
|
return this.map
|
||||||
}
|
}
|
||||||
|
|
||||||
public addCharacter(character: Character) {
|
public addCharacter(character: Character): MapCharacter {
|
||||||
const mapCharacter = new MapCharacter(character)
|
const existingCharacter = this.getCharacterById(character.id)
|
||||||
this.characters.push(mapCharacter)
|
if (existingCharacter) {
|
||||||
|
return existingCharacter
|
||||||
}
|
}
|
||||||
|
|
||||||
public async removeCharacter(id: UUID) {
|
const mapCharacter = new MapCharacter(character)
|
||||||
|
this.characters.push(mapCharacter)
|
||||||
|
return mapCharacter
|
||||||
|
}
|
||||||
|
|
||||||
|
public async removeCharacter(id: UUID): Promise<void> {
|
||||||
const mapCharacter = this.getCharacterById(id)
|
const mapCharacter = this.getCharacterById(id)
|
||||||
if (mapCharacter) {
|
if (!mapCharacter) return
|
||||||
|
|
||||||
await mapCharacter.savePosition()
|
await mapCharacter.savePosition()
|
||||||
this.characters = this.characters.filter((c) => c.character.id !== id)
|
this.characters = this.characters.filter((c) => c.character.id !== id)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public getCharacterById(id: UUID): MapCharacter | undefined {
|
public getCharacterById(id: UUID): MapCharacter | undefined {
|
||||||
return this.characters.find((c) => c.character.id === id)
|
return this.characters.find((c) => c.character.id === id)
|
||||||
@ -38,12 +44,11 @@ class LoadedMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async getGrid(): Promise<number[][]> {
|
public async getGrid(): Promise<number[][]> {
|
||||||
let grid: number[][] = Array.from({ length: this.map.height }, () => Array.from({ length: this.map.width }, () => 0))
|
const grid: number[][] = Array.from({ length: this.map.height }, () => Array.from({ length: this.map.width }, () => 0))
|
||||||
|
|
||||||
const mapEventTileRepository = new MapEventTileRepository()
|
const mapEventTileRepository = new MapEventTileRepository()
|
||||||
const eventTiles = await mapEventTileRepository.getAll(this.map.id)
|
const eventTiles = await mapEventTileRepository.getAll(this.map.id)
|
||||||
|
|
||||||
// Set the grid values based on the event tiles, these are strings
|
|
||||||
eventTiles.forEach((eventTile) => {
|
eventTiles.forEach((eventTile) => {
|
||||||
if (eventTile.type === 'BLOCK') {
|
if (eventTile.type === 'BLOCK') {
|
||||||
grid[eventTile.positionY]![eventTile.positionX] = 1
|
grid[eventTile.positionY]![eventTile.positionX] = 1
|
||||||
|
@ -21,72 +21,25 @@ class CharacterTeleportService {
|
|||||||
private readonly logger = Logger.type(LoggerType.GAME)
|
private readonly logger = Logger.type(LoggerType.GAME)
|
||||||
|
|
||||||
public async teleportCharacter(characterId: UUID, options: TeleportOptions): Promise<boolean> {
|
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 {
|
try {
|
||||||
|
const { socket, targetMap, mapCharacter } = await this.validateTeleportRequest(characterId, options)
|
||||||
|
if (!socket || !targetMap || !mapCharacter) return false
|
||||||
|
|
||||||
const currentMapId = mapCharacter.character.map?.id
|
const currentMapId = mapCharacter.character.map?.id
|
||||||
const currentMap = MapManager.getMapById(currentMapId!)
|
const currentMap = MapManager.getMapById(currentMapId!)
|
||||||
const io = SocketManager.getIO()
|
const io = SocketManager.getIO()
|
||||||
|
|
||||||
// Update character position and map
|
// Update character position and map
|
||||||
await mapCharacter
|
await this.updateCharacterPosition(mapCharacter, options, targetMap)
|
||||||
.getCharacter()
|
|
||||||
.setPositionX(options.targetX)
|
|
||||||
.setPositionY(options.targetY)
|
|
||||||
.setRotation(options.rotation ?? 0)
|
|
||||||
.setMap(targetMap.getMap())
|
|
||||||
.save()
|
|
||||||
|
|
||||||
// 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 (currentMapId === options.targetMapId && !options.isInitialJoin) {
|
||||||
// If the current map is the target map, send move event
|
|
||||||
CharacterMoveService.broadcastMovement(mapCharacter.character, false)
|
CharacterMoveService.broadcastMovement(mapCharacter.character, false)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle current map cleanup
|
// Handle map transition
|
||||||
if (currentMapId && currentMap) {
|
await this.handleMapTransition(socket, io, currentMapId, currentMap, options.targetMapId, targetMap, characterId, mapCharacter)
|
||||||
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()
|
|
||||||
})
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -94,6 +47,64 @@ class CharacterTeleportService {
|
|||||||
return false
|
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()
|
export default new CharacterTeleportService()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user