diff --git a/apps/server/src/domains/room/RoomHandler.ts b/apps/server/src/domains/room/RoomHandler.ts index 756cb63..9483894 100644 --- a/apps/server/src/domains/room/RoomHandler.ts +++ b/apps/server/src/domains/room/RoomHandler.ts @@ -4,8 +4,10 @@ import type { roomTypes } from "@repo/shared"; import { joinRoomUseCase } from "./application/useCases/joinRoomUseCase"; import { roomDisconnectUseCase } from "./application/useCases/roomDisconnectUseCase"; +import { createEmitToRoom } from "./application/adapters/createEmitToRoom"; export const registerRoomHandlers = (io: Server, socket: Socket, roomManager: RoomManager) => { + const emitToRoom = createEmitToRoom(io); socket.on(protocol.SocketEvents.JOIN_ROOM, (data: roomTypes.JoinRoomPayload) => { const { roomId } = data; @@ -16,14 +18,7 @@ roomManager, socketId: socket.id, data, - emitToRoom: (targetRoomId, event, payload) => { - if (payload === undefined) { - io.to(targetRoomId).emit(event); - return; - } - - io.to(targetRoomId).emit(event, payload); - }, + emitToRoom, }); }); @@ -33,16 +28,11 @@ * 切断時のルームクリーンアップ処理 */ export const handleRoomDisconnect = (io: Server, socket: Socket, roomManager: RoomManager) => { + const emitToRoom = createEmitToRoom(io); + roomDisconnectUseCase({ roomManager, socketId: socket.id, - emitToRoom: (roomId, event, payload) => { - if (payload === undefined) { - io.to(roomId).emit(event); - return; - } - - io.to(roomId).emit(event, payload); - }, + emitToRoom, }); }; \ No newline at end of file diff --git a/apps/server/src/domains/room/RoomManager.ts b/apps/server/src/domains/room/RoomManager.ts index 48832ec..defaf38 100644 --- a/apps/server/src/domains/room/RoomManager.ts +++ b/apps/server/src/domains/room/RoomManager.ts @@ -1,83 +1,32 @@ -import { roomConsts, config } from "@repo/shared"; import type { roomTypes } from "@repo/shared"; +import { RoomJoinService } from "./application/services/RoomJoinService"; +import { RoomExitService } from "./application/services/RoomExitService"; +import { RoomQueryService } from "./application/services/RoomQueryService"; export class RoomManager { private rooms: Map = new Map(); + private roomJoinService: RoomJoinService; + private roomExitService: RoomExitService; + private roomQueryService: RoomQueryService; + + constructor() { + this.roomJoinService = new RoomJoinService(this.rooms); + this.roomExitService = new RoomExitService(this.rooms); + this.roomQueryService = new RoomQueryService(this.rooms); + } // ルームにプレイヤーを追加(なければ作成) public addPlayerToRoom(roomId: string, socketId: string, playerName: string): roomTypes.Room { - let room = this.rooms.get(roomId); - if (!room) { - room = { - roomId: roomId, - ownerId: socketId, - players: [], - status: roomConsts.RoomPhase.WAITING, - maxPlayers: config.GAME_CONFIG.MAX_PLAYERS_PER_ROOM - }; - this.rooms.set(roomId, room); - console.log("[RoomManager] created room", { roomId, ownerId: socketId }); - } - - const newPlayer: roomTypes.RoomMember = { - id: socketId, - name: playerName, - isOwner: room.ownerId === socketId, - isReady: false - }; - room.players.push(newPlayer); - console.log("[RoomManager] player joined", { - roomId, - socketId, - playerName, - totalPlayers: room.players.length - }); - - return room; + return this.roomJoinService.addPlayerToRoom(roomId, socketId, playerName); } // プレイヤーをルームから削除し、更新があったルームの配列を返す public removePlayer(socketId: string): roomTypes.Room[] { - const updatedRooms: roomTypes.Room[] = []; - - for (const [roomId, room] of this.rooms.entries()) { - const playerIndex = room.players.findIndex(p => p.id === socketId); - if (playerIndex !== -1) { - room.players.splice(playerIndex, 1); - console.log("[RoomManager] player left", { - roomId, - socketId, - totalPlayers: room.players.length - }); - - if (room.players.length === 0) { - // 空ルーム削除 - this.rooms.delete(roomId); - console.log("[RoomManager] deleted room", { roomId }); - } else { - // オーナー切断時所有権移譲処理 - if (room.ownerId === socketId) { - room.ownerId = room.players[0].id; - room.players[0].isOwner = true; - console.log("[RoomManager] transferred ownership", { - roomId, - newOwnerId: room.ownerId - }); - } - updatedRooms.push(room); - } - } - } - return updatedRooms; + return this.roomExitService.removePlayer(socketId); } // オーナーIDからルームを取得 public getRoomByOwnerId(ownerId: string): roomTypes.Room | undefined { - for (const room of this.rooms.values()) { - if (room.ownerId === ownerId) { - return room; - } - } - return undefined; + return this.roomQueryService.getRoomByOwnerId(ownerId); } } \ No newline at end of file diff --git a/apps/server/src/domains/room/application/adapters/createEmitToRoom.ts b/apps/server/src/domains/room/application/adapters/createEmitToRoom.ts new file mode 100644 index 0000000..abab427 --- /dev/null +++ b/apps/server/src/domains/room/application/adapters/createEmitToRoom.ts @@ -0,0 +1,14 @@ +import { Server } from "socket.io"; + +export type EmitToRoom = (roomId: string, event: string, payload?: unknown) => void; + +export const createEmitToRoom = (io: Server): EmitToRoom => { + return (roomId, event, payload) => { + if (payload === undefined) { + io.to(roomId).emit(event); + return; + } + + io.to(roomId).emit(event, payload); + }; +}; diff --git a/apps/server/src/domains/room/application/services/RoomExitService.ts b/apps/server/src/domains/room/application/services/RoomExitService.ts new file mode 100644 index 0000000..9fcdc6e --- /dev/null +++ b/apps/server/src/domains/room/application/services/RoomExitService.ts @@ -0,0 +1,42 @@ +import type { roomTypes } from "@repo/shared"; + +export class RoomExitService { + constructor(private rooms: Map) {} + + public removePlayer(socketId: string): roomTypes.Room[] { + const updatedRooms: roomTypes.Room[] = []; + + for (const [roomId, room] of this.rooms.entries()) { + const playerIndex = room.players.findIndex((player) => player.id === socketId); + if (playerIndex === -1) { + continue; + } + + room.players.splice(playerIndex, 1); + console.log("[RoomManager] player left", { + roomId, + socketId, + totalPlayers: room.players.length, + }); + + if (room.players.length === 0) { + this.rooms.delete(roomId); + console.log("[RoomManager] deleted room", { roomId }); + continue; + } + + if (room.ownerId === socketId) { + room.ownerId = room.players[0].id; + room.players[0].isOwner = true; + console.log("[RoomManager] transferred ownership", { + roomId, + newOwnerId: room.ownerId, + }); + } + + updatedRooms.push(room); + } + + return updatedRooms; + } +} diff --git a/apps/server/src/domains/room/application/services/RoomJoinService.ts b/apps/server/src/domains/room/application/services/RoomJoinService.ts new file mode 100644 index 0000000..3fe81b1 --- /dev/null +++ b/apps/server/src/domains/room/application/services/RoomJoinService.ts @@ -0,0 +1,38 @@ +import { config, roomConsts } from "@repo/shared"; +import type { roomTypes } from "@repo/shared"; + +export class RoomJoinService { + constructor(private rooms: Map) {} + + public addPlayerToRoom(roomId: string, socketId: string, playerName: string): roomTypes.Room { + let room = this.rooms.get(roomId); + if (!room) { + room = { + roomId, + ownerId: socketId, + players: [], + status: roomConsts.RoomPhase.WAITING, + maxPlayers: config.GAME_CONFIG.MAX_PLAYERS_PER_ROOM, + }; + this.rooms.set(roomId, room); + console.log("[RoomManager] created room", { roomId, ownerId: socketId }); + } + + const newPlayer: roomTypes.RoomMember = { + id: socketId, + name: playerName, + isOwner: room.ownerId === socketId, + isReady: false, + }; + + room.players.push(newPlayer); + console.log("[RoomManager] player joined", { + roomId, + socketId, + playerName, + totalPlayers: room.players.length, + }); + + return room; + } +} diff --git a/apps/server/src/domains/room/application/services/RoomQueryService.ts b/apps/server/src/domains/room/application/services/RoomQueryService.ts new file mode 100644 index 0000000..3ad5dc2 --- /dev/null +++ b/apps/server/src/domains/room/application/services/RoomQueryService.ts @@ -0,0 +1,15 @@ +import type { roomTypes } from "@repo/shared"; + +export class RoomQueryService { + constructor(private rooms: Map) {} + + public getRoomByOwnerId(ownerId: string): roomTypes.Room | undefined { + for (const room of this.rooms.values()) { + if (room.ownerId === ownerId) { + return room; + } + } + + return undefined; + } +}