diff --git a/apps/client/src/app.tsx b/apps/client/src/app.tsx
index 37a01a3..8b37e31 100644
--- a/apps/client/src/app.tsx
+++ b/apps/client/src/app.tsx
@@ -8,7 +8,7 @@
import { ResultScene } from "./scenes/result/ResultScene";
import { LandscapeOnlyGate } from "./components/LandscapeOnlyGate";
-import { appConsts } from "@repo/shared";
+import { domain } from "@repo/shared";
export default function App() {
const {
@@ -25,7 +25,7 @@
let scene = ;
// タイトル画面分岐
- if (scenePhase === appConsts.ScenePhase.TITLE) {
+ if (scenePhase === domain.app.ScenePhase.TITLE) {
scene = (
void;
+ requestJoin: (payload: domain.room.JoinRoomPayload) => void;
returnToTitle: (options?: { leaveRoom?: boolean }) => void;
};
@@ -28,7 +28,7 @@
};
type JoinFailureReason =
- | roomTypes.JoinRoomRejectedPayload["reason"]
+ | domain.room.JoinRoomRejectedPayload["reason"]
| "timeout";
type JoinFailure = {
@@ -65,16 +65,16 @@
/** アプリ全体のシーン状態と参加要求フローを管理するフック */
export const useAppFlow = (): AppFlowState => {
- const [scenePhase, setScenePhase] = useState(
- appConsts.ScenePhase.TITLE,
+ const [scenePhase, setScenePhase] = useState(
+ domain.app.ScenePhase.TITLE,
);
- const [room, setRoom] = useState(null);
+ const [room, setRoom] = useState(null);
const [myId, setMyId] = useState(null);
const [gameResult, setGameResult] = useState(null);
const [joinState, dispatchJoin] = useReducer(joinReducer, initialJoinState);
const joinTimeoutRef = useRef | null>(null);
const joinRejectedHandlerRef = useRef<
- ((payload: roomTypes.JoinRoomRejectedPayload) => void) | null
+ ((payload: domain.room.JoinRoomRejectedPayload) => void) | null
>(null);
const clearJoinRejectedHandler = useCallback(() => {
@@ -128,7 +128,7 @@
);
const requestJoin = useCallback(
- (payload: roomTypes.JoinRoomPayload) => {
+ (payload: domain.room.JoinRoomPayload) => {
if (joinState.isJoining) {
return;
}
@@ -137,7 +137,7 @@
dispatchJoin({ type: "start" });
const handleJoinRejected = (
- payload: roomTypes.JoinRoomRejectedPayload,
+ payload: domain.room.JoinRoomRejectedPayload,
) => {
completeJoinRequest({
reason: payload.reason,
@@ -162,7 +162,7 @@
completeJoinRequest();
setRoom(null);
setGameResult(null);
- setScenePhase(appConsts.ScenePhase.TITLE);
+ setScenePhase(domain.app.ScenePhase.TITLE);
if (!options?.leaveRoom) {
return;
diff --git a/apps/client/src/hooks/useSocketSubscriptions.ts b/apps/client/src/hooks/useSocketSubscriptions.ts
index 33f2df7..19a2ef8 100644
--- a/apps/client/src/hooks/useSocketSubscriptions.ts
+++ b/apps/client/src/hooks/useSocketSubscriptions.ts
@@ -5,20 +5,20 @@
*/
import { useEffect } from "react";
import { socketManager } from "@client/network/SocketManager";
-import { appConsts } from "@repo/shared";
-import type { appTypes, roomTypes, GameResultPayload } from "@repo/shared";
+import { domain } from "@repo/shared";
+import type { GameResultPayload } from "@repo/shared";
type UseSocketSubscriptionsParams = {
completeJoinRequest: () => void;
setGameResult: (payload: GameResultPayload | null) => void;
setMyId: (id: string | null) => void;
- setRoom: (room: roomTypes.Room | null) => void;
- setScenePhase: (phase: appTypes.ScenePhase) => void;
+ setRoom: (room: domain.room.Room | null) => void;
+ setScenePhase: (phase: domain.app.ScenePhaseType) => void;
};
type AppSocketHandlers = {
handleConnect: (id: string) => void;
- handleRoomUpdate: (updatedRoom: roomTypes.Room) => void;
+ handleRoomUpdate: (updatedRoom: domain.room.Room) => void;
handleGameStart: () => void;
handleGameResult: (payload: GameResultPayload) => void;
};
@@ -77,20 +77,20 @@
setMyId(id);
},
- handleRoomUpdate: (updatedRoom: roomTypes.Room) => {
+ handleRoomUpdate: (updatedRoom: domain.room.Room) => {
completeJoinRequest();
setRoom(updatedRoom);
- setScenePhase(appConsts.ScenePhase.LOBBY);
+ setScenePhase(domain.app.ScenePhase.LOBBY);
},
handleGameStart: () => {
setGameResult(null);
- setScenePhase(appConsts.ScenePhase.PLAYING);
+ setScenePhase(domain.app.ScenePhase.PLAYING);
},
handleGameResult: (payload: GameResultPayload) => {
setGameResult(payload);
- setScenePhase(appConsts.ScenePhase.RESULT);
+ setScenePhase(domain.app.ScenePhase.RESULT);
},
};
diff --git a/apps/client/src/network/handlers/CommonHandler.ts b/apps/client/src/network/handlers/CommonHandler.ts
index 9f08170..840f99c 100644
--- a/apps/client/src/network/handlers/CommonHandler.ts
+++ b/apps/client/src/network/handlers/CommonHandler.ts
@@ -4,7 +4,7 @@
* connect イベントをアプリ用の id 通知に変換する
*/
import type { Socket } from "socket.io-client";
-import { protocol } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
import type { ConnectionLifecyclePayloadOf } from "@repo/shared";
import { createClientSocketEventBridge } from "./socketEventBridge";
diff --git a/apps/client/src/network/handlers/GameHandler.ts b/apps/client/src/network/handlers/GameHandler.ts
index c5f42c6..51bc03a 100644
--- a/apps/client/src/network/handlers/GameHandler.ts
+++ b/apps/client/src/network/handlers/GameHandler.ts
@@ -4,7 +4,7 @@
* シーン層が利用する通信操作を集約する
*/
import type { Socket } from "socket.io-client";
-import { protocol } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
import type {
BombHitReportPayload,
BombPlacedAckPayload,
diff --git a/apps/client/src/network/handlers/LobbyHandler.ts b/apps/client/src/network/handlers/LobbyHandler.ts
index 6e9c994..1b1d70e 100644
--- a/apps/client/src/network/handlers/LobbyHandler.ts
+++ b/apps/client/src/network/handlers/LobbyHandler.ts
@@ -4,7 +4,7 @@
* ルーム更新購読とゲーム開始要求送信を提供する
*/
import type { Socket } from "socket.io-client";
-import { protocol } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
import type { ServerToClientPayloadOf } from "@repo/shared";
import { createClientSocketEventBridge } from "./socketEventBridge";
diff --git a/apps/client/src/network/handlers/TitleHandler.ts b/apps/client/src/network/handlers/TitleHandler.ts
index 06b18d8..456cdc0 100644
--- a/apps/client/src/network/handlers/TitleHandler.ts
+++ b/apps/client/src/network/handlers/TitleHandler.ts
@@ -4,7 +4,7 @@
* ルーム参加フローの送受信イベントを集約する
*/
import type { Socket } from "socket.io-client";
-import { protocol } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
import type { ClientToServerPayloadOf, ServerToClientPayloadOf } from "@repo/shared";
import { createClientSocketEventBridge } from "./socketEventBridge";
diff --git a/apps/client/src/network/handlers/socketEventBridge.ts b/apps/client/src/network/handlers/socketEventBridge.ts
index 143fe00..7c7f602 100644
--- a/apps/client/src/network/handlers/socketEventBridge.ts
+++ b/apps/client/src/network/handlers/socketEventBridge.ts
@@ -8,6 +8,7 @@
createSocketEventBridge,
type ClientToServerEventPayloadMap,
type ConnectionLifecycleEventPayloadMap,
+ type SocketBridgeTarget,
type ServerToClientEventPayloadMap,
} from "@repo/shared";
@@ -17,10 +18,30 @@
/** クライアント向けの型付きソケットイベント bridge を生成する */
export const createClientSocketEventBridge = (socket: Socket) => {
+ const bridgeTarget: SocketBridgeTarget = {
+ on: (event: string, callback: (payload: TPayload) => void) => {
+ socket.on(event, callback as (payload: unknown) => void);
+ },
+ once: (event: string, callback: (payload: TPayload) => void) => {
+ socket.once(event, callback as (payload: unknown) => void);
+ },
+ off: (event: string, callback: (payload: TPayload) => void) => {
+ socket.off(event, callback as (payload: unknown) => void);
+ },
+ emit: (event: string, payload?: unknown) => {
+ if (payload === undefined) {
+ socket.emit(event);
+ return;
+ }
+
+ socket.emit(event, payload);
+ },
+ };
+
const { onEvent, onceEvent, offEvent, emitEvent } = createSocketEventBridge<
ClientInboundEventPayloadMap,
ClientToServerEventPayloadMap
- >(socket as any);
+ >(bridgeTarget);
return {
onEvent,
diff --git a/apps/client/src/scenes/game/entities/map/GameMapController.ts b/apps/client/src/scenes/game/entities/map/GameMapController.ts
index 6213174..da2d52c 100644
--- a/apps/client/src/scenes/game/entities/map/GameMapController.ts
+++ b/apps/client/src/scenes/game/entities/map/GameMapController.ts
@@ -3,7 +3,7 @@
* 外部からのマップ更新入力をModelとViewへ仲介するコントローラー
* 全体更新と差分更新を統一的に扱い,描画同期を提供する
*/
-import type { gridMapTypes } from '@repo/shared';
+import type { domain } from '@repo/shared';
import type { Container } from 'pixi.js';
import { AppearanceResolver } from '@client/scenes/game/application/AppearanceResolver';
import { GameMapModel } from './GameMapModel';
@@ -29,13 +29,13 @@
}
/** 全体マップ状態を反映する */
- public updateMapState(state: gridMapTypes.MapState): void {
+ public updateMapState(state: domain.gridMap.MapState): void {
this.model.applyMapState(state);
this.view.renderAll(this.resolveAllCellColors(this.model.getAllTeamIds()));
}
/** 差分セル更新を反映する */
- public updateCells(updates: gridMapTypes.CellUpdate[]): void {
+ public updateCells(updates: domain.gridMap.CellUpdate[]): void {
this.model.applyUpdates(updates);
updates.forEach(({ index }) => {
diff --git a/apps/client/src/scenes/game/entities/map/GameMapModel.ts b/apps/client/src/scenes/game/entities/map/GameMapModel.ts
index 75b490e..886bdbb 100644
--- a/apps/client/src/scenes/game/entities/map/GameMapModel.ts
+++ b/apps/client/src/scenes/game/entities/map/GameMapModel.ts
@@ -4,7 +4,7 @@
* 全体更新と差分更新を適用して描画入力用の状態を保持する
*/
import { config } from '@client/config';
-import type { gridMapTypes } from '@repo/shared';
+import type { domain } from '@repo/shared';
/** マップセル状態の計算責務を担うモデル */
export class GameMapModel {
@@ -17,7 +17,7 @@
}
/** 全体マップ状態を適用する */
- public applyMapState(state: gridMapTypes.MapState): void {
+ public applyMapState(state: domain.gridMap.MapState): void {
const maxLength = Math.min(this.cellTeamIds.length, state.gridColors.length);
for (let index = 0; index < maxLength; index++) {
this.cellTeamIds[index] = state.gridColors[index];
@@ -25,7 +25,7 @@
}
/** 差分セル更新を適用する */
- public applyUpdates(updates: gridMapTypes.CellUpdate[]): void {
+ public applyUpdates(updates: domain.gridMap.CellUpdate[]): void {
updates.forEach(({ index, teamId }) => {
if (!this.isValidIndex(index)) return;
this.cellTeamIds[index] = teamId;
diff --git a/apps/client/src/scenes/game/entities/player/PlayerController.ts b/apps/client/src/scenes/game/entities/player/PlayerController.ts
index 3543d25..fa4467c 100644
--- a/apps/client/src/scenes/game/entities/player/PlayerController.ts
+++ b/apps/client/src/scenes/game/entities/player/PlayerController.ts
@@ -3,7 +3,7 @@
* 外部入出力とModel/Viewの橋渡しを担うコントローラー群
* ローカル入力適用,リモート更新適用,描画同期を分離して扱う
*/
-import type { playerTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
import { config } from "@client/config";
import { AppearanceResolver } from "@client/scenes/game/application/AppearanceResolver";
import { BombHitBlinkRenderer } from "@client/scenes/game/entities/bomb/BombHitBlinkRenderer";
@@ -18,7 +18,7 @@
};
/** リモート移動更新を表す型 */
-export type RemoteUpdate = Partial;
+export type RemoteUpdate = Partial;
/**
* ローカル用コントローラーとリモート用コントローラーの共通基底
@@ -30,7 +30,7 @@
/** 共通初期化としてModelとViewを生成する */
protected constructor(
- data: playerTypes.PlayerData,
+ data: domain.player.PlayerData,
isLocal: boolean,
appearanceResolver: AppearanceResolver,
) {
@@ -57,12 +57,12 @@
}
/** 現在座標を取得する */
- public getPosition(): playerTypes.MovePayload {
+ public getPosition(): domain.player.MovePayload {
return this.model.getPosition();
}
/** 外部送信用スナップショットを取得する */
- public getSnapshot(): playerTypes.PlayerData {
+ public getSnapshot(): domain.player.PlayerData {
return this.model.getSnapshot();
}
@@ -82,7 +82,7 @@
export class LocalPlayerController extends BasePlayerController {
/** ローカルプレイヤー用コントローラーを初期化する */
constructor(
- data: playerTypes.PlayerData,
+ data: domain.player.PlayerData,
appearanceResolver: AppearanceResolver,
) {
super(data, true, appearanceResolver);
@@ -104,7 +104,7 @@
export class RemotePlayerController extends BasePlayerController {
/** リモートプレイヤー用コントローラーを初期化する */
constructor(
- data: playerTypes.PlayerData,
+ data: domain.player.PlayerData,
appearanceResolver: AppearanceResolver,
) {
super(data, false, appearanceResolver);
diff --git a/apps/client/src/scenes/game/entities/player/PlayerModel.ts b/apps/client/src/scenes/game/entities/player/PlayerModel.ts
index 1e2882f..630f248 100644
--- a/apps/client/src/scenes/game/entities/player/PlayerModel.ts
+++ b/apps/client/src/scenes/game/entities/player/PlayerModel.ts
@@ -4,7 +4,7 @@
* ローカル移動,リモート目標座標,送信スナップショットを管理する
*/
import { config } from "@client/config";
-import type { playerTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
/** プレイヤーの座標計算と補間計算を管理するモデル */
export class PlayerModel {
@@ -18,7 +18,7 @@
private targetGridY: number;
/** 共有プレイヤー情報から初期状態を構築する */
- constructor(data: playerTypes.PlayerData) {
+ constructor(data: domain.player.PlayerData) {
this.id = data.id;
this.name = data.name;
this.teamId = data.teamId;
@@ -29,12 +29,12 @@
}
/** 現在座標を取得する */
- public getPosition(): playerTypes.MovePayload {
+ public getPosition(): domain.player.MovePayload {
return { x: this.gridX, y: this.gridY };
}
/** 送信用スナップショットを取得する */
- public getSnapshot(): playerTypes.PlayerData {
+ public getSnapshot(): domain.player.PlayerData {
return {
id: this.id,
name: this.name,
@@ -64,7 +64,7 @@
}
/** リモート更新の目標座標を設定する */
- public setRemoteTarget(update: Partial): void {
+ public setRemoteTarget(update: Partial): void {
if (update.x !== undefined && this.isFiniteNumber(update.x))
this.targetGridX = update.x;
if (update.y !== undefined && this.isFiniteNumber(update.y))
diff --git a/apps/client/src/scenes/lobby/LobbyScene.tsx b/apps/client/src/scenes/lobby/LobbyScene.tsx
index 12ae64a..483505d 100644
--- a/apps/client/src/scenes/lobby/LobbyScene.tsx
+++ b/apps/client/src/scenes/lobby/LobbyScene.tsx
@@ -1,8 +1,8 @@
import { useEffect, useMemo, useState } from "react";
-import type { roomTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
type Props = {
- room: roomTypes.Room | null;
+ room: domain.room.Room | null;
myId: string | null;
onStart: (targetPlayerCount: number) => void;
onBackToTitle: () => void;
@@ -278,7 +278,7 @@
paddingRight: "10px",
}}
>
- {room.players.map((p: roomTypes.RoomMember) => (
+ {room.players.map((p: domain.room.RoomMember) => (
void;
+ onJoin: (payload: domain.room.JoinRoomPayload) => void;
// 入室失敗時の表示メッセージ
joinErrorMessage: string | null;
// 入室リクエスト送信中フラグ
diff --git a/apps/server/src/domains/game/GameManager.ts b/apps/server/src/domains/game/GameManager.ts
index fa7b906..ce01adc 100644
--- a/apps/server/src/domains/game/GameManager.ts
+++ b/apps/server/src/domains/game/GameManager.ts
@@ -3,7 +3,7 @@
* ゲームセッション集合の生成,更新,参照管理を統括する
*/
import type {
- gameTypes,
+ domain,
GameResultPayload,
PlaceBombPayload,
} from "@repo/shared";
@@ -61,7 +61,7 @@
startRoomSession(
playerIds: string[],
playerNamesById: Record,
- onTick: (data: gameTypes.TickData) => void,
+ onTick: (data: domain.game.TickData) => void,
onGameEnd: (payload: GameResultPayload) => void,
onBotPlaceBomb?: (ownerId: string, payload: PlaceBombPayload) => void,
) {
diff --git a/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts b/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts
index a6a84fa..73819f0 100644
--- a/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts
+++ b/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts
@@ -7,10 +7,8 @@
BombPlacedAckPayload,
BombPlacedPayload,
PlayerDeadPayload,
- gameTypes,
- playerTypes,
+ domain,
PlaceBombPayload,
- roomTypes,
CurrentPlayersPayload,
GameResultPayload,
GameStartPayload,
@@ -25,7 +23,7 @@
startRoomSession(
playerIds: string[],
playerNamesById: Record,
- onTick: (data: gameTypes.TickData) => void,
+ onTick: (data: domain.game.TickData) => void,
onGameEnd: (payload: GameResultPayload) => void,
onBotPlaceBomb?: (ownerId: string, payload: PlaceBombPayload) => void,
): void;
@@ -34,7 +32,7 @@
/** 準備完了ユースケースが利用するゲーム状態参照入力ポート */
export interface ReadyForGamePort {
- getRoomPlayers(): playerTypes.PlayerData[];
+ getRoomPlayers(): domain.player.PlayerData[];
getRoomStartTime(): number | undefined;
}
@@ -56,22 +54,22 @@
players: UpdatePlayersPayload,
): void;
publishMapCellUpdatesToRoom(
- roomId: roomTypes.Room["roomId"],
+ roomId: domain.room.Room["roomId"],
cellUpdates: UpdateMapCellsPayload,
): void;
- publishGameEndToRoom(roomId: roomTypes.Room["roomId"]): void;
+ publishGameEndToRoom(roomId: domain.room.Room["roomId"]): void;
publishGameResultToRoom(
- roomId: roomTypes.Room["roomId"],
+ roomId: domain.room.Room["roomId"],
payload: GameResultPayload,
): void;
publishGameStartToRoom(
- roomId: roomTypes.Room["roomId"],
+ roomId: domain.room.Room["roomId"],
payload: GameStartPayload,
): void;
publishCurrentPlayersToSocket(players: CurrentPlayersPayload): void;
publishGameStartToSocket(payload: GameStartPayload): void;
publishPlayerRemovedToRoom(
- roomId: roomTypes.Room["roomId"],
+ roomId: domain.room.Room["roomId"],
removedPlayerId: RemovePlayerPayload,
): void;
}
@@ -79,7 +77,7 @@
/** 爆弾ユースケースが利用する送信出力ポート */
export interface BombOutputPort {
publishBombPlacedToOthersInRoom(
- roomId: roomTypes.Room["roomId"],
+ roomId: domain.room.Room["roomId"],
ownerSocketId: string,
payload: BombPlacedPayload,
): void;
@@ -88,7 +86,7 @@
payload: BombPlacedAckPayload,
): void;
publishPlayerDeadToOthersInRoom(
- roomId: roomTypes.Room["roomId"],
+ roomId: domain.room.Room["roomId"],
deadPlayerId: string,
payload: PlayerDeadPayload,
): void;
diff --git a/apps/server/src/domains/game/application/services/GameRoomSession.ts b/apps/server/src/domains/game/application/services/GameRoomSession.ts
index c932481..abbd935 100644
--- a/apps/server/src/domains/game/application/services/GameRoomSession.ts
+++ b/apps/server/src/domains/game/application/services/GameRoomSession.ts
@@ -8,7 +8,7 @@
logResults,
logScopes,
} from "@server/logging/index";
-import type { gameTypes, GameResultPayload } from "@repo/shared";
+import type { domain, GameResultPayload } from "@repo/shared";
import { config } from "@server/config";
import { GameLoop } from "../../loop/GameLoop";
import { Player } from "../../entities/player/Player.js";
@@ -57,7 +57,7 @@
public start(
tickRate: number,
- onTick: (data: gameTypes.TickData) => void,
+ onTick: (data: domain.game.TickData) => void,
onGameEnd: (payload: GameResultPayload) => void,
onBotPlaceBomb?: (ownerId: string, payload: PlaceBombPayload) => void,
): void {
diff --git a/apps/server/src/domains/game/application/services/GameSessionLifecycleService.ts b/apps/server/src/domains/game/application/services/GameSessionLifecycleService.ts
index a8e0da7..e5d05ec 100644
--- a/apps/server/src/domains/game/application/services/GameSessionLifecycleService.ts
+++ b/apps/server/src/domains/game/application/services/GameSessionLifecycleService.ts
@@ -4,7 +4,7 @@
*/
import { config } from "@server/config";
import type {
- gameTypes,
+ domain,
GameResultPayload,
PlaceBombPayload,
} from "@repo/shared";
@@ -64,7 +64,7 @@
public startRoomSession(
playerIds: string[],
playerNamesById: Record,
- onTick: (data: gameTypes.TickData) => void,
+ onTick: (data: domain.game.TickData) => void,
onGameEnd: (payload: GameResultPayload) => void,
onBotPlaceBomb?: (ownerId: string, payload: PlaceBombPayload) => void,
) {
diff --git a/apps/server/src/domains/game/application/useCases/movePlayerUseCase.ts b/apps/server/src/domains/game/application/useCases/movePlayerUseCase.ts
index 400b1ae..054fbfe 100644
--- a/apps/server/src/domains/game/application/useCases/movePlayerUseCase.ts
+++ b/apps/server/src/domains/game/application/useCases/movePlayerUseCase.ts
@@ -2,13 +2,13 @@
* movePlayerUseCase
* プレイヤー移動入力を受け取り,ゲーム管理へ反映する
*/
-import type { playerTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
import type { MovePlayerPort } from "../ports/gameUseCasePorts";
type MovePlayerUseCaseParams = {
gameManager: MovePlayerPort;
playerId: string;
- move: playerTypes.MovePayload;
+ move: domain.player.MovePayload;
};
/** プレイヤー移動入力をゲーム管理へ委譲する */
diff --git a/apps/server/src/domains/game/entities/map/MapStore.ts b/apps/server/src/domains/game/entities/map/MapStore.ts
index f116f44..3c9e35b 100644
--- a/apps/server/src/domains/game/entities/map/MapStore.ts
+++ b/apps/server/src/domains/game/entities/map/MapStore.ts
@@ -2,7 +2,7 @@
* MapStore
* 塗り状態グリッドと差分更新キューを保持して提供する
*/
-import type { gridMapTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
import { createInitialGridColors } from "./mapGrid.js";
import { paintCellIfChanged } from "./mapPainting.js";
import { drainPendingUpdates } from "./mapUpdates.js";
@@ -12,7 +12,7 @@
// 全マスの現在の色(teamId)を保持
private gridColors: number[];
// 次回の送信ループで送る差分リスト
- private pendingUpdates: gridMapTypes.CellUpdate[];
+ private pendingUpdates: domain.gridMap.CellUpdate[];
constructor() {
// 初期状態は -1 (無色) などで初期化
@@ -35,7 +35,7 @@
/**
* 溜まっている差分を取得し,キューをクリアする(ループ送信時に使用)
*/
- public getAndClearUpdates(): gridMapTypes.CellUpdate[] {
+ public getAndClearUpdates(): domain.gridMap.CellUpdate[] {
return drainPendingUpdates(this.pendingUpdates);
}
diff --git a/apps/server/src/domains/game/entities/map/mapPainting.ts b/apps/server/src/domains/game/entities/map/mapPainting.ts
index 8ffe9fb..efb054c 100644
--- a/apps/server/src/domains/game/entities/map/mapPainting.ts
+++ b/apps/server/src/domains/game/entities/map/mapPainting.ts
@@ -2,11 +2,11 @@
* mapPainting
* マップセルの塗り更新と差分追加処理を提供する
*/
-import type { gridMapTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
type PaintCellParams = {
gridColors: number[];
- pendingUpdates: gridMapTypes.CellUpdate[];
+ pendingUpdates: domain.gridMap.CellUpdate[];
index: number;
teamId: number;
};
diff --git a/apps/server/src/domains/game/entities/map/mapUpdates.ts b/apps/server/src/domains/game/entities/map/mapUpdates.ts
index 9c51618..2d56960 100644
--- a/apps/server/src/domains/game/entities/map/mapUpdates.ts
+++ b/apps/server/src/domains/game/entities/map/mapUpdates.ts
@@ -2,12 +2,12 @@
* mapUpdates
* マップ差分キューの取り出しとクリア処理を提供する
*/
-import type { gridMapTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
/** 差分キューを配列として返却し,キューを空にする */
export const drainPendingUpdates = (
- pendingUpdates: gridMapTypes.CellUpdate[]
-): gridMapTypes.CellUpdate[] => {
+ pendingUpdates: domain.gridMap.CellUpdate[]
+): domain.gridMap.CellUpdate[] => {
const updates = [...pendingUpdates];
pendingUpdates.length = 0;
return updates;
diff --git a/apps/server/src/domains/game/entities/player/Player.ts b/apps/server/src/domains/game/entities/player/Player.ts
index fc4daa5..48943b1 100644
--- a/apps/server/src/domains/game/entities/player/Player.ts
+++ b/apps/server/src/domains/game/entities/player/Player.ts
@@ -2,10 +2,9 @@
* Player
* サーバー側で保持するプレイヤー状態モデルを定義する
*/
-import type { playerTypes } from "@repo/shared";
-// configのimportは不要になります
+import { domain } from "@repo/shared";
-export class Player implements playerTypes.PlayerData {
+export class Player implements domain.player.PlayerData {
public id: string;
public name: string;
public x: number = 0;
diff --git a/apps/server/src/domains/game/entities/player/playerPosition.ts b/apps/server/src/domains/game/entities/player/playerPosition.ts
index 0a2112c..700b0da 100644
--- a/apps/server/src/domains/game/entities/player/playerPosition.ts
+++ b/apps/server/src/domains/game/entities/player/playerPosition.ts
@@ -2,10 +2,10 @@
* playerPosition
* プレイヤー座標からマップ上のセル位置を解決する
*/
-import { gridMapLogic } from "@repo/shared";
+import { domain } from "@repo/shared";
import { Player } from "./Player.js";
/** プレイヤー座標に対応するグリッドインデックスを返す */
export const getPlayerGridIndex = (player: Player): number | null => {
- return gridMapLogic.getGridIndexFromPosition(player.x, player.y);
+ return domain.gridMap.getGridIndexFromPosition(player.x, player.y);
};
diff --git a/apps/server/src/domains/game/loop/GameLoop.ts b/apps/server/src/domains/game/loop/GameLoop.ts
index 339c05d..7497a75 100644
--- a/apps/server/src/domains/game/loop/GameLoop.ts
+++ b/apps/server/src/domains/game/loop/GameLoop.ts
@@ -6,7 +6,7 @@
import { MapStore } from "../entities/map/MapStore";
import { getPlayerGridIndex } from "../entities/player/playerPosition.js";
import { config } from "@server/config";
-import type { gameTypes, PlaceBombPayload } from "@repo/shared";
+import type { domain, PlaceBombPayload } from "@repo/shared";
import { logEvent } from "@server/logging/logger";
import {
gameDomainLogEvents,
@@ -25,7 +25,7 @@
private endMonotonicTimeMs: number = 0;
private nextTickAtMs: number = 0;
private readonly maxCatchUpTicks: number = 3;
- private lastSentPlayers: Map =
+ private lastSentPlayers: Map =
new Map();
private botAiService: BotAiService = new BotAiService();
@@ -34,7 +34,7 @@
private tickRate: number,
private players: Map,
private mapStore: MapStore,
- private onTick: (data: gameTypes.TickData) => void,
+ private onTick: (data: domain.game.TickData) => void,
private onGameEnd: () => void,
private onBotPlaceBomb?: (
ownerId: string,
@@ -143,7 +143,7 @@
});
}
- private buildTickData(): gameTypes.TickData {
+ private buildTickData(): domain.game.TickData {
const activePlayerIds = new Set();
const playerUpdates = this.collectChangedPlayerUpdates(activePlayerIds);
this.cleanupInactivePlayerSnapshots(activePlayerIds);
@@ -156,8 +156,8 @@
private collectChangedPlayerUpdates(
activePlayerIds: Set,
- ): gameTypes.TickData["playerUpdates"] {
- const changedPlayers: gameTypes.TickData["playerUpdates"] = [];
+ ): domain.game.TickData["playerUpdates"] {
+ const changedPlayers: domain.game.TickData["playerUpdates"] = [];
this.players.forEach((player) => {
activePlayerIds.add(player.id);
@@ -167,7 +167,7 @@
}
// 送信用のプレイヤーデータを構築
- const playerData: gameTypes.PlayerPositionUpdate = {
+ const playerData: domain.game.PlayerPositionUpdate = {
id: player.id,
x: player.x,
y: player.y,
diff --git a/apps/server/src/domains/room/RoomManager.ts b/apps/server/src/domains/room/RoomManager.ts
index fc446c6..6a7be2e 100644
--- a/apps/server/src/domains/room/RoomManager.ts
+++ b/apps/server/src/domains/room/RoomManager.ts
@@ -2,7 +2,7 @@
* RoomManager
* ルーム状態の保持とルーム操作サービスへの委譲を担うマネージャ
*/
-import type { roomTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
import { RoomJoinService } from "./application/services/RoomJoinService";
import { RoomExitService } from "./application/services/RoomExitService";
import { RoomPhaseService } from "./application/services/RoomPhaseService";
@@ -15,7 +15,7 @@
/** ルーム操作の公開インターフェースを提供するマネージャ */
export class RoomManager {
- private rooms: Map = new Map();
+ private rooms: Map = new Map();
private roomJoinService: RoomJoinService;
private roomExitService: RoomExitService;
private roomPhaseService: RoomPhaseService;
@@ -39,17 +39,17 @@
}
// オーナーIDからルームを取得する
- public getRoomByOwnerId(ownerId: string): roomTypes.Room | undefined {
+ public getRoomByOwnerId(ownerId: string): domain.room.Room | undefined {
return this.roomQueryService.getRoomByOwnerId(ownerId);
}
// ルームIDからルームを取得する
- public getRoomById(roomId: string): roomTypes.Room | undefined {
+ public getRoomById(roomId: string): domain.room.Room | undefined {
return this.roomQueryService.getRoomById(roomId);
}
// プレイヤーIDから所属ルームを取得する
- public getRoomByPlayerId(playerId: string): roomTypes.Room | undefined {
+ public getRoomByPlayerId(playerId: string): domain.room.Room | undefined {
return this.roomQueryService.getRoomByPlayerId(playerId);
}
diff --git a/apps/server/src/domains/room/application/ports/roomUseCasePorts.ts b/apps/server/src/domains/room/application/ports/roomUseCasePorts.ts
index d72a13c..3cbf6d3 100644
--- a/apps/server/src/domains/room/application/ports/roomUseCasePorts.ts
+++ b/apps/server/src/domains/room/application/ports/roomUseCasePorts.ts
@@ -2,7 +2,7 @@
* roomUseCasePorts
* ルームユースケースが依存する操作ポートを定義する
*/
-import type { roomTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
import type {
BombHitReportValidationPort,
BombPlacementPort,
@@ -23,14 +23,14 @@
/** ルーム参加処理の実行結果 */
export type JoinRoomResult = {
- room: roomTypes.Room;
+ room: domain.room.Room;
status: "joined" | "duplicate" | "full";
};
/** ルームユースケースが利用する出力ポート */
export interface RoomOutputPort {
- publishRoomUpdateToRoom(roomId: roomTypes.Room["roomId"], room: roomTypes.Room): void;
- publishJoinRejectedToSocket(payload: roomTypes.JoinRoomRejectedPayload): void;
+ publishRoomUpdateToRoom(roomId: domain.room.Room["roomId"], room: domain.room.Room): void;
+ publishJoinRejectedToSocket(payload: domain.room.JoinRoomRejectedPayload): void;
}
/** ルーム参加ユースケースが利用する参加操作ポート */
@@ -45,18 +45,18 @@
/** 退出処理で更新対象となったルーム情報 */
export type RoomDisconnectResult = {
- updatedRooms: roomTypes.Room[];
+ updatedRooms: domain.room.Room[];
deletedRoomIds: string[];
};
/** 切断調停で利用するプレイヤー所属ルーム参照ポート */
export interface FindRoomByPlayerPort {
- getRoomByPlayerId(playerId: string): roomTypes.Room | undefined;
+ getRoomByPlayerId(playerId: string): domain.room.Room | undefined;
}
/** ゲーム開始調停で利用するオーナー所属ルーム参照ポート */
export interface FindRoomByOwnerPort {
- getRoomByOwnerId(ownerId: string): roomTypes.Room | undefined;
+ getRoomByOwnerId(ownerId: string): domain.room.Room | undefined;
}
/** ゲーム開始調停で利用するルーム状態遷移ポート */
@@ -68,12 +68,12 @@
/** ルーム状態遷移の実行結果 */
export type RoomPhaseTransitionResult = {
status: "updated" | "not_found" | "invalid_transition";
- room?: roomTypes.Room;
+ room?: domain.room.Room;
};
/** ルームIDでの存在確認に利用する参照ポート */
export interface FindRoomByIdPort {
- getRoomById(roomId: string): roomTypes.Room | undefined;
+ getRoomById(roomId: string): domain.room.Room | undefined;
}
/** ルーム参加後にゲームランタイムを確保する操作ポート */
diff --git a/apps/server/src/domains/room/application/services/RoomExitService.ts b/apps/server/src/domains/room/application/services/RoomExitService.ts
index 1c54f38..90afa17 100644
--- a/apps/server/src/domains/room/application/services/RoomExitService.ts
+++ b/apps/server/src/domains/room/application/services/RoomExitService.ts
@@ -2,17 +2,17 @@
* RoomExitService
* ルーム退出処理とオーナー移譲処理を担うサービス
*/
-import type { roomTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
import type { RoomDisconnectResult } from "../ports/roomUseCasePorts";
import { logEvent } from "@server/logging/logger";
import { logResults, logScopes, roomDomainLogEvents } from "@server/logging/index";
/** 退出要求に応じてプレイヤー削除とルーム整理を行うサービス */
export class RoomExitService {
- constructor(private rooms: Map) {}
+ constructor(private rooms: Map) {}
public removePlayer(socketId: string): RoomDisconnectResult {
- const updatedRooms: roomTypes.Room[] = [];
+ const updatedRooms: domain.room.Room[] = [];
const deletedRoomIds: string[] = [];
for (const [roomId, room] of this.rooms.entries()) {
diff --git a/apps/server/src/domains/room/application/services/RoomJoinService.ts b/apps/server/src/domains/room/application/services/RoomJoinService.ts
index dfaf7b8..8b72619 100644
--- a/apps/server/src/domains/room/application/services/RoomJoinService.ts
+++ b/apps/server/src/domains/room/application/services/RoomJoinService.ts
@@ -2,16 +2,15 @@
* RoomJoinService
* ルーム作成とプレイヤー参加処理を担うサービス
*/
-import { roomConsts } from "@repo/shared";
+import { domain } from "@repo/shared";
import { config } from "@server/config";
-import type { roomTypes } from "@repo/shared";
import { logEvent } from "@server/logging/logger";
import { logResults, logScopes, roomDomainLogEvents } from "@server/logging/index";
import type { JoinRoomResult } from "../ports/roomUseCasePorts";
/** 参加要求に応じてルーム作成と参加者追加を行うサービス */
export class RoomJoinService {
- constructor(private rooms: Map) {}
+ constructor(private rooms: Map) {}
public addPlayerToRoom(roomId: string, socketId: string, playerName: string): JoinRoomResult {
let room = this.rooms.get(roomId);
@@ -20,7 +19,7 @@
roomId,
ownerId: socketId,
players: [],
- status: roomConsts.RoomPhase.WAITING,
+ status: domain.room.RoomPhase.WAITING,
maxPlayers: config.GAME_CONFIG.MAX_PLAYERS_PER_ROOM,
};
this.rooms.set(roomId, room);
@@ -59,7 +58,7 @@
return { room, status: "full" };
}
- const newPlayer: roomTypes.RoomMember = {
+ const newPlayer: domain.room.RoomMember = {
id: socketId,
name: playerName,
isOwner: room.ownerId === socketId,
diff --git a/apps/server/src/domains/room/application/services/RoomPhaseService.ts b/apps/server/src/domains/room/application/services/RoomPhaseService.ts
index b79a237..3ee0466 100644
--- a/apps/server/src/domains/room/application/services/RoomPhaseService.ts
+++ b/apps/server/src/domains/room/application/services/RoomPhaseService.ts
@@ -2,13 +2,12 @@
* RoomPhaseService
* ルーム状態のフェーズ更新処理を提供する
*/
-import { roomConsts } from "@repo/shared";
-import type { roomTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
import type { RoomPhaseTransitionResult } from "../ports/roomUseCasePorts";
/** ルーム状態のフェーズ遷移を管理するサービス */
export class RoomPhaseService {
- constructor(private rooms: Map) {}
+ constructor(private rooms: Map) {}
public markRoomPlaying(roomId: string): RoomPhaseTransitionResult {
const room = this.rooms.get(roomId);
@@ -16,14 +15,14 @@
return { status: "not_found" };
}
- if (room.status === roomConsts.RoomPhase.PLAYING) {
+ if (room.status === domain.room.RoomPhase.PLAYING) {
return {
status: "invalid_transition",
room,
};
}
- room.status = roomConsts.RoomPhase.PLAYING;
+ room.status = domain.room.RoomPhase.PLAYING;
return {
status: "updated",
room,
@@ -36,14 +35,14 @@
return { status: "not_found" };
}
- if (room.status === roomConsts.RoomPhase.WAITING) {
+ if (room.status === domain.room.RoomPhase.WAITING) {
return {
status: "invalid_transition",
room,
};
}
- room.status = roomConsts.RoomPhase.WAITING;
+ room.status = domain.room.RoomPhase.WAITING;
return {
status: "updated",
room,
diff --git a/apps/server/src/domains/room/application/services/RoomQueryService.ts b/apps/server/src/domains/room/application/services/RoomQueryService.ts
index 6881df8..e9b02da 100644
--- a/apps/server/src/domains/room/application/services/RoomQueryService.ts
+++ b/apps/server/src/domains/room/application/services/RoomQueryService.ts
@@ -2,17 +2,17 @@
* RoomQueryService
* ルーム状態の参照系クエリを提供するサービス
*/
-import type { roomTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
/** ルームの参照クエリを提供するサービス */
export class RoomQueryService {
- constructor(private rooms: Map) {}
+ constructor(private rooms: Map) {}
- public getRoomById(roomId: string): roomTypes.Room | undefined {
+ public getRoomById(roomId: string): domain.room.Room | undefined {
return this.rooms.get(roomId);
}
- public getRoomByPlayerId(playerId: string): roomTypes.Room | undefined {
+ public getRoomByPlayerId(playerId: string): domain.room.Room | undefined {
for (const room of this.rooms.values()) {
if (room.players.some((player) => player.id === playerId)) {
return room;
@@ -22,7 +22,7 @@
return undefined;
}
- public getRoomByOwnerId(ownerId: string): roomTypes.Room | undefined {
+ public getRoomByOwnerId(ownerId: string): domain.room.Room | undefined {
for (const room of this.rooms.values()) {
if (room.ownerId === ownerId) {
return room;
diff --git a/apps/server/src/domains/room/application/useCases/joinRoomUseCase.ts b/apps/server/src/domains/room/application/useCases/joinRoomUseCase.ts
index f83aa9b..2b8b02f 100644
--- a/apps/server/src/domains/room/application/useCases/joinRoomUseCase.ts
+++ b/apps/server/src/domains/room/application/useCases/joinRoomUseCase.ts
@@ -2,7 +2,7 @@
* joinRoomUseCase
* ルーム参加要求を処理し,状態更新を配信するユースケース
*/
-import type { roomTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
import type {
EnsureGameRuntimePort,
JoinRoomPort,
@@ -16,7 +16,7 @@
roomManager: JoinRoomPort;
runtimeRegistry: EnsureGameRuntimePort;
socketId: string;
- data: roomTypes.JoinRoomPayload;
+ data: domain.room.JoinRoomPayload;
output: Pick;
};
diff --git a/apps/server/src/logging/constants/eventNames.ts b/apps/server/src/logging/constants/eventNames.ts
index fdeeb92..0aed1a4 100644
--- a/apps/server/src/logging/constants/eventNames.ts
+++ b/apps/server/src/logging/constants/eventNames.ts
@@ -2,7 +2,7 @@
* eventNames
* ログ出力で利用するイベント名定数群を提供する
*/
-import { protocol } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
/** GameUseCaseログで利用するイベント名定数 */
export const gameUseCaseLogEvents = {
diff --git a/apps/server/src/logging/contracts/payloadByScope.ts b/apps/server/src/logging/contracts/payloadByScope.ts
index 0480671..8620418 100644
--- a/apps/server/src/logging/contracts/payloadByScope.ts
+++ b/apps/server/src/logging/contracts/payloadByScope.ts
@@ -2,7 +2,7 @@
* payloadByScope
* スコープごとのログペイロード型契約を提供する
*/
-import { protocol } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
import { gameDomainLogEvents, gameUseCaseLogEvents, roomDomainLogEvents, roomUseCaseLogEvents } from "../constants/eventNames";
import { logResults } from "../constants/results";
import { logScopes } from "../constants/scopes";
diff --git a/apps/server/src/network/handlers/connectionEventLogger.ts b/apps/server/src/network/handlers/connectionEventLogger.ts
index f5ccc84..0fec54f 100644
--- a/apps/server/src/network/handlers/connectionEventLogger.ts
+++ b/apps/server/src/network/handlers/connectionEventLogger.ts
@@ -2,7 +2,7 @@
* connectionEventLogger
* 接続ハンドラで利用するログ記録処理を共通化する
*/
-import { protocol } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
import { logEvent } from "@server/logging/logger";
import { logResults, logScopes } from "@server/logging/index";
diff --git a/apps/server/src/network/handlers/game/createGameOutputAdapter.ts b/apps/server/src/network/handlers/game/createGameOutputAdapter.ts
index bad3082..6e3945c 100644
--- a/apps/server/src/network/handlers/game/createGameOutputAdapter.ts
+++ b/apps/server/src/network/handlers/game/createGameOutputAdapter.ts
@@ -3,15 +3,15 @@
* ゲーム系ユースケースから利用する送信関数群を生成する
*/
import { Server } from "socket.io";
-import { protocol } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
import type {
BombPlacedAckPayload,
BombPlacedPayload,
+ domain,
GameStartPayload,
GameResultPayload,
PlayerDeadPayload,
PongPayload,
- roomTypes,
CurrentPlayersPayload,
RemovePlayerPayload,
UpdateMapCellsPayload,
@@ -25,7 +25,7 @@
import { createEmitToRoom } from "@server/network/adapters/socketEmitters";
import type { CommonHandlerContext } from "../CommonHandler";
-type RoomId = roomTypes.Room["roomId"];
+type RoomId = domain.room.Room["roomId"];
/** ゲーム出力アダプターのインターフェース */
export type GameOutputAdapter = Omit & BombOutputPort;
diff --git a/apps/server/src/network/handlers/game/gameEventOrchestrators.ts b/apps/server/src/network/handlers/game/gameEventOrchestrators.ts
index a522685..874cdf2 100644
--- a/apps/server/src/network/handlers/game/gameEventOrchestrators.ts
+++ b/apps/server/src/network/handlers/game/gameEventOrchestrators.ts
@@ -4,7 +4,7 @@
* 受信ハンドラからユースケース実行責務を分離する
* ランタイム未解決時はNetworkスコープでignored_missing_roomを記録する
*/
-import { protocol, type BombHitReportPayload, type PingPayload, type PlaceBombPayload, type playerTypes } from "@repo/shared";
+import { contracts as protocol, domain, type BombHitReportPayload, type PingPayload, type PlaceBombPayload } from "@repo/shared";
import { readyForGameCoordinator } from "@server/application/coordinators/readyForGameCoordinator";
import { startGameCoordinator } from "@server/application/coordinators/startGameCoordinator";
import { movePlayerUseCase } from "@server/domains/game/application/useCases/movePlayerUseCase";
@@ -84,7 +84,7 @@
/** MOVEイベントを調停して移動ユースケースを実行する */
export const handleMoveEvent = (
deps: GameEventOrchestratorDeps,
- move: playerTypes.MovePayload,
+ move: domain.player.MovePayload,
): void => {
const resolved = runWithRuntimeByPlayerId(
deps.roomManager,
diff --git a/apps/server/src/network/handlers/game/registerGameHandlers.ts b/apps/server/src/network/handlers/game/registerGameHandlers.ts
index 22b807c..46a7dee 100644
--- a/apps/server/src/network/handlers/game/registerGameHandlers.ts
+++ b/apps/server/src/network/handlers/game/registerGameHandlers.ts
@@ -3,7 +3,7 @@
* ゲーム関連イベントの受信ハンドラを登録する
*/
import { Socket } from "socket.io";
-import { protocol } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
import type {
GameEventRoomUseCasePort,
GameEventRuntimeUseCasePort,
diff --git a/apps/server/src/network/handlers/orchestratorEventLogger.ts b/apps/server/src/network/handlers/orchestratorEventLogger.ts
index 7cfb0a5..ca7487b 100644
--- a/apps/server/src/network/handlers/orchestratorEventLogger.ts
+++ b/apps/server/src/network/handlers/orchestratorEventLogger.ts
@@ -2,7 +2,7 @@
* orchestratorEventLogger
* オーケストレータ層で利用するイベントログ記録を共通化する
*/
-import { protocol } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
import { logEvent } from "@server/logging/logger";
import { logResults, logScopes } from "@server/logging/index";
diff --git a/apps/server/src/network/handlers/payloadGuard.ts b/apps/server/src/network/handlers/payloadGuard.ts
index dd1ab88..3bd6936 100644
--- a/apps/server/src/network/handlers/payloadGuard.ts
+++ b/apps/server/src/network/handlers/payloadGuard.ts
@@ -2,7 +2,7 @@
* payloadGuard
* 受信ペイロード検証と不正時ログ記録を共通化するガード生成を担う
*/
-import { protocol } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
import { logEvent } from "@server/logging/logger";
import { logResults, logScopes } from "@server/logging/index";
diff --git a/apps/server/src/network/handlers/registerConnectionHandlers.ts b/apps/server/src/network/handlers/registerConnectionHandlers.ts
index 0703ca3..fc5d64b 100644
--- a/apps/server/src/network/handlers/registerConnectionHandlers.ts
+++ b/apps/server/src/network/handlers/registerConnectionHandlers.ts
@@ -3,7 +3,7 @@
* 接続時にルームとゲームの各ハンドラを登録する
*/
import { Socket } from "socket.io";
-import { protocol } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
import { disconnectCoordinator } from "@server/application/coordinators/disconnectCoordinator";
import { registerGameHandlers } from "./game/registerGameHandlers";
import { registerRoomHandlers } from "./room/registerRoomHandlers";
diff --git a/apps/server/src/network/handlers/room/createRoomOutputAdapter.ts b/apps/server/src/network/handlers/room/createRoomOutputAdapter.ts
index 90aacab..090a0b9 100644
--- a/apps/server/src/network/handlers/room/createRoomOutputAdapter.ts
+++ b/apps/server/src/network/handlers/room/createRoomOutputAdapter.ts
@@ -3,14 +3,14 @@
* ルーム系ユースケースから利用する送信関数を生成する
*/
import { Server } from "socket.io";
-import { protocol } from "@repo/shared";
-import type { roomTypes } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
+import { domain } from "@repo/shared";
import type { RoomOutputPort } from "@server/domains/room/application/ports/roomUseCasePorts";
import { createEmitToRoom } from "@server/network/adapters/socketEmitters";
import type { CommonHandlerContext } from "../CommonHandler";
-type RoomId = roomTypes.Room["roomId"];
-type RoomUpdatePayload = roomTypes.Room;
+type RoomId = domain.room.Room["roomId"];
+type RoomUpdatePayload = domain.room.Room;
/** ルーム出力アダプターのインターフェース */
export type RoomOutputAdapter = RoomOutputPort;
@@ -23,7 +23,7 @@
publishRoomUpdateToRoom: (roomId: RoomId, room: RoomUpdatePayload) => {
common.emitToRoom(roomId, protocol.SocketEvents.ROOM_UPDATE, room);
},
- publishJoinRejectedToSocket: (payload: roomTypes.JoinRoomRejectedPayload) => {
+ publishJoinRejectedToSocket: (payload: domain.room.JoinRoomRejectedPayload) => {
common.emitToSocket(protocol.SocketEvents.ROOM_JOIN_REJECTED, payload);
},
};
diff --git a/apps/server/src/network/handlers/room/registerRoomHandlers.ts b/apps/server/src/network/handlers/room/registerRoomHandlers.ts
index 7fdd565..bb3f083 100644
--- a/apps/server/src/network/handlers/room/registerRoomHandlers.ts
+++ b/apps/server/src/network/handlers/room/registerRoomHandlers.ts
@@ -3,7 +3,7 @@
* ルーム参加イベントの受信ハンドラを登録する
*/
import { Socket } from "socket.io";
-import { protocol } from "@repo/shared";
+import { contracts as protocol } from "@repo/shared";
import type {
JoinRoomEventRoomUseCasePort,
JoinRoomEventRuntimeUseCasePort,
diff --git a/apps/server/src/network/handlers/room/roomEventOrchestrators.ts b/apps/server/src/network/handlers/room/roomEventOrchestrators.ts
index 3de3c7a..b3b4996 100644
--- a/apps/server/src/network/handlers/room/roomEventOrchestrators.ts
+++ b/apps/server/src/network/handlers/room/roomEventOrchestrators.ts
@@ -4,7 +4,7 @@
* 受信ハンドラからユースケース実行責務を分離する
* 本ファイルではランタイム未解決ログ対象イベントを扱わない
*/
-import type { roomTypes } from "@repo/shared";
+import { domain } from "@repo/shared";
import { joinRoomUseCase } from "@server/domains/room/application/useCases/joinRoomUseCase";
import { logEvent } from "@server/logging/logger";
import { logResults, logScopes, roomUseCaseLogEvents } from "@server/logging/index";
@@ -29,7 +29,7 @@
/** JOIN_ROOMイベントを調停して参加ユースケースを実行する */
export const handleJoinRoomEvent = async (
deps: JoinRoomOrchestratorDeps,
- payload: roomTypes.JoinRoomPayload,
+ payload: domain.room.JoinRoomPayload,
): Promise => {
const joinResult = joinRoomUseCase({
roomManager: deps.roomManager,
diff --git a/apps/server/src/network/handlers/socketEventBridge.ts b/apps/server/src/network/handlers/socketEventBridge.ts
index 977ef98..3ead355 100644
--- a/apps/server/src/network/handlers/socketEventBridge.ts
+++ b/apps/server/src/network/handlers/socketEventBridge.ts
@@ -14,16 +14,16 @@
/** サーバー向けの型付きソケットイベント bridge を生成する */
export const createServerSocketOnBridge = (socket: Socket) => {
const bridgeTarget: SocketBridgeTarget = {
- on: (event, callback) => {
- socket.on(event, callback);
+ on: (event: string, callback: (payload: TPayload) => void) => {
+ socket.on(event, callback as (payload: unknown) => void);
},
- once: (event, callback) => {
- socket.once(event, callback);
+ once: (event: string, callback: (payload: TPayload) => void) => {
+ socket.once(event, callback as (payload: unknown) => void);
},
- off: (event, callback) => {
- socket.off(event, callback);
+ off: (event: string, callback: (payload: TPayload) => void) => {
+ socket.off(event, callback as (payload: unknown) => void);
},
- emit: (event, payload) => {
+ emit: (event: string, payload?: unknown) => {
if (payload === undefined) {
socket.emit(event);
return;
diff --git a/apps/server/src/network/validation/socketPayloadValidators.ts b/apps/server/src/network/validation/socketPayloadValidators.ts
index 7f05d71..39941ea 100644
--- a/apps/server/src/network/validation/socketPayloadValidators.ts
+++ b/apps/server/src/network/validation/socketPayloadValidators.ts
@@ -3,8 +3,7 @@
* ソケット受信ペイロードの型ガードを提供する
*/
import type {
- playerTypes,
- roomTypes,
+ domain,
PlaceBombPayload,
BombHitReportPayload,
} from "@repo/shared";
@@ -27,7 +26,7 @@
/** MOVEイベントのペイロードが移動座標であるか判定する */
export const isMovePayload = (
value: unknown,
-): value is playerTypes.MovePayload => {
+): value is domain.player.MovePayload => {
if (typeof value !== "object" || value === null) {
return false;
}
@@ -79,7 +78,7 @@
/** JOIN_ROOMイベントのペイロードが参加情報であるか判定する */
export const isJoinRoomPayload = (
value: unknown,
-): value is roomTypes.JoinRoomPayload => {
+): value is domain.room.JoinRoomPayload => {
if (typeof value !== "object" || value === null) {
return false;
}
diff --git "a/docs/02_Guide/GUIDE_05_\343\203\227\343\203\255\343\203\210\343\202\263\343\203\253\350\277\275\345\212\240\346\211\213\351\240\206.txt" "b/docs/02_Guide/GUIDE_05_\343\203\227\343\203\255\343\203\210\343\202\263\343\203\253\350\277\275\345\212\240\346\211\213\351\240\206.txt"
index 56c5839..3104ac6 100644
--- "a/docs/02_Guide/GUIDE_05_\343\203\227\343\203\255\343\203\210\343\202\263\343\203\253\350\277\275\345\212\240\346\211\213\351\240\206.txt"
+++ "b/docs/02_Guide/GUIDE_05_\343\203\227\343\203\255\343\203\210\343\202\263\343\203\253\350\277\275\345\212\240\346\211\213\351\240\206.txt"
@@ -73,8 +73,8 @@
・events.ts 再公開が過不足ないか
・client/server で型エラーがないか
・既存イベントの型互換を壊していないか
-・player 座標差分イベント(UPDATE_PLAYERS)に teamId を含めていないか
-・初期同期イベント(CURRENT_PLAYERS / NEW_PLAYER)に teamId を含めているか
+・player 座標差分イベント(SocketEvents.UPDATE_PLAYERS / update-players)に teamId を含めていないか
+・初期同期イベント(SocketEvents.CURRENT_PLAYERS / current-players,SocketEvents.NEW_PLAYER / new-player)に teamId を含めているか
6. 典型ミスと対策 (Common Pitfalls)
diff --git a/packages/shared/eslint.config.mjs b/packages/shared/eslint.config.mjs
new file mode 100644
index 0000000..e314f77
--- /dev/null
+++ b/packages/shared/eslint.config.mjs
@@ -0,0 +1,16 @@
+import tsParser from '@typescript-eslint/parser';
+
+export default [
+ {
+ ignores: ['dist/**', 'node_modules/**'],
+ },
+ {
+ files: ['src/**/*.ts'],
+ languageOptions: {
+ parser: tsParser,
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ },
+ rules: {},
+ },
+];
diff --git a/packages/shared/package.json b/packages/shared/package.json
index 02afce3..55e5450 100644
--- a/packages/shared/package.json
+++ b/packages/shared/package.json
@@ -18,6 +18,8 @@
},
"scripts": {
"build": "tsup src/index.ts src/config/gameConfig.ts --format cjs,esm --dts",
+ "lint": "eslint src --ext .ts",
+ "lint:fix": "eslint src --ext .ts --fix",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
@@ -25,6 +27,8 @@
"license": "ISC",
"packageManager": "pnpm@10.28.2",
"devDependencies": {
+ "@typescript-eslint/parser": "^8.56.1",
+ "eslint": "^10.0.2",
"tsup": "^8.5.1",
"typescript": "^5.9.3"
}
diff --git a/packages/shared/src/config/gameConfig.ts b/packages/shared/src/config/gameConfig.ts
index c3dcdbd..7c11d92 100644
--- a/packages/shared/src/config/gameConfig.ts
+++ b/packages/shared/src/config/gameConfig.ts
@@ -43,36 +43,3 @@
/** プレイヤー情報から teamId を解決できない場合に利用する既定値 */
export const UNKNOWN_TEAM_ID = -1;
-
-/** teamId が unknown を表す値か判定する */
-export const isUnknownTeamId = (teamId: number): boolean => {
- return teamId === UNKNOWN_TEAM_ID;
-};
-
-/** teamId が有効範囲内かを真偽値で判定する */
-export const isKnownTeamId = (teamId: number): boolean => {
- return (
- Number.isInteger(teamId) && teamId >= 0 && teamId < GAME_CONFIG.TEAM_COUNT
- );
-};
-
-/** TEAM_COUNT と TEAM_NAMES の整合性を検証する */
-export const validateTeamConfig = (): void => {
- const { TEAM_COUNT } = GAME_CONFIG;
-
- if (TEAM_NAMES.length !== TEAM_COUNT) {
- throw new Error(
- `GAME_CONFIG mismatch: TEAM_NAMES length (${TEAM_NAMES.length}) must equal TEAM_COUNT (${TEAM_COUNT})`,
- );
- }
-};
-
-/** teamId が有効範囲内かを検証する */
-export const assertValidTeamId = (teamId: number): void => {
- validateTeamConfig();
-
- const { TEAM_COUNT } = GAME_CONFIG;
- if (!Number.isInteger(teamId) || teamId < 0 || teamId >= TEAM_COUNT) {
- throw new Error(`Invalid teamId: ${teamId}`);
- }
-};
diff --git a/packages/shared/src/config/index.ts b/packages/shared/src/config/index.ts
index 27ba7e8..3d3230d 100644
--- a/packages/shared/src/config/index.ts
+++ b/packages/shared/src/config/index.ts
@@ -1,5 +1,21 @@
+/**
+ * index
+ * 共有設定値を集約して再公開するエントリ
+ * ゲーム設定とネットワーク設定の参照口を一本化する
+ */
+
+/** ゲーム全体の共有設定値を再公開する */
export { GAME_CONFIG } from "./gameConfig";
+/** チーム名配列を再公開する */
export { TEAM_NAMES } from "./gameConfig";
+/** 未確定 teamId の既定値を再公開する */
export { UNKNOWN_TEAM_ID } from "./gameConfig";
-export { validateTeamConfig, assertValidTeamId, isUnknownTeamId, isKnownTeamId } from "./gameConfig";
+/** チーム設定関連の検証関数を再公開する */
+export {
+ validateTeamConfig,
+ assertValidTeamId,
+ isUnknownTeamId,
+ isKnownTeamId,
+} from "./teamValidators";
+/** ネットワーク共有設定値を再公開する */
export { NETWORK_CONFIG } from "./networkConfig";
diff --git a/packages/shared/src/config/networkConfig.ts b/packages/shared/src/config/networkConfig.ts
index eff99b6..f5ad576 100644
--- a/packages/shared/src/config/networkConfig.ts
+++ b/packages/shared/src/config/networkConfig.ts
@@ -1,3 +1,10 @@
+/**
+ * networkConfig
+ * ネットワーク通信で利用する共有設定値を定義する
+ * クライアントとサーバーの接続契約を集約する
+ */
+
+/** ソケット通信で利用する共有設定値 */
export const NETWORK_CONFIG = {
SOCKET_IO_PATH: "/socket.io",
} as const;
diff --git a/packages/shared/src/config/teamValidators.ts b/packages/shared/src/config/teamValidators.ts
new file mode 100644
index 0000000..badcc25
--- /dev/null
+++ b/packages/shared/src/config/teamValidators.ts
@@ -0,0 +1,39 @@
+/**
+ * teamValidators
+ * チーム設定に対する検証関数を定義する
+ * 設定値と参照IDの整合性検査を集約する
+ */
+import { GAME_CONFIG, TEAM_NAMES, UNKNOWN_TEAM_ID } from "./gameConfig";
+
+/** teamId が unknown を表す値か判定する */
+export const isUnknownTeamId = (teamId: number): boolean => {
+ return teamId === UNKNOWN_TEAM_ID;
+};
+
+/** teamId が有効範囲内かを真偽値で判定する */
+export const isKnownTeamId = (teamId: number): boolean => {
+ return (
+ Number.isInteger(teamId) && teamId >= 0 && teamId < GAME_CONFIG.TEAM_COUNT
+ );
+};
+
+/** TEAM_COUNT と TEAM_NAMES の整合性を検証する */
+export const validateTeamConfig = (): void => {
+ const { TEAM_COUNT } = GAME_CONFIG;
+
+ if (TEAM_NAMES.length !== TEAM_COUNT) {
+ throw new Error(
+ `GAME_CONFIG mismatch: TEAM_NAMES length (${TEAM_NAMES.length}) must equal TEAM_COUNT (${TEAM_COUNT})`,
+ );
+ }
+};
+
+/** teamId が有効範囲内かを検証する */
+export const assertValidTeamId = (teamId: number): void => {
+ validateTeamConfig();
+
+ const { TEAM_COUNT } = GAME_CONFIG;
+ if (!Number.isInteger(teamId) || teamId < 0 || teamId >= TEAM_COUNT) {
+ throw new Error(`Invalid teamId: ${teamId}`);
+ }
+};
diff --git a/packages/shared/src/domains/app/app.const.ts b/packages/shared/src/domains/app/app.const.ts
index f8beb8d..f72fd2a 100644
--- a/packages/shared/src/domains/app/app.const.ts
+++ b/packages/shared/src/domains/app/app.const.ts
@@ -1,6 +1,11 @@
+/**
+ * app.const
+ * アプリ状態領域で利用する定数を定義する
+ * 画面遷移フェーズ値を外部利用向けに提供する
+ */
import type { ScenePhase as ScenePhaseType } from "./app.type";
-// クライアント画面遷移利用フェーズの値
+/** クライアント画面遷移で利用するフェーズ定数 */
export const ScenePhase = {
TITLE: "title",
LOBBY: "lobby",
diff --git a/packages/shared/src/domains/app/app.type.ts b/packages/shared/src/domains/app/app.type.ts
index 83777d0..b334be3 100644
--- a/packages/shared/src/domains/app/app.type.ts
+++ b/packages/shared/src/domains/app/app.type.ts
@@ -1,2 +1,8 @@
-// クライアント画面遷移利用フェーズ型
+/**
+ * app.type
+ * アプリ状態領域で利用する共有型を定義する
+ * 画面遷移フェーズ契約を外部参照向けに提供する
+ */
+
+/** クライアント画面遷移で利用するフェーズ型 */
export type ScenePhase = "title" | "lobby" | "playing" | "result";
diff --git a/packages/shared/src/domains/app/index.ts b/packages/shared/src/domains/app/index.ts
new file mode 100644
index 0000000..026f0bb
--- /dev/null
+++ b/packages/shared/src/domains/app/index.ts
@@ -0,0 +1,10 @@
+/**
+ * index
+ * app ドメインの公開要素を集約して再公開する
+ * 画面遷移フェーズの型と定数を外部利用向けに束ねる
+ */
+
+/** 画面遷移フェーズ定数を再公開する */
+export { ScenePhase } from "./app.const";
+/** 画面遷移フェーズ型を再公開する */
+export type { ScenePhase as ScenePhaseType } from "./app.type";
diff --git a/packages/shared/src/domains/game/index.ts b/packages/shared/src/domains/game/index.ts
new file mode 100644
index 0000000..3b3cd6b
--- /dev/null
+++ b/packages/shared/src/domains/game/index.ts
@@ -0,0 +1,8 @@
+/**
+ * index
+ * game ドメインの公開要素を集約して再公開する
+ * ゲーム進行で利用する型を外部利用向けに束ねる
+ */
+
+/** ゲーム進行関連の型を再公開する */
+export type { PlayerPositionUpdate, TickData } from "./game.type";
diff --git a/packages/shared/src/domains/gridMap/gridMap.type.ts b/packages/shared/src/domains/gridMap/gridMap.type.ts
index d85090e..3e7811a 100644
--- a/packages/shared/src/domains/gridMap/gridMap.type.ts
+++ b/packages/shared/src/domains/gridMap/gridMap.type.ts
@@ -1,7 +1,15 @@
+/**
+ * gridMap.type
+ * グリッドマップ領域で利用する共有型を定義する
+ * マップ状態と差分更新の契約を集約する
+ */
+
+/** マップ全体の色状態を保持する構造 */
export interface MapState {
gridColors: number[];
}
+/** マップ1セル分の差分更新情報 */
export interface CellUpdate {
index: number;
teamId: number;
diff --git a/packages/shared/src/domains/gridMap/index.ts b/packages/shared/src/domains/gridMap/index.ts
new file mode 100644
index 0000000..5daa48f
--- /dev/null
+++ b/packages/shared/src/domains/gridMap/index.ts
@@ -0,0 +1,10 @@
+/**
+ * index
+ * gridMap ドメインの公開要素を集約して再公開する
+ * 型定義と座標変換ロジックを外部利用向けに束ねる
+ */
+
+/** グリッドマップ関連の型を再公開する */
+export type { MapState, CellUpdate } from "./gridMap.type";
+/** グリッド座標変換ロジックを再公開する */
+export { getGridIndexFromPosition } from "./gridMap.logic";
diff --git a/packages/shared/src/domains/index.ts b/packages/shared/src/domains/index.ts
new file mode 100644
index 0000000..15dcb80
--- /dev/null
+++ b/packages/shared/src/domains/index.ts
@@ -0,0 +1,16 @@
+/**
+ * index
+ * domains 配下の公開要素を集約して再公開する
+ * ドメイン単位で参照できる安定公開面を提供する
+ */
+
+/** app ドメインを再公開する */
+export * as app from "./app";
+/** game ドメインを再公開する */
+export * as game from "./game";
+/** gridMap ドメインを再公開する */
+export * as gridMap from "./gridMap";
+/** player ドメインを再公開する */
+export * as player from "./player";
+/** room ドメインを再公開する */
+export * as room from "./room";
diff --git a/packages/shared/src/domains/player/index.ts b/packages/shared/src/domains/player/index.ts
new file mode 100644
index 0000000..9ce56af
--- /dev/null
+++ b/packages/shared/src/domains/player/index.ts
@@ -0,0 +1,8 @@
+/**
+ * index
+ * player ドメインの公開要素を集約して再公開する
+ * プレイヤー契約で利用する型を外部利用向けに束ねる
+ */
+
+/** プレイヤー契約関連の型を再公開する */
+export type { PlayerData, MovePayload } from "./player.type";
diff --git a/packages/shared/src/domains/player/player.type.ts b/packages/shared/src/domains/player/player.type.ts
index c478463..108052d 100644
--- a/packages/shared/src/domains/player/player.type.ts
+++ b/packages/shared/src/domains/player/player.type.ts
@@ -1,4 +1,10 @@
-// クライアント・サーバー間共有プレイヤー基本情報型
+/**
+ * player.type
+ * プレイヤー領域で利用する共有型を定義する
+ * クライアントとサーバーで参照する契約を集約する
+ */
+
+/** クライアントとサーバー間で共有するプレイヤー基本情報 */
export interface PlayerData {
id: string;
name: string;
@@ -8,7 +14,7 @@
teamId: number; // 0〜3 のチームID
}
-// 移動イベント送信ペイロード型
+/** MOVE イベントで利用する移動入力ペイロード */
export interface MovePayload {
// グリッド単位の座標
x: number;
diff --git a/packages/shared/src/domains/room/index.ts b/packages/shared/src/domains/room/index.ts
new file mode 100644
index 0000000..cd19cd4
--- /dev/null
+++ b/packages/shared/src/domains/room/index.ts
@@ -0,0 +1,18 @@
+/**
+ * index
+ * room ドメインの公開要素を集約して再公開する
+ * ルーム状態契約の型と定数を外部利用向けに束ねる
+ */
+
+/** ルーム進行フェーズ定数を再公開する */
+export { RoomPhase } from "./room.const";
+/** ルーム進行フェーズ型を再公開する */
+export type { RoomPhase as RoomPhaseType } from "./room.const";
+/** ルーム契約関連の型を再公開する */
+export type {
+ RoomMember,
+ Room,
+ JoinRoomPayload,
+ JoinRoomRejectedReason,
+ JoinRoomRejectedPayload,
+} from "./room.type";
diff --git a/packages/shared/src/domains/room/room.const.ts b/packages/shared/src/domains/room/room.const.ts
index bf0f189..ee3ece3 100644
--- a/packages/shared/src/domains/room/room.const.ts
+++ b/packages/shared/src/domains/room/room.const.ts
@@ -1,6 +1,11 @@
+/**
+ * room.const
+ * ルーム領域で利用する定数を定義する
+ * 進行フェーズ値を外部利用向けに提供する
+ */
import type { RoomPhase as RoomPhaseType } from "./room.type";
-// ルーム進行フェーズ状態の値
+/** ルーム進行フェーズで利用する定数 */
export const RoomPhase = {
WAITING: "waiting",
PLAYING: "playing",
diff --git a/packages/shared/src/domains/room/room.type.ts b/packages/shared/src/domains/room/room.type.ts
index f69dcbd..ce8c529 100644
--- a/packages/shared/src/domains/room/room.type.ts
+++ b/packages/shared/src/domains/room/room.type.ts
@@ -1,7 +1,13 @@
-// ルーム進行フェーズ状態型
+/**
+ * room.type
+ * ルーム領域で利用する共有型を定義する
+ * 参加状態とイベントペイロード契約を集約する
+ */
+
+/** ルーム進行フェーズ状態型 */
export type RoomPhase = "waiting" | "playing" | "result";
-// ルーム所属プレイヤー情報型
+/** ルーム所属プレイヤー情報 */
export interface RoomMember {
id: string;
name: string;
@@ -9,7 +15,7 @@
isReady: boolean;
}
-// ルーム全体状態データ構造型
+/** ルーム全体状態データ */
export interface Room {
roomId: string;
ownerId: string;
@@ -18,16 +24,16 @@
maxPlayers: number;
}
-// ルーム参加時送信ペイロード型
+/** ルーム参加時に送信するペイロード */
export interface JoinRoomPayload {
roomId: string;
playerName: string;
}
-// ルーム参加拒否理由型
+/** ルーム参加拒否理由 */
export type JoinRoomRejectedReason = "full" | "duplicate";
-// ルーム参加拒否通知ペイロード型
+/** ルーム参加拒否通知ペイロード */
export interface JoinRoomRejectedPayload {
roomId: string;
reason: JoinRoomRejectedReason;
diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts
index 8eb0070..4f69fcd 100644
--- a/packages/shared/src/index.ts
+++ b/packages/shared/src/index.ts
@@ -1,8 +1,14 @@
/**
* index
* shared パッケージの公開 API を集約して再公開するエントリ
- * ドメイン型,プロトコル型,設定値を外部利用向けに束ねる
+ * 安定公開面と既存互換公開面を併存して外部利用向けに束ねる
*/
+/** 安定公開面として domains の集約を再公開 */
+export * as domain from "./domains";
+/** 安定公開面として protocol 契約の集約を再公開 */
+export * as contracts from "./protocol";
+
+/** 既存互換のため,以下は従来どおり再公開する */
/** グリッドマップ関連の型定義を再公開 */
export * as gridMapTypes from "./domains/gridMap/gridMap.type";
/** グリッドマップ関連のロジックを再公開 */
diff --git a/packages/shared/src/protocol/eventPayloadMaps.ts b/packages/shared/src/protocol/eventPayloadMaps.ts
index eabb623..5f371c3 100644
--- a/packages/shared/src/protocol/eventPayloadMaps.ts
+++ b/packages/shared/src/protocol/eventPayloadMaps.ts
@@ -4,7 +4,7 @@
* 機能別に分割した対応表を合成して公開契約を維持する
*/
import type {
- ConnectionLifecycleEventPayloadMap as CommonConnectionLifecycleEventPayloadMap,
+ ConnectionLifecycleEventPayloadMap,
} from "./maps/commonEventPayloadMap";
import type {
LobbyClientToServerEventPayloadMap,
@@ -18,9 +18,6 @@
/** 接続ライフサイクルイベントのペイロード対応表を再公開する */
export type { ConnectionLifecycleEventPayloadMap } from "./maps/commonEventPayloadMap";
-/** 接続ライフサイクルイベントのペイロード対応表 */
-type ConnectionLifecycleEventPayloadMap = CommonConnectionLifecycleEventPayloadMap;
-
/** クライアントからサーバーへ送信するイベントごとのペイロード対応表 */
export type ClientToServerEventPayloadMap =
& LobbyClientToServerEventPayloadMap
diff --git a/packages/shared/src/protocol/eventPayloads.ts b/packages/shared/src/protocol/eventPayloads.ts
index e444c18..3276144 100644
--- a/packages/shared/src/protocol/eventPayloads.ts
+++ b/packages/shared/src/protocol/eventPayloads.ts
@@ -16,6 +16,8 @@
/** ゲームイベントのペイロード型を再公開する */
export type {
+ PlayerSnapshotPayload,
+ PlayerDeltaPayload,
InitialPlayerSyncPayload,
DeltaPlayerSyncPayload,
UpdatePlayersPayload,
diff --git a/packages/shared/src/protocol/index.ts b/packages/shared/src/protocol/index.ts
new file mode 100644
index 0000000..f6e00f1
--- /dev/null
+++ b/packages/shared/src/protocol/index.ts
@@ -0,0 +1,12 @@
+/**
+ * index
+ * protocol 配下の公開要素を集約して再公開する
+ * イベント契約と bridge をまとめた安定公開面を提供する
+ */
+
+/** ソケットイベント契約を再公開する */
+export * from "./events";
+/** ソケットイベント bridge を再公開する */
+export { createSocketEventBridge } from "./socketEventBridge";
+/** ソケットイベント bridge の対象インターフェースを再公開する */
+export type { SocketBridgeTarget } from "./socketEventBridge";
diff --git a/packages/shared/src/protocol/maps/gameEventPayloadMap.ts b/packages/shared/src/protocol/maps/gameEventPayloadMap.ts
index 7cc6fc9..2772b08 100644
--- a/packages/shared/src/protocol/maps/gameEventPayloadMap.ts
+++ b/packages/shared/src/protocol/maps/gameEventPayloadMap.ts
@@ -5,6 +5,10 @@
*/
import { SocketEvents } from "../socketEvents";
import type {
+ PingPayload,
+ PongPayload,
+} from "../payloads/commonPayloads";
+import type {
BombHitReportPayload,
BombPlacedAckPayload,
BombPlacedPayload,
@@ -16,12 +20,10 @@
NewPlayerPayload,
PlaceBombPayload,
PlayerDeadPayload,
- PingPayload,
- PongPayload,
RemovePlayerPayload,
UpdateMapCellsPayload,
UpdatePlayersPayload,
-} from "../eventPayloads";
+} from "../payloads/gamePayloads";
/** ゲーム関連のクライアント送信イベントペイロード対応表 */
export type GameClientToServerEventPayloadMap = {
@@ -36,11 +38,11 @@
/** ゲーム関連のサーバー送信イベントペイロード対応表 */
export type GameServerToClientEventPayloadMap = {
[SocketEvents.GAME_START]: GameStartPayload;
- [SocketEvents.CURRENT_PLAYERS]: CurrentPlayersPayload;
- [SocketEvents.NEW_PLAYER]: NewPlayerPayload;
- [SocketEvents.UPDATE_PLAYERS]: UpdatePlayersPayload;
- [SocketEvents.REMOVE_PLAYER]: RemovePlayerPayload;
- [SocketEvents.UPDATE_MAP_CELLS]: UpdateMapCellsPayload;
+ [SocketEvents.CURRENT_PLAYERS_SYNC]: CurrentPlayersPayload;
+ [SocketEvents.NEW_PLAYER_SYNC]: NewPlayerPayload;
+ [SocketEvents.UPDATE_PLAYERS_SYNC]: UpdatePlayersPayload;
+ [SocketEvents.REMOVE_PLAYER_SYNC]: RemovePlayerPayload;
+ [SocketEvents.UPDATE_MAP_CELLS_SYNC]: UpdateMapCellsPayload;
[SocketEvents.BOMB_PLACED]: BombPlacedPayload;
[SocketEvents.BOMB_PLACED_ACK]: BombPlacedAckPayload;
[SocketEvents.PLAYER_DEAD]: PlayerDeadPayload;
diff --git a/packages/shared/src/protocol/maps/lobbyEventPayloadMap.ts b/packages/shared/src/protocol/maps/lobbyEventPayloadMap.ts
index 796ff47..9625774 100644
--- a/packages/shared/src/protocol/maps/lobbyEventPayloadMap.ts
+++ b/packages/shared/src/protocol/maps/lobbyEventPayloadMap.ts
@@ -8,7 +8,7 @@
JoinRoomPayload,
RoomJoinRejectedPayload,
RoomUpdatePayload,
-} from "../eventPayloads";
+} from "../payloads/lobbyPayloads";
/** ロビー関連のクライアント送信イベントペイロード対応表 */
export type LobbyClientToServerEventPayloadMap = {
diff --git a/packages/shared/src/protocol/payloads/gamePayloads.ts b/packages/shared/src/protocol/payloads/gamePayloads.ts
index a8d5999..6e1d6b2 100644
--- a/packages/shared/src/protocol/payloads/gamePayloads.ts
+++ b/packages/shared/src/protocol/payloads/gamePayloads.ts
@@ -10,7 +10,7 @@
PlayerData,
} from "../../domains/player/player.type";
-/** GAME_RESULT イベントで送受信するランキング1行 */
+/** game-result イベントで送受信するランキング1行 */
export type GameResultRanking = {
rank: number;
teamId: number;
@@ -18,53 +18,62 @@
paintRate: number;
};
-/** GAME_RESULT イベントで送受信する最終結果 */
+/** game-result イベントで送受信する最終結果 */
export type GameResultPayload = {
rankings: GameResultRanking[];
};
-/**
- * 初期同期(CURRENT_PLAYERS)で利用するプレイヤー一覧
- * 初期同期用のため teamId を含む完全な PlayerData を配信する
- */
-export type InitialPlayerSyncPayload = PlayerData[];
+/** current-players で配信するプレイヤー全体スナップショット */
+export type PlayerSnapshotPayload = PlayerData[];
/**
- * 差分同期(UPDATE_PLAYERS)で利用するプレイヤー差分配列
+ * update-players で配信するプレイヤー差分配列
* 帯域最適化のため teamId は含めず,id/x/y のみを配信する
*/
-export type DeltaPlayerSyncPayload = PlayerPositionUpdate[];
+export type PlayerDeltaPayload = PlayerPositionUpdate[];
-/** UPDATE_PLAYERS イベントで送受信するプレイヤー差分配列 */
-export type UpdatePlayersPayload = DeltaPlayerSyncPayload;
+/**
+ * 初期同期(current-players)で利用するプレイヤー一覧
+ * 初期同期用のため teamId を含む完全な PlayerData を配信する
+ */
+export type InitialPlayerSyncPayload = PlayerSnapshotPayload;
-/** CURRENT_PLAYERS イベントで送受信するプレイヤー一覧 */
-export type CurrentPlayersPayload = InitialPlayerSyncPayload;
+/**
+ * 差分同期(update-players)で利用するプレイヤー差分配列
+ * 帯域最適化のため teamId は含めず,id/x/y のみを配信する
+ */
+export type DeltaPlayerSyncPayload = PlayerDeltaPayload;
-/** UPDATE_MAP_CELLS イベントで送受信するマップ差分配列 */
+/** update-players イベントで送受信するプレイヤー差分配列 */
+export type UpdatePlayersPayload = PlayerDeltaPayload;
+
+/** current-players イベントで送受信するプレイヤー一覧 */
+export type CurrentPlayersPayload = PlayerSnapshotPayload;
+
+/** update-map-cells イベントで送受信するマップ差分配列 */
export type UpdateMapCellsPayload = CellUpdate[];
/**
- * NEW_PLAYER イベントで送受信するプレイヤー情報
+ * new-player イベントで送受信するプレイヤー情報
* 初回参加通知のため teamId を含む完全な PlayerData を配信する
*/
export type NewPlayerPayload = PlayerData;
-/** REMOVE_PLAYER イベントで送受信するプレイヤーID */
+/** remove-player イベントで送受信するプレイヤーID */
export type RemovePlayerPayload = PlayerData["id"];
-/** GAME_START イベントで送受信するゲーム開始情報 */
+/** game-start イベントで送受信するゲーム開始情報 */
export type GameStartPayload = { startTime: number };
-/** START_GAME イベントで受信するゲーム開始要求 */
+/** start-game イベントで受信するゲーム開始要求 */
export type StartGameRequestPayload = {
targetPlayerCount?: number;
};
-/** MOVE イベントで送受信する移動入力情報 */
+/** move イベントで送受信する移動入力情報 */
export type MovePayload = PlayerMovePayload;
-/** PLACE_BOMB イベントで送受信する爆弾設置要求 */
+/** place-bomb イベントで送受信する爆弾設置要求 */
export type PlaceBombPayload = {
requestId: string;
x: number;
@@ -72,7 +81,7 @@
explodeAtElapsedMs: number;
};
-/** BOMB_PLACED イベントで送受信する他プレイヤー向け爆弾確定情報,設置者識別は ownerSocketId で扱う */
+/** bomb-placed イベントで送受信する他プレイヤー向け爆弾確定情報,設置者識別は ownerSocketId で扱う */
export type BombPlacedPayload = {
bombId: string;
ownerSocketId: string;
@@ -81,18 +90,18 @@
explodeAtElapsedMs: number;
};
-/** BOMB_PLACED_ACK イベントで送受信する設置者向け確定情報 */
+/** bomb-placed-ack イベントで送受信する設置者向け確定情報 */
export type BombPlacedAckPayload = {
bombId: string;
requestId: string;
};
-/** BOMB_HIT_REPORT イベントで送受信する被弾報告 */
+/** bomb-hit-report イベントで送受信する被弾報告 */
export type BombHitReportPayload = {
bombId: string;
};
-/** PLAYER_DEAD イベントで送受信する死亡プレイヤー情報 */
+/** player-dead イベントで送受信する死亡プレイヤー情報 */
export type PlayerDeadPayload = {
playerId: string;
};
diff --git a/packages/shared/src/protocol/socketEventBridge.ts b/packages/shared/src/protocol/socketEventBridge.ts
index a5f61e2..8055445 100644
--- a/packages/shared/src/protocol/socketEventBridge.ts
+++ b/packages/shared/src/protocol/socketEventBridge.ts
@@ -8,10 +8,13 @@
/** ソケットブリッジ生成に必要な最小インターフェース */
export type SocketBridgeTarget = {
- on: (event: string, callback: (payload: unknown) => void) => void;
- once: (event: string, callback: (payload: unknown) => void) => void;
- off: (event: string, callback: (payload: unknown) => void) => void;
- emit: (event: string, payload?: unknown) => void;
+ on: (event: string, callback: (payload: TPayload) => void) => void;
+ once: (event: string, callback: (payload: TPayload) => void) => void;
+ off: (event: string, callback: (payload: TPayload) => void) => void;
+ emit: {
+ (event: string): void;
+ (event: string, payload: TPayload): void;
+ };
};
/**
@@ -25,21 +28,21 @@
event: TEvent,
callback: (payload: TInboundMap[TEvent]) => void
) => {
- socket.on(event, callback as (payload: unknown) => void);
+ socket.on(event, callback);
};
const onceEvent = >(
event: TEvent,
callback: (payload: TInboundMap[TEvent]) => void
) => {
- socket.once(event, callback as (payload: unknown) => void);
+ socket.once(event, callback);
};
const offEvent = >(
event: TEvent,
callback: (payload: TInboundMap[TEvent]) => void
) => {
- socket.off(event, callback as (payload: unknown) => void);
+ socket.off(event, callback);
};
function emitEvent>(event: TEvent): void;
@@ -50,7 +53,7 @@
return;
}
- socket.emit(event, payload as unknown);
+ socket.emit(event, payload);
}
return {
diff --git a/packages/shared/src/protocol/socketEvents.ts b/packages/shared/src/protocol/socketEvents.ts
index f2c9a50..f896567 100644
--- a/packages/shared/src/protocol/socketEvents.ts
+++ b/packages/shared/src/protocol/socketEvents.ts
@@ -19,14 +19,21 @@
READY_FOR_GAME: "ready-for-game",
// ゲームプレイ関連イベント名
- CURRENT_PLAYERS: "current_players",
- NEW_PLAYER: "new_player",
- UPDATE_PLAYERS: "update_players",
- REMOVE_PLAYER: "remove_player",
+ CURRENT_PLAYERS_SYNC: "current-players",
+ NEW_PLAYER_SYNC: "new-player",
+ UPDATE_PLAYERS_SYNC: "update-players",
+ REMOVE_PLAYER_SYNC: "remove-player",
+ UPDATE_MAP_CELLS_SYNC: "update-map-cells",
+
+ // 互換維持のため残す旧キー名
+ CURRENT_PLAYERS: "current-players",
+ NEW_PLAYER: "new-player",
+ UPDATE_PLAYERS: "update-players",
+ REMOVE_PLAYER: "remove-player",
MOVE: "move",
PLACE_BOMB: "place-bomb",
BOMB_HIT_REPORT: "bomb-hit-report",
- UPDATE_MAP_CELLS: "update_map_cells",
+ UPDATE_MAP_CELLS: "update-map-cells",
BOMB_PLACED: "bomb-placed",
BOMB_PLACED_ACK: "bomb-placed-ack",
PLAYER_DEAD: "player-dead",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 37621b8..aecee8f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -90,6 +90,12 @@
packages/shared:
devDependencies:
+ '@typescript-eslint/parser':
+ specifier: ^8.56.1
+ version: 8.56.1(eslint@10.0.2)(typescript@5.9.3)
+ eslint:
+ specifier: ^10.0.2
+ version: 10.0.2
tsup:
specifier: ^8.5.1
version: 8.5.1(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)
diff --git a/test/load-bot.ts b/test/load-bot.ts
index df8930e..c66661f 100644
--- a/test/load-bot.ts
+++ b/test/load-bot.ts
@@ -233,7 +233,7 @@
}
});
- socket.on("current_players", (players: CurrentPlayer[]) => {
+ socket.on("current-players", (players: CurrentPlayer[]) => {
const self = players.find((player) => player.id === socket.id);
if (self) {
posX = self.x;