/**
* GameNetworkSync
* ソケットイベントとゲーム内状態更新の同期を担う
* プレイヤー生成更新削除とマップ更新購読を管理する
*/
import { Container } from "pixi.js";
import type {
BombPlacedAckPayload,
BombPlacedPayload,
PlayerDeadPayload,
} from "@repo/shared";
import { AppearanceResolver } from "./AppearanceResolver";
import { GameMapController } from "@client/scenes/game/entities/map/GameMapController";
import { PlayerRepository } from "@client/scenes/game/entities/player/PlayerRepository";
import { GameNetworkEventReceiver } from "./network/receivers/GameNetworkEventReceiver";
import { GameNetworkStateApplier } from "./network/handlers/GameNetworkStateApplier";
import type { GamePlayers } from "./game.types";
const ENABLE_DEBUG_LOG = import.meta.env.DEV;
type GameNetworkSyncOptions = {
worldContainer: Container;
players: GamePlayers;
myId: string;
gameMap: GameMapController;
appearanceResolver: AppearanceResolver;
onGameStarted: (startTime: number) => void;
onGameEnded: () => void;
onRemoteBombPlaced: (payload: BombPlacedPayload) => void;
onBombPlacementAcknowledged: (payload: BombPlacedAckPayload) => void;
onRemotePlayerDead: (payload: PlayerDeadPayload) => void;
};
/** ゲーム中のネットワークイベント購読と同期処理を管理する */
export class GameNetworkSync {
private readonly eventReceiver: GameNetworkEventReceiver;
private readonly stateApplier: GameNetworkStateApplier;
private debugLog = (message: string) => {
if (!ENABLE_DEBUG_LOG) {
return;
}
console.log(message);
};
constructor({
worldContainer,
players,
myId,
gameMap,
appearanceResolver,
onGameStarted,
onGameEnded,
onRemoteBombPlaced,
onBombPlacementAcknowledged,
onRemotePlayerDead,
}: GameNetworkSyncOptions) {
const playerRepository = new PlayerRepository(players);
this.stateApplier = new GameNetworkStateApplier({
worldContainer,
playerRepository,
myId,
gameMap,
appearanceResolver,
onGameStarted,
onGameEnded,
onRemoteBombPlaced,
onBombPlacementAcknowledged,
onRemotePlayerDead,
onDebugLog: this.debugLog,
});
this.eventReceiver = new GameNetworkEventReceiver({
onReceivedCurrentPlayers: this.stateApplier.applyReceivedCurrentPlayers.bind(this.stateApplier),
onReceivedNewPlayer: this.stateApplier.applyReceivedNewPlayer.bind(this.stateApplier),
onReceivedGameStart: this.stateApplier.applyReceivedGameStart.bind(this.stateApplier),
onReceivedUpdatePlayers: this.stateApplier.applyReceivedUpdatePlayers.bind(this.stateApplier),
onReceivedRemovePlayer: this.stateApplier.applyReceivedRemovePlayer.bind(this.stateApplier),
onReceivedUpdateMapCells: this.stateApplier.applyReceivedUpdateMapCells.bind(this.stateApplier),
onReceivedGameEnd: this.stateApplier.applyReceivedGameEnd.bind(this.stateApplier),
onReceivedBombPlaced: this.stateApplier.applyReceivedBombPlaced.bind(this.stateApplier),
onReceivedBombPlacedAck: this.stateApplier.applyReceivedBombPlacedAck.bind(this.stateApplier),
onReceivedPlayerDead: this.stateApplier.applyReceivedPlayerDead.bind(this.stateApplier),
});
}
public bind() {
this.eventReceiver.bind();
}
public unbind() {
this.eventReceiver.unbind();
}
}