feat(game): 添加房间玩家状态同步功能
- 定义 RoomPlayerUpdatePayload 接口用于处理房间状态更新 - 在游戏动作中新增 ROOM_PLAYER_UPDATE 类型支持 - 实现游戏状态管理器中的房间玩家更新逻辑 - 重构成都麻将页面以使用新的状态管理机制 - 添加从 WebSocket 消息转换为游戏动作的功能 - 更新房间离开时的 WebSocket 消息发送逻辑 - 优化玩家手牌显示和选择逻辑 - 调整房间状态显示逻辑以匹配新状态模型 - 修复座位索引计算和庄家标识逻辑 - 更新全局样式中的图标按钮样式 - 替换大厅页面的刷新图标为 SVG 图像 - 升级 pnpm 包管理器版本 - 扩展玩家状态类型定义以支持显示名称和缺门信息
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
||||
type GameState,
|
||||
type PendingClaimState,
|
||||
} from '../types/state'
|
||||
import type { RoomPlayerUpdatePayload } from '../game/actions'
|
||||
|
||||
import type { Tile } from '../types/tile'
|
||||
|
||||
@@ -91,6 +92,94 @@ export const useGameStore = defineStore('game', {
|
||||
this.phase = GAME_PHASE.ACTION
|
||||
},
|
||||
|
||||
onRoomPlayerUpdate(payload: RoomPlayerUpdatePayload) {
|
||||
if (typeof payload.room_id === 'string' && payload.room_id) {
|
||||
this.roomId = payload.room_id
|
||||
}
|
||||
|
||||
if (typeof payload.status === 'string' && payload.status) {
|
||||
const phaseMap: Record<string, GameState['phase']> = {
|
||||
waiting: GAME_PHASE.WAITING,
|
||||
dealing: GAME_PHASE.DEALING,
|
||||
playing: GAME_PHASE.PLAYING,
|
||||
action: GAME_PHASE.ACTION,
|
||||
settlement: GAME_PHASE.SETTLEMENT,
|
||||
}
|
||||
this.phase = phaseMap[payload.status] ?? this.phase
|
||||
}
|
||||
|
||||
const hasPlayerList =
|
||||
Array.isArray(payload.players) || Array.isArray(payload.player_ids)
|
||||
if (!hasPlayerList) {
|
||||
return
|
||||
}
|
||||
|
||||
const nextPlayers: GameState['players'] = {}
|
||||
const players = Array.isArray(payload.players) ? payload.players : []
|
||||
const playerIds = Array.isArray(payload.player_ids) ? payload.player_ids : []
|
||||
|
||||
players.forEach((raw, index) => {
|
||||
const playerId =
|
||||
(typeof raw.PlayerID === 'string' && raw.PlayerID) ||
|
||||
(typeof raw.player_id === 'string' && raw.player_id) ||
|
||||
playerIds[index]
|
||||
if (!playerId) {
|
||||
return
|
||||
}
|
||||
|
||||
const previous = this.players[playerId]
|
||||
const seatRaw = raw.Index ?? raw.index ?? index
|
||||
const seatIndex =
|
||||
typeof seatRaw === 'number' && Number.isFinite(seatRaw) ? seatRaw : index
|
||||
const readyRaw = raw.Ready ?? raw.ready
|
||||
const displayNameRaw = raw.PlayerName ?? raw.player_name
|
||||
const missingSuitRaw = raw.MissingSuit ?? raw.missing_suit
|
||||
|
||||
nextPlayers[playerId] = {
|
||||
playerId,
|
||||
seatIndex,
|
||||
displayName:
|
||||
typeof displayNameRaw === 'string' && displayNameRaw
|
||||
? displayNameRaw
|
||||
: previous?.displayName,
|
||||
missingSuit:
|
||||
typeof missingSuitRaw === 'string' || missingSuitRaw === null
|
||||
? missingSuitRaw
|
||||
: previous?.missingSuit,
|
||||
handTiles: previous?.handTiles ?? [],
|
||||
melds: previous?.melds ?? [],
|
||||
discardTiles: previous?.discardTiles ?? [],
|
||||
score: previous?.score ?? 0,
|
||||
isReady:
|
||||
typeof readyRaw === 'boolean'
|
||||
? readyRaw
|
||||
: (previous?.isReady ?? false),
|
||||
}
|
||||
})
|
||||
|
||||
if (players.length === 0) {
|
||||
playerIds.forEach((playerId, index) => {
|
||||
if (typeof playerId !== 'string' || !playerId) {
|
||||
return
|
||||
}
|
||||
const previous = this.players[playerId]
|
||||
nextPlayers[playerId] = {
|
||||
playerId,
|
||||
seatIndex: previous?.seatIndex ?? index,
|
||||
displayName: previous?.displayName ?? playerId,
|
||||
missingSuit: previous?.missingSuit,
|
||||
handTiles: previous?.handTiles ?? [],
|
||||
melds: previous?.melds ?? [],
|
||||
discardTiles: previous?.discardTiles ?? [],
|
||||
score: previous?.score ?? 0,
|
||||
isReady: previous?.isReady ?? false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.players = nextPlayers
|
||||
},
|
||||
|
||||
// 清理操作窗口
|
||||
clearPendingClaim() {
|
||||
this.pendingClaim = undefined
|
||||
@@ -102,4 +191,4 @@ export const useGameStore = defineStore('game', {
|
||||
return Object.keys(this.players)[0] || ''
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user