Newer
Older
PixelPaintWar / apps / server / src / network / SocketManager.ts
@rinto hasegawa rinto hasegawa on 21 Feb 4 KB [refctor] コメントの整理
import { Server, Socket } from "socket.io";
import { GameManager } from "../managers/GameManager.js";
import { Room, RoomStatus } from "@repo/shared/src/types/room";
import { SocketEvents } from "@repo/shared/src/protocol/events";
import { GAME_CONFIG } from "@repo/shared/src/config/gameConfig";

type RoomPlayer = Room["players"][0];

export class SocketManager {
  private io: Server;
  private gameManager: GameManager;
  
  // サーバーメモリ上ルーム情報テーブル
  private rooms: Map<string, Room> = new Map();

  constructor(io: Server, gameManager: GameManager) {
    this.io = io;
    this.gameManager = gameManager;
  }

  public initialize() {
    this.io.on(SocketEvents.CONNECT, (socket: Socket) => {
      console.log(`✅ User connected: ${socket.id}`);

      // ロビー・ルーム関連イベント群

      socket.on(SocketEvents.JOIN_ROOM, (data: { roomId: string; playerName: string }) => {
        const { roomId, playerName } = data;
        
        // Socket.io ルーム参加処理
        socket.join(roomId);

        // ルーム未作成時の新規作成分岐
        let room = this.rooms.get(roomId);
        if (!room) {
          room = {
            roomId: roomId,
            // 先着参加者のオーナー割り当て
            ownerId: socket.id,
            players: [],
            status: RoomStatus.WAITING,
            maxPlayers: GAME_CONFIG.MAX_PLAYERS_PER_ROOM
          };
          this.rooms.set(roomId, room);
        }

        // 参加プレイヤー情報ルーム追加
        const newPlayer: RoomPlayer = {
          id: socket.id,
          name: playerName,
          isOwner: room.ownerId === socket.id,
          isReady: false
        };
        room.players.push(newPlayer);

        // ルーム内全員向け最新状態配信
        this.io.to(roomId).emit(SocketEvents.ROOM_UPDATE, room);
      });

      // ゲーム開始要求処理
      socket.on(SocketEvents.START_GAME, () => {
        for (const [roomId, room] of this.rooms.entries()) {
          if (room.ownerId === socket.id) {
            room.status = RoomStatus.PLAYING;
            
            // 同ルーム全プレイヤーのゲーム管理登録
            room.players.forEach(p => {
              this.gameManager.addPlayer(p.id);
            });

            // ルーム全員向けゲーム開始通知
            this.io.to(roomId).emit(SocketEvents.GAME_START);
            
            // 初期プレイヤー一覧送信タイミング分離方針
            break;
          }
        }
      });

      // 画面準備完了通知受信時初期データ返却
      socket.on(SocketEvents.READY_FOR_GAME, () => {
        // ゲーム管理中全プレイヤー情報取得
        const allPlayers = this.gameManager.getAllPlayers();
        
        // 通知元ソケット限定初期データ送信
        socket.emit(SocketEvents.CURRENT_PLAYERS, allPlayers);
      });

      // ゲームプレイ中イベント群

      socket.on(SocketEvents.MOVE, (data: { x: number; y: number }) => {
        // サーバー側プレイヤー座標更新
        this.gameManager.movePlayer(socket.id, data.x, data.y);
        
        const updatedPlayer = this.gameManager.getPlayer(socket.id);
        if (updatedPlayer) {
            // 同一ルーム参加者限定座標更新配信
            const myRooms = Array.from(socket.rooms).filter(r => r !== socket.id);
            const targetRoom = myRooms.length > 0 ? myRooms[0] : null;

            if (targetRoom) {
              this.io.to(targetRoom).emit(SocketEvents.UPDATE_PLAYER, { 
                  id: socket.id, 
                  x: updatedPlayer.x, 
                  y: updatedPlayer.y 
              });
            }
        }
      });

      // 切断時イベント群

      socket.on(SocketEvents.DISCONNECT, () => {
        console.log(`❌ User disconnected: ${socket.id}`);
        this.gameManager.removePlayer(socket.id);
        this.io.emit(SocketEvents.REMOVE_PLAYER, socket.id);

        // 参加中ルームからの切断プレイヤー除外処理
        for (const [roomId, room] of this.rooms.entries()) {
          const playerIndex = room.players.findIndex(p => p.id === socket.id);
          if (playerIndex !== -1) {
            room.players.splice(playerIndex, 1);
            
            if (room.players.length === 0) {
              // 空ルーム削除分岐
              this.rooms.delete(roomId);
            } else {
              // オーナー切断時所有権移譲処理
              if (room.ownerId === socket.id) {
                room.ownerId = room.players[0].id;
                room.players[0].isOwner = true;
              }
              this.io.to(roomId).emit(SocketEvents.ROOM_UPDATE, room);
            }
          }
        }
      });

    });
  }
}