diff --git a/apps/server/src/domains/game/GameManager.ts b/apps/server/src/domains/game/GameManager.ts index 97ef4cf..4bbc1f7 100644 --- a/apps/server/src/domains/game/GameManager.ts +++ b/apps/server/src/domains/game/GameManager.ts @@ -66,8 +66,15 @@ return this.playerRegistry.getAllPlayers(); } + // 指定ID配列のプレイヤーを取得 + getPlayersByIds(playerIds: string[]) { + return playerIds + .map((playerId) => this.playerRegistry.getPlayer(playerId)) + .filter((player): player is Player => player !== undefined); + } + // 【一時的】移動したプレイヤーの足元を塗り、差分を返すメソッド - public paintAndGetUpdates(playerId: string): gridMapTypes.CellUpdate[] { - return this.gameSessionService.paintAndGetUpdates(playerId); + public paintAndGetUpdates(roomId: string, playerId: string): gridMapTypes.CellUpdate[] { + return this.gameSessionService.paintAndGetUpdates(roomId, playerId); } } \ No newline at end of file diff --git a/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts b/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts index bbeb4f2..851750a 100644 --- a/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts +++ b/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts @@ -13,7 +13,7 @@ } export interface ReadyForGamePort { - getAllPlayers(): playerTypes.PlayerData[]; + getPlayersByIds(playerIds: string[]): playerTypes.PlayerData[]; getRoomStartTime(roomId: string): number | undefined; } diff --git a/apps/server/src/domains/game/application/services/GameSessionService.ts b/apps/server/src/domains/game/application/services/GameSessionService.ts index d91ee70..83ae1f3 100644 --- a/apps/server/src/domains/game/application/services/GameSessionService.ts +++ b/apps/server/src/domains/game/application/services/GameSessionService.ts @@ -6,12 +6,12 @@ import { logEvent } from "@server/logging/logEvent"; export class GameSessionService { - private mapStore: MapStore; + private mapStores: Map; private gameLoops: Map; private roomStartTimes: Map; constructor(private players: Map) { - this.mapStore = new MapStore(); + this.mapStores = new Map(); this.gameLoops = new Map(); this.roomStartTimes = new Map(); } @@ -37,17 +37,20 @@ const tickRate = config.GAME_CONFIG.PLAYER_POSITION_UPDATE_MS; this.roomStartTimes.set(roomId, Date.now()); + const mapStore = this.mapStores.get(roomId) ?? new MapStore(); + this.mapStores.set(roomId, mapStore); const loop = new GameLoop( roomId, tickRate, playerIds, this.players, - this.mapStore, + mapStore, onTick, () => { this.roomStartTimes.delete(roomId); this.gameLoops.delete(roomId); + this.mapStores.delete(roomId); onGameEnd(); } ); @@ -68,6 +71,7 @@ loop.stop(); this.gameLoops.delete(roomId); this.roomStartTimes.delete(roomId); + this.mapStores.delete(roomId); logEvent("GameSessionService", { event: "STOP_GAME_LOOP", result: "stopped", @@ -82,15 +86,18 @@ } } - public paintAndGetUpdates(playerId: string): gridMapTypes.CellUpdate[] { + public paintAndGetUpdates(roomId: string, playerId: string): gridMapTypes.CellUpdate[] { + const mapStore = this.mapStores.get(roomId); + if (!mapStore) return []; + const player = this.players.get(playerId); if (!player) return []; const gridIndex = gridMapLogic.getGridIndexFromPosition(player.x, player.y); if (gridIndex !== null) { - this.mapStore.paintCell(gridIndex, player.teamId); + mapStore.paintCell(gridIndex, player.teamId); } - return this.mapStore.getAndClearUpdates(); + return mapStore.getAndClearUpdates(); } } diff --git a/apps/server/src/domains/game/application/useCases/readyForGameUseCase.ts b/apps/server/src/domains/game/application/useCases/readyForGameUseCase.ts index dfae3fd..1084d78 100644 --- a/apps/server/src/domains/game/application/useCases/readyForGameUseCase.ts +++ b/apps/server/src/domains/game/application/useCases/readyForGameUseCase.ts @@ -5,6 +5,7 @@ type ReadyForGameUseCaseParams = { socketId: string; roomId?: string; + playerIds: string[]; gameManager: ReadyForGamePort; publishCurrentPlayers: (players: playerTypes.PlayerData[]) => void; publishGameStart: (payload: { startTime: number }) => void; @@ -13,19 +14,20 @@ export const readyForGameUseCase = ({ socketId, roomId, + playerIds, gameManager, publishCurrentPlayers, publishGameStart, }: ReadyForGameUseCaseParams) => { - const allPlayers = gameManager.getAllPlayers(); - publishCurrentPlayers(allPlayers); + const roomPlayers = gameManager.getPlayersByIds(playerIds); + publishCurrentPlayers(roomPlayers); logEvent("GameUseCase", { event: "READY_FOR_GAME", result: "received", socketId, roomId, - totalPlayers: allPlayers.length, + totalPlayers: roomPlayers.length, }); if (!roomId) { diff --git a/apps/server/src/domains/room/RoomManager.ts b/apps/server/src/domains/room/RoomManager.ts index 7dc2152..4197846 100644 --- a/apps/server/src/domains/room/RoomManager.ts +++ b/apps/server/src/domains/room/RoomManager.ts @@ -35,4 +35,14 @@ public getRoomByOwnerId(ownerId: string): roomTypes.Room | undefined { return this.roomQueryService.getRoomByOwnerId(ownerId); } + + // ルームIDからルームを取得する + public getRoomById(roomId: string): roomTypes.Room | undefined { + return this.roomQueryService.getRoomById(roomId); + } + + // プレイヤーIDから所属ルームを取得する + public getRoomByPlayerId(playerId: string): roomTypes.Room | undefined { + return this.roomQueryService.getRoomByPlayerId(playerId); + } } \ No newline at end of file diff --git a/apps/server/src/domains/room/application/services/RoomQueryService.ts b/apps/server/src/domains/room/application/services/RoomQueryService.ts index 89abc7c..6881df8 100644 --- a/apps/server/src/domains/room/application/services/RoomQueryService.ts +++ b/apps/server/src/domains/room/application/services/RoomQueryService.ts @@ -8,6 +8,20 @@ export class RoomQueryService { constructor(private rooms: Map) {} + public getRoomById(roomId: string): roomTypes.Room | undefined { + return this.rooms.get(roomId); + } + + public getRoomByPlayerId(playerId: string): roomTypes.Room | undefined { + for (const room of this.rooms.values()) { + if (room.players.some((player) => player.id === playerId)) { + return room; + } + } + + return undefined; + } + public getRoomByOwnerId(ownerId: string): roomTypes.Room | undefined { for (const room of this.rooms.values()) { if (room.ownerId === ownerId) { diff --git a/apps/server/src/network/handlers/game/createGameEventPublisher.ts b/apps/server/src/network/handlers/game/createGameEventPublisher.ts index c8b1927..8d36b1e 100644 --- a/apps/server/src/network/handlers/game/createGameEventPublisher.ts +++ b/apps/server/src/network/handlers/game/createGameEventPublisher.ts @@ -5,7 +5,7 @@ import { Server } from "socket.io"; import { protocol } from "@repo/shared"; import type { gridMapTypes, playerTypes, roomTypes } from "@repo/shared"; -import { createEmitToAll } from "@server/network/adapters/socketEmitters"; +import { createEmitToRoom } from "@server/network/adapters/socketEmitters"; import type { CommonHandlerContext } from "../CommonHandler"; type RoomId = roomTypes.Room["roomId"]; @@ -29,7 +29,7 @@ /** 切断時に配信するゲームイベントの送信インターフェース */ export type GameDisconnectPublisher = { - publishPlayerRemovedToAll: (removedPlayerId: SocketId) => void; + publishPlayerRemovedToRoom: (roomId: RoomId, removedPlayerId: SocketId) => void; }; /** 共通送信コンテキストからゲームイベント送信関数群を生成する */ @@ -61,11 +61,11 @@ /** ゲーム切断時の送信関数群を生成する */ export const createGameDisconnectPublisher = (io: Server): GameDisconnectPublisher => { - const emitToAll = createEmitToAll(io); + const emitToRoom = createEmitToRoom(io); return { - publishPlayerRemovedToAll: (removedPlayerId: SocketId) => { - emitToAll(protocol.SocketEvents.REMOVE_PLAYER, removedPlayerId); + publishPlayerRemovedToRoom: (roomId: RoomId, removedPlayerId: SocketId) => { + emitToRoom(roomId, protocol.SocketEvents.REMOVE_PLAYER, removedPlayerId); }, }; }; diff --git a/apps/server/src/network/handlers/game/handleGameDisconnect.ts b/apps/server/src/network/handlers/game/handleGameDisconnect.ts index 3cb2c11..0a7be66 100644 --- a/apps/server/src/network/handlers/game/handleGameDisconnect.ts +++ b/apps/server/src/network/handlers/game/handleGameDisconnect.ts @@ -11,6 +11,7 @@ export const handleGameDisconnect = ( io: Server, gameManager: GameManager, + roomId: string | undefined, playerId: string ) => { const gameDisconnectPublisher = createGameDisconnectPublisher(io); @@ -18,6 +19,12 @@ disconnectUseCase({ gameManager, playerId, - publishPlayerRemoved: gameDisconnectPublisher.publishPlayerRemovedToAll, + publishPlayerRemoved: (removedPlayerId) => { + if (!roomId) { + return; + } + + gameDisconnectPublisher.publishPlayerRemovedToRoom(roomId, removedPlayerId); + }, }); }; diff --git a/apps/server/src/network/handlers/game/registerGameHandlers.ts b/apps/server/src/network/handlers/game/registerGameHandlers.ts index 29d3511..859a451 100644 --- a/apps/server/src/network/handlers/game/registerGameHandlers.ts +++ b/apps/server/src/network/handlers/game/registerGameHandlers.ts @@ -59,10 +59,14 @@ // 参加者の準備完了通知を受けて現在状態を返す socket.on(protocol.SocketEvents.READY_FOR_GAME, () => { const roomId = Array.from(socket.rooms).find((room) => room !== socket.id); + const playerIds = roomId + ? (roomManager.getRoomById(roomId)?.players ?? []).map((p) => p.id) + : []; readyForGameUseCase({ socketId: socket.id, roomId, + playerIds, gameManager, publishCurrentPlayers: gamePublisher.publishCurrentPlayersToSocket, publishGameStart: gamePublisher.publishGameStartToSocket, diff --git a/apps/server/src/network/handlers/registerConnectionHandlers.ts b/apps/server/src/network/handlers/registerConnectionHandlers.ts index 690c439..88a7fac 100644 --- a/apps/server/src/network/handlers/registerConnectionHandlers.ts +++ b/apps/server/src/network/handlers/registerConnectionHandlers.ts @@ -41,7 +41,8 @@ socketId: socket.id, }); - handleGameDisconnect(io, gameManager, socket.id); + const roomId = roomManager.getRoomByPlayerId(socket.id)?.roomId; + handleGameDisconnect(io, gameManager, roomId, socket.id); handleRoomDisconnect(io, socket, roomManager); }); });