import { _decorator, Component, Node } from 'cc'; import type { PlayerState } from '../framework/platform/stores/types.ts'; import { applyPlayerCount, applyPlayerData, applySeatLayoutPositions, clearSlots, computeActiveFlags, computePositions, type PlayerSlotLike, type SeatLayout, validateCount, validateLayout, validateSeat, } from './room-scene-controller.ts'; export { applyPlayerCount, applyPlayerData, applySeatLayoutPositions, clearSlots, computeActiveFlags, computePositions, validateCount, validateLayout, validateSeat, type PlayerSlotLike, }; export type { SeatLayout }; const { ccclass, property } = _decorator; /** * RoomSceneStart: 房间场景控制脚本。 * * 工作流: * 1. 子游戏初始化 → setPlayerCount(n) + setSeatLayout(layout) 调整可见槽位与位置 * 2. 子游戏收到玩家状态变更 → setPlayerData(seat, data) 注入到对应槽位的 PlayerInfoView * 3. 子游戏重置房间 → clearSeats() 把当前可见槽位刷成占位数据 * * 8 个 playerSlots 在场景里预先挂好(Plan Task 2 负责),setPlayerCount 只切 active, * 不运行时 instantiate 节点(避免预制重复实例化开销)。 * * 纯逻辑(校验 + 槽位操作 + 视图交互)放在 room-scene-controller.ts(同目录), * 本文件只 re-export 并做 cc 包装 — 这样单元测试可以直接 import 控制器函数 * 而无需 mock cc 模块(CLAUDE.md 第二准则:RoomSceneStart 的下游消费者不应被 cc 依赖拖累)。 */ @ccclass('RoomSceneStart') export class RoomSceneStart extends Component { @property([Node]) playerSlots: Node[] = []; private currentCount: number = 4; private currentLayout: SeatLayout = 'horizontal'; start(): void { if (!this.playerSlots || this.playerSlots.length !== 8) { throw new Error( `[RoomSceneStart] playerSlots must have 8 entries, got ${this.playerSlots?.length}`, ); } // 校验 playerSlots 内是否有 null/undefined;start 时显式 throw,不兜底。 for (let i = 0; i < this.playerSlots.length; i++) { if (!this.playerSlots[i]) { throw new Error(`[RoomSceneStart] playerSlots[${i}] is null/undefined`); } } this.setPlayerCount(this.currentCount); this.setSeatLayout(this.currentLayout); } public setPlayerCount(n: number): void { validateCount(n); this.currentCount = n; applyPlayerCount(this.playerSlots as unknown as PlayerSlotLike[], n); } public setSeatLayout(layout: SeatLayout): void { validateLayout(layout); this.currentLayout = layout; applySeatLayoutPositions( this.playerSlots as unknown as PlayerSlotLike[], layout, this.currentCount, ); } public setPlayerData(seat: number, data: PlayerState): void { applyPlayerData( this.playerSlots as unknown as PlayerSlotLike[], seat, this.currentCount, data as unknown as { nickname?: unknown; bean?: unknown; avatar?: unknown }, ); } public clearSeats(): void { clearSlots(this.playerSlots as unknown as PlayerSlotLike[], this.currentCount); } }