feat(game): 添加成都麻将游戏页面和大厅功能
- 实现 ChengduGamePage.vue 组件,包含完整的麻将游戏界面 - 实现 HallPage.vue 组件,支持房间列表展示、创建和加入功能 - 添加 mahjong API 接口用于房间管理操作 - 集成 store 状态管理和本地存储功能 - 实现 ChengduBottomActions 等游戏控制组件 - 添加 websocket 连接和游戏会话管理逻辑 - 实现游戏倒计时、结算等功能模块
This commit is contained in:
170
src/views/chengdu/socket/handlers/playerHandlers.ts
Normal file
170
src/views/chengdu/socket/handlers/playerHandlers.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import {
|
||||
asRecord,
|
||||
normalizeTiles,
|
||||
normalizeWsType,
|
||||
readBoolean,
|
||||
readString,
|
||||
} from '../../../../game/chengdu/messageNormalizers'
|
||||
import type { RoomPlayerUpdatePayload, RoomTrusteePayload } from '../../../../game/actions'
|
||||
import {
|
||||
clearDingQuePending,
|
||||
clearReadyTogglePending,
|
||||
clearStartGamePending,
|
||||
clearTurnPending,
|
||||
completeDiscard,
|
||||
setTrustMode,
|
||||
syncCurrentUserId,
|
||||
} from '../session/sessionStateAdapter'
|
||||
import { setPlayerHandState, setPlayerMissingSuit, setPlayerReadyState, setPlayerTrusteeState } from '../store/gameStoreAdapter'
|
||||
import type { PlayerHandlerApi, SocketHandlerContext } from '../types'
|
||||
|
||||
export function createPlayerHandlers(context: SocketHandlerContext): PlayerHandlerApi {
|
||||
function applyPlayerReadyState(playerId: string, ready: boolean): void {
|
||||
setPlayerReadyState(context.gameStore, playerId, ready)
|
||||
}
|
||||
|
||||
function syncReadyStatesFromRoomUpdate(payload: RoomPlayerUpdatePayload): void {
|
||||
if (!Array.isArray(payload.players)) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const item of payload.players) {
|
||||
const playerId =
|
||||
(typeof item.PlayerID === 'string' && item.PlayerID) ||
|
||||
(typeof item.player_id === 'string' && item.player_id) ||
|
||||
''
|
||||
const ready =
|
||||
typeof item.Ready === 'boolean'
|
||||
? item.Ready
|
||||
: typeof item.ready === 'boolean'
|
||||
? item.ready
|
||||
: typeof item.is_ready === 'boolean'
|
||||
? item.is_ready
|
||||
: undefined
|
||||
|
||||
if (!playerId || typeof ready !== 'boolean') {
|
||||
continue
|
||||
}
|
||||
|
||||
applyPlayerReadyState(playerId, ready)
|
||||
}
|
||||
}
|
||||
|
||||
function handlePlayerHandResponse(message: unknown): void {
|
||||
const source = asRecord(message)
|
||||
if (!source || typeof source.type !== 'string' || normalizeWsType(source.type) !== 'PLAYER_HAND') {
|
||||
return
|
||||
}
|
||||
|
||||
const payload = asRecord(source.payload)
|
||||
if (!payload) {
|
||||
return
|
||||
}
|
||||
|
||||
syncCurrentUserId(context.session, readString(source, 'target'))
|
||||
const roomId = readString(payload, 'room_id', 'roomId') || readString(source, 'roomId')
|
||||
if (roomId && context.gameStore.roomId && roomId !== context.gameStore.roomId) {
|
||||
return
|
||||
}
|
||||
|
||||
const handTiles = normalizeTiles(payload.hand)
|
||||
if (!context.session.loggedInUserId.value || handTiles.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
clearTurnPending(context.session)
|
||||
setPlayerHandState(context.gameStore, context.session.loggedInUserId.value, handTiles)
|
||||
clearDingQuePending(context.session)
|
||||
|
||||
completeDiscard(context.session)
|
||||
if (context.gameStore.phase !== 'waiting') {
|
||||
clearStartGamePending(context.session)
|
||||
}
|
||||
}
|
||||
|
||||
function syncTrusteeState(payload: RoomTrusteePayload): void {
|
||||
const playerId =
|
||||
(typeof payload.player_id === 'string' && payload.player_id) ||
|
||||
(typeof payload.playerId === 'string' && payload.playerId) ||
|
||||
''
|
||||
if (!playerId) {
|
||||
return
|
||||
}
|
||||
|
||||
const trustee = typeof payload.trustee === 'boolean' ? payload.trustee : true
|
||||
setPlayerTrusteeState(context.gameStore, playerId, trustee)
|
||||
if (playerId === context.session.loggedInUserId.value) {
|
||||
setTrustMode(context.session, trustee)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function handleReadyStateResponse(message: unknown): void {
|
||||
const source = asRecord(message)
|
||||
if (!source || typeof source.type !== 'string' || normalizeWsType(source.type) !== 'PLAYER_READY') {
|
||||
return
|
||||
}
|
||||
|
||||
const payload = asRecord(source.payload)
|
||||
if (!payload) {
|
||||
return
|
||||
}
|
||||
|
||||
const roomId = typeof payload.room_id === 'string' ? payload.room_id : readString(source, 'roomId')
|
||||
const userId =
|
||||
(typeof payload.player_id === 'string' && payload.player_id) ||
|
||||
(typeof payload.user_id === 'string' && payload.user_id) ||
|
||||
readString(source, 'target')
|
||||
const ready = readBoolean(payload, 'is_ready', 'ready', 'Ready')
|
||||
|
||||
if (roomId && roomId !== context.gameStore.roomId) {
|
||||
return
|
||||
}
|
||||
|
||||
if (ready !== null && userId) {
|
||||
applyPlayerReadyState(userId, ready)
|
||||
}
|
||||
if (userId && userId === context.session.loggedInUserId.value) {
|
||||
clearReadyTogglePending(context.session)
|
||||
}
|
||||
}
|
||||
|
||||
function handlePlayerDingQueResponse(message: unknown): void {
|
||||
const source = asRecord(message)
|
||||
if (!source || typeof source.type !== 'string' || normalizeWsType(source.type) !== 'PLAYER_DING_QUE') {
|
||||
return
|
||||
}
|
||||
|
||||
const payload = asRecord(source.payload)
|
||||
if (!payload) {
|
||||
return
|
||||
}
|
||||
|
||||
const roomId = readString(payload, 'room_id', 'roomId') || readString(source, 'roomId')
|
||||
if (roomId && roomId !== context.gameStore.roomId) {
|
||||
return
|
||||
}
|
||||
|
||||
const userId =
|
||||
readString(payload, 'user_id', 'userId', 'player_id', 'playerId') || readString(source, 'target')
|
||||
const suit = readString(payload, 'suit', 'Suit')
|
||||
if (!userId || !suit) {
|
||||
return
|
||||
}
|
||||
|
||||
setPlayerMissingSuit(context.gameStore, userId, suit)
|
||||
|
||||
if (userId === context.session.loggedInUserId.value) {
|
||||
clearDingQuePending(context.session)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
applyPlayerReadyState,
|
||||
syncReadyStatesFromRoomUpdate,
|
||||
handlePlayerHandResponse,
|
||||
handleReadyStateResponse,
|
||||
handlePlayerDingQueResponse,
|
||||
syncTrusteeState,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user