Skip to content

WebSocket 协议

TuringHunt 前端通过单条 WebSocket 连接与后端实时通信。所有消息均为 JSON 格式。

连接地址

环境地址
优先读取环境变量NEXT_PUBLIC_WS_URL
未配置时自动推断ws(s)://{hostname}/ws/game

消息格式

所有消息均遵循:

json
{ "type": "消息类型", "data": { /* 载荷 */ } }

data 字段对于无载荷消息为 null


服务端 → 客户端消息

GAME_STATE

完整游戏快照,通常在玩家首次连接或重连时发送。

ts
interface GameStateData {
  players: Player[];
  player_count: number;
  phase: Phase;
  leader_id: string | null;
  required_team_size: number;
  mission_number: number;
  current_team: string[];
  is_speaker: boolean;
  current_speaker_id: string | null;
  needs_vote: boolean;
  input_locked: boolean;
}

ROLE_ASSIGNED

游戏开始时告知本玩家的角色及其可见的其他玩家身份。

ts
interface RoleAssignedData {
  role: Role;
  visible_others: Record<string, string>; // user_id → role
}

PHASE_CHANGED

阶段切换通知,前端据此更新 phase 并重置阶段相关状态。

ts
interface PhaseChangedData {
  phase: Phase;
  leader_id: string | null;
  required_team_size: number;
  mission_number: number;
  current_speaker_id?: string | null;
}

REQUEST_INPUT

服务端请求玩家进行特定输入,前端据此解锁对应 UI。

ts
interface RequestInputData {
  input_type: "SPEECH" | "SUBMIT_TEAM" | "VOTE" | "ASSASSIN_CHOOSE";
  phase: Phase;
  mission_number: number;
}

INPUT_LOCKED / INPUT_UNLOCKED

直接控制所有交互元素的禁用状态,datanull

TEAM_PROPOSED

领袖提交队伍后广播给所有人。

ts
interface TeamProposedData {
  leader_id: string;
  team: string[];
  mission_number: number;
}

TEAM_VOTE_RESULT

所有人投票完成后广播结果。

ts
interface TeamVoteResultData {
  votes: Record<string, boolean>;  // user_id → 是否赞成
  approved: boolean;
  consecutive_vote_failures: number;
  mission_number: number;
}

MISSION_RESULT

任务执行完毕后广播结果(不公开投票人)。

ts
interface MissionResultData {
  mission_number: number;
  success: boolean;
  fail_votes: number;
  success_votes: number;
  good_wins: number;
  evil_wins: number;
}

SPEECH_ADDED

某位玩家发言后实时广播,同时告知下一位发言者。

ts
interface SpeechAddedData {
  player_id: string;
  content: string;
  next_speaker_id: string | null;
}

SPEECH_HISTORY

发言阶段结束后广播本轮完整发言记录(用于后续阶段的侧边栏展示)。

ts
interface SpeechHistoryData {
  speeches: Array<{ player_id: string; username: string; content: string }>;
}

GAME_OVER

游戏结束,公开所有人身份。

ts
interface GameOverData {
  winner: "good" | "evil";
  reason: "good_missions" | "evil_missions" | "vote_failures" | "assassin_success";
  role_reveal: Record<string, string>; // user_id → role
}

ERROR

服务端返回错误(如非法操作),前端通过 Toast 展示。

ts
interface ErrorData { error: string }

客户端 → 服务端消息

typedata说明
START_GAMEnull开始游戏
SPEECH{ content: string }提交发言内容
END_SPEECHnull结束本人发言
SUBMIT_TEAM{ team: string[] }领袖提交任务队伍
VOTE{ vote: boolean }投票(队伍或任务)
ASSASSIN_CHOOSE{ target_id: string }刺客指定目标

重连机制

useWebSocket 实现指数退避自动重连:

  • 最大重试次数:5
  • 重试延迟:2^n 秒(n = 重试次数)
  • 关闭码 4001(鉴权失败):不重试,触发 WS_AUTH_ERROR
ts
const delay = Math.pow(2, retriesRef.current) * 1000;
retriesRef.current += 1;
setTimeout(connect, delay);

TuringHunt Frontend