feat(ws): 添加WebSocket客户端及房间状态处理功能
- 实现WebSocket客户端类,支持连接、发送消息、状态监听和自动重连 - 添加房间信息和状态的消息处理器,用于同步游戏状态和玩家数据 - 实现房间快照解析功能,处理玩家信息、游戏阶段、计时器等数据结构 - 集成会话状态适配器,管理房间倒计时、结算截止时间等状态变更 - 添加单例WebSocket客户端实例,统一管理WebSocket连接生命周期
This commit is contained in:
@@ -3,9 +3,11 @@ import { parseRoomInfoSnapshot } from '../parsers/roomInfoSnapshot'
|
||||
import { clearRoomAndRedirect, syncActiveRoomFromRoomInfo } from '../room/roomSnapshotSync'
|
||||
import {
|
||||
clearClaimAndTurnPending,
|
||||
clearRoomCountdown,
|
||||
clearDingQuePending,
|
||||
clearSelfTurnAllowActions,
|
||||
clearTurnPending,
|
||||
setRoomCountdown,
|
||||
setSettlementDeadline,
|
||||
syncCurrentUserId,
|
||||
} from '../session/sessionStateAdapter'
|
||||
@@ -69,6 +71,11 @@ export function createRoomInfoHandlers(context: SocketHandlerContext) {
|
||||
} else {
|
||||
clearTurnPending(context.session)
|
||||
}
|
||||
if (snapshot.actionTimer) {
|
||||
setRoomCountdown(context.session, snapshot.actionTimer)
|
||||
} else {
|
||||
clearRoomCountdown(context.session)
|
||||
}
|
||||
if (typeof snapshot.settlementDeadlineMs === 'number' && snapshot.settlementDeadlineMs > 0) {
|
||||
setSettlementDeadline(context.session, snapshot.settlementDeadlineMs)
|
||||
}
|
||||
|
||||
@@ -8,11 +8,13 @@ import { parseRoomStateSnapshot } from '../parsers/roomStateSnapshot'
|
||||
import { syncActiveRoomFromRoomState } from '../room/roomSnapshotSync'
|
||||
import {
|
||||
clearClaimAndTurnPending,
|
||||
clearRoomCountdown,
|
||||
clearSelfTurnAllowActions,
|
||||
clearStartGamePending,
|
||||
clearTurnPending,
|
||||
completeDiscard,
|
||||
resetSettlementOverlayState,
|
||||
setRoomCountdown,
|
||||
setSettlementDeadline,
|
||||
} from '../session/sessionStateAdapter'
|
||||
import { applyRoomSnapshot } from '../store/gameStoreAdapter'
|
||||
@@ -61,6 +63,11 @@ export function createRoomStateHandlers(context: SocketHandlerContext) {
|
||||
} else if (snapshot.phase !== 'settlement') {
|
||||
setSettlementDeadline(context.session, null)
|
||||
}
|
||||
if (snapshot.actionTimer) {
|
||||
setRoomCountdown(context.session, snapshot.actionTimer)
|
||||
} else {
|
||||
clearRoomCountdown(context.session)
|
||||
}
|
||||
|
||||
if (!snapshot.pendingClaim) {
|
||||
clearClaimAndTurnPending(context.session)
|
||||
|
||||
27
src/views/chengdu/socket/parsers/actionTimerSnapshot.ts
Normal file
27
src/views/chengdu/socket/parsers/actionTimerSnapshot.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { asRecord, readNumber, readString, readStringArray } from '../../../../game/chengdu/messageNormalizers'
|
||||
import type { PlayerActionTimer } from '../../types'
|
||||
|
||||
export function parseActionTimerSnapshot(source: unknown): PlayerActionTimer | null {
|
||||
const timer = asRecord(source)
|
||||
if (!timer) {
|
||||
return null
|
||||
}
|
||||
|
||||
const playerIds = readStringArray(timer, 'player_ids', 'playerIds', 'PlayerIDs')
|
||||
const countdownSeconds = readNumber(timer, 'countdown_seconds', 'countdownSeconds', 'CountdownSeconds') ?? 0
|
||||
const duration = readNumber(timer, 'duration', 'Duration') ?? countdownSeconds
|
||||
const remaining = readNumber(timer, 'remaining', 'Remaining') ?? countdownSeconds
|
||||
const actionDeadlineAt = readString(timer, 'action_deadline_at', 'actionDeadlineAt', 'ActionDeadlineAt') || null
|
||||
|
||||
if (playerIds.length === 0 && countdownSeconds <= 0 && remaining <= 0 && !actionDeadlineAt) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
playerIds,
|
||||
actionDeadlineAt,
|
||||
countdownSeconds,
|
||||
duration,
|
||||
remaining,
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
} from '../../../../game/chengdu/messageNormalizers'
|
||||
import type { RoomMetaSnapshotState } from '../../../../store/state'
|
||||
import type { PendingClaimState, PlayerState } from '../../../../types/state'
|
||||
import type { PlayerActionTimer } from '../../types'
|
||||
import { parseActionTimerSnapshot } from './actionTimerSnapshot'
|
||||
|
||||
interface RoomInfoSnapshotPlayerPair {
|
||||
roomPlayer: RoomMetaSnapshotState['players'][number]
|
||||
@@ -39,6 +41,7 @@ export interface ParsedRoomInfoSnapshot {
|
||||
currentRound: number | null
|
||||
totalRounds: number | null
|
||||
settlementDeadlineMs: number | null
|
||||
actionTimer: PlayerActionTimer | null
|
||||
}
|
||||
|
||||
interface ParseRoomInfoSnapshotOptions {
|
||||
@@ -273,5 +276,6 @@ export function parseRoomInfoSnapshot(
|
||||
currentRound: readNumber(gameState ?? {}, 'current_round', 'currentRound'),
|
||||
totalRounds: readNumber(gameState ?? {}, 'total_rounds', 'totalRounds'),
|
||||
settlementDeadlineMs: readNumber(gameState ?? {}, 'settlement_deadline_ms', 'settlementDeadlineMs'),
|
||||
actionTimer: parseActionTimerSnapshot(gameState?.action_timer ?? gameState?.actionTimer),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import {
|
||||
readStringArray,
|
||||
} from '../../../../game/chengdu/messageNormalizers'
|
||||
import type { PendingClaimState, PlayerState } from '../../../../types/state'
|
||||
import type { PlayerActionTimer } from '../../types'
|
||||
import { parseActionTimerSnapshot } from './actionTimerSnapshot'
|
||||
|
||||
export interface ParsedRoomStateSnapshot {
|
||||
roomId: string
|
||||
@@ -25,6 +27,7 @@ export interface ParsedRoomStateSnapshot {
|
||||
currentRound: number | null
|
||||
totalRounds: number | null
|
||||
settlementDeadlineMs: number | null
|
||||
actionTimer: PlayerActionTimer | null
|
||||
}
|
||||
|
||||
interface ParseRoomStateSnapshotOptions {
|
||||
@@ -108,5 +111,6 @@ export function parseRoomStateSnapshot(
|
||||
currentRound: readNumber(payload, 'current_round', 'currentRound'),
|
||||
totalRounds: readNumber(payload, 'total_rounds', 'totalRounds'),
|
||||
settlementDeadlineMs: readNumber(payload, 'settlement_deadline_ms', 'settlementDeadlineMs'),
|
||||
actionTimer: parseActionTimerSnapshot(payload.action_timer ?? payload.actionTimer),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,7 @@ class WsClient {
|
||||
// 订阅状态变化
|
||||
onStatusChange(handler: StatusHandler) {
|
||||
this.statusHandlers.push(handler)
|
||||
handler(this.status)
|
||||
return () => {
|
||||
this.statusHandlers = this.statusHandlers.filter(fn => fn !== handler)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user