diff --git a/apps/client/src/network/handlers/GameHandler.ts b/apps/client/src/network/handlers/GameHandler.ts index 21a033f..597f7e3 100644 --- a/apps/client/src/network/handlers/GameHandler.ts +++ b/apps/client/src/network/handlers/GameHandler.ts @@ -10,11 +10,15 @@ GameStartPayload, MovePayload, NewPlayerPayload, + PayloadOf, RemovePlayerPayload, + SocketPayloadMap, UpdateMapCellsPayload, UpdatePlayersPayload, } from "@repo/shared"; +type SocketEventName = Exclude; + /** ゲームシーンが利用するソケット操作の契約 */ export type GameHandler = { onCurrentPlayers: (callback: (players: CurrentPlayersPayload) => void) => void; @@ -35,49 +39,74 @@ /** ソケットインスタンスからゲーム向けハンドラを生成する */ export const createGameHandler = (socket: Socket): GameHandler => { + const onEvent = ( + event: TEvent, + callback: (payload: PayloadOf) => void + ) => { + (socket as any).on(event, callback); + }; + + const offEvent = ( + event: TEvent, + callback: (payload: PayloadOf) => void + ) => { + (socket as any).off(event, callback); + }; + + function emitEvent(event: TEvent): void; + function emitEvent(event: TEvent, payload: PayloadOf): void; + function emitEvent(event: TEvent, payload?: PayloadOf): void { + if (payload === undefined) { + (socket as any).emit(event); + return; + } + + (socket as any).emit(event, payload); + } + return { onCurrentPlayers: (callback) => { - socket.on(protocol.SocketEvents.CURRENT_PLAYERS, callback); + onEvent(protocol.SocketEvents.CURRENT_PLAYERS, callback); }, offCurrentPlayers: (callback) => { - socket.off(protocol.SocketEvents.CURRENT_PLAYERS, callback); + offEvent(protocol.SocketEvents.CURRENT_PLAYERS, callback); }, onNewPlayer: (callback) => { - socket.on(protocol.SocketEvents.NEW_PLAYER, callback); + onEvent(protocol.SocketEvents.NEW_PLAYER, callback); }, offNewPlayer: (callback) => { - socket.off(protocol.SocketEvents.NEW_PLAYER, callback); + offEvent(protocol.SocketEvents.NEW_PLAYER, callback); }, onUpdatePlayers: (callback) => { - socket.on(protocol.SocketEvents.UPDATE_PLAYERS, callback); + onEvent(protocol.SocketEvents.UPDATE_PLAYERS, callback); }, offUpdatePlayers: (callback) => { - socket.off(protocol.SocketEvents.UPDATE_PLAYERS, callback); + offEvent(protocol.SocketEvents.UPDATE_PLAYERS, callback); }, onRemovePlayer: (callback) => { - socket.on(protocol.SocketEvents.REMOVE_PLAYER, callback); + onEvent(protocol.SocketEvents.REMOVE_PLAYER, callback); }, offRemovePlayer: (callback) => { - socket.off(protocol.SocketEvents.REMOVE_PLAYER, callback); + offEvent(protocol.SocketEvents.REMOVE_PLAYER, callback); }, onUpdateMapCells: (callback) => { - socket.on(protocol.SocketEvents.UPDATE_MAP_CELLS, callback); + onEvent(protocol.SocketEvents.UPDATE_MAP_CELLS, callback); }, offUpdateMapCells: (callback) => { - socket.off(protocol.SocketEvents.UPDATE_MAP_CELLS, callback); + offEvent(protocol.SocketEvents.UPDATE_MAP_CELLS, callback); }, onGameStart: (callback) => { - socket.on(protocol.SocketEvents.GAME_START, callback); + onEvent(protocol.SocketEvents.GAME_START, callback); }, offGameStart: (callback) => { - socket.off(protocol.SocketEvents.GAME_START, callback); + offEvent(protocol.SocketEvents.GAME_START, callback); }, sendMove: (x, y) => { const payload: MovePayload = { x, y }; - socket.emit(protocol.SocketEvents.MOVE, payload); + emitEvent(protocol.SocketEvents.MOVE, payload); }, readyForGame: () => { - socket.emit(protocol.SocketEvents.READY_FOR_GAME); + emitEvent(protocol.SocketEvents.READY_FOR_GAME); } }; }; diff --git a/apps/server/src/network/adapters/socketEmitters.ts b/apps/server/src/network/adapters/socketEmitters.ts index 4895b90..fd5be3b 100644 --- a/apps/server/src/network/adapters/socketEmitters.ts +++ b/apps/server/src/network/adapters/socketEmitters.ts @@ -3,13 +3,29 @@ * Socket.IOの送信処理を用途別に生成するアダプタ */ import { Server, Socket } from "socket.io"; +import type { PayloadOf, SocketPayloadMap } from "@repo/shared"; -type EmitPayload = unknown; +type SocketEventName = keyof SocketPayloadMap; + +type EmitToRoom = { + (roomId: string, event: TEvent): void; + (roomId: string, event: TEvent, payload: PayloadOf): void; +}; + +type EmitToSocket = { + (event: TEvent): void; + (event: TEvent, payload: PayloadOf): void; +}; + +type EmitToAll = { + (event: TEvent): void; + (event: TEvent, payload: PayloadOf): void; +}; const emitWithOptionalPayload = ( - emit: (event: string, payload?: EmitPayload) => void, - event: string, - payload?: EmitPayload + emit: (event: SocketEventName, payload?: unknown) => void, + event: SocketEventName, + payload?: unknown ) => { if (payload === undefined) { emit(event); @@ -20,22 +36,22 @@ }; /** ルーム単位の送信関数を生成する */ -export const createEmitToRoom = (io: Server) => { - return (roomId: string, event: string, payload?: EmitPayload) => { +export const createEmitToRoom = (io: Server): EmitToRoom => { + return (roomId: string, event: SocketEventName, payload?: unknown) => { emitWithOptionalPayload((eventName, body) => io.to(roomId).emit(eventName, body), event, payload); }; }; /** 単一ソケット向けの送信関数を生成する */ -export const createEmitToSocket = (socket: Socket) => { - return (event: string, payload?: EmitPayload) => { +export const createEmitToSocket = (socket: Socket): EmitToSocket => { + return (event: SocketEventName, payload?: unknown) => { emitWithOptionalPayload((eventName, body) => socket.emit(eventName, body), event, payload); }; }; /** 全接続向けの送信関数を生成する */ -export const createEmitToAll = (io: Server) => { - return (event: string, payload?: EmitPayload) => { +export const createEmitToAll = (io: Server): EmitToAll => { + return (event: SocketEventName, payload?: unknown) => { emitWithOptionalPayload((eventName, body) => io.emit(eventName, body), event, payload); }; };