支持多人数对局与 AI 补位:玩法声明人数范围、匹配分队列与超时补 AI、房间玩家名册

This commit is contained in:
2026-09-28 00:41:28 +08:00
parent fb5a730ef3
commit adb31eec68
17 changed files with 854 additions and 367 deletions
+31 -17
View File
@@ -1,12 +1,23 @@
package dto // 包名声明:与 user.go 同属 dto 包,集中放置对外数据结构
package dto // 包名声明:与 user.go 同属 dto 包
import "encoding/json" // 标准库:玩法动作的自定义参数保持原始 JSON,由玩法插件自行解析
// PlayerBrief 是玩家在房间里的展示信息。
// 客户端只拿到昵称与头像,不含任何 AI 标记,因此无法区分真人与 AI。
type PlayerBrief struct {
UserID int64 `json:"user_id"` // 用户 ID(AI 也使用同构 ID,号段隔离但对外无差别)
Nickname string `json:"nickname"` // 昵称
Avatar string `json:"avatar"` // 头像(可访问 URL;为空时客户端用默认头像)
Seat int `json:"seat"` // 座位下标
Online bool `json:"online"` // 是否在线
}
// ===== 大厅上行 =====
// WSHallMatchRequest 是 hall.match 的上行体:请求进入匹配队列。
type WSHallMatchRequest struct {
GameID string `json:"game_id"` // 要玩的游戏 ID,必须是已注册的玩法
Seats int `json:"seats"` // 要开的桌人数(如贪吃蛇 2/3/4);0 或空表示按玩法最少人数
}
// WSHallCancelRequest 是 hall.cancel 的上行体:取消当前排队。
@@ -28,7 +39,7 @@ type WSRoomReadyRequest struct {
// WSRoomActionRequest 是 room.action 的上行体:一次玩法动作,透传给玩法插件。
type WSRoomActionRequest struct {
Action string `json:"action"` // 动作名,由玩法约定(如 "place")
Action string `json:"action"` // 动作名,由玩法约定(如 "place" / "turn")
Payload json.RawMessage `json:"payload,omitempty"` // 动作参数:原样透传,网关与房间都不解析
}
@@ -44,10 +55,11 @@ type WSRoomReconnectRequest struct {
// WSHallMatchedPayload 是 hall.matched 的下行体:告知匹配成功与房间信息。
type WSHallMatchedPayload struct {
RoomID string `json:"room_id"` // 新建房间 ID
GameID string `json:"game_id"` // 游戏 ID
Seats int `json:"seats"` // 总座位数(2=双人,>2=多人)
Users []int64 `json:"users"` // 同局用户 ID,顺序即座位顺序
RoomID string `json:"room_id"` // 房间 ID
GameID string `json:"game_id"` // 游戏 ID
Seats int `json:"seats"` // 总座位数
Users []int64 `json:"users"` // 同局全部用户 ID(顺序即入座顺序)
Players []PlayerBrief `json:"players"` // 同局展示信息:客户端应优先用它渲染头像与昵称
}
// WSHallCancelledPayload 是 hall.cancelled 的下行体:告知排队已取消。
@@ -60,12 +72,13 @@ type WSHallCancelledPayload struct {
// WSRoomStatePayload 是 room.state 的下行体:房间全量快照。
type WSRoomStatePayload struct {
RoomID string `json:"room_id"` // 房间 ID
GameID string `json:"game_id"` // 游戏 ID
Status string `json:"status"` // 状态:waiting/ready/playing/paused/finished/closed
Seats []int64 `json:"seats"` // 座位顺序(0 表示空位)
Ready []int64 `json:"ready"` // 已准备的用户 ID
State any `json:"state"` // 玩法对该用户可见的状态(Game.Snapshot 生成,可做信息隐藏)
RoomID string `json:"room_id"` // 房间 ID
GameID string `json:"game_id"` // 游戏 ID
Status string `json:"status"` // 状态:waiting/ready/playing/paused/finished/closed
Seats []int64 `json:"seats"` // 座位顺序(0 表示空位)
Ready []int64 `json:"ready"` // 已准备的用户 ID
Players []PlayerBrief `json:"players"` // 玩家展示信息(含 AI,但无任何标识)
State any `json:"state"` // 玩法对该用户可见的状态
}
// WSRoomEventPayload 是 room.event 的下行体:玩法产生的增量事件。
@@ -77,11 +90,12 @@ type WSRoomEventPayload struct {
// WSRoomFinishedPayload 是 room.finished 的下行体:对局结束与结算。
type WSRoomFinishedPayload struct {
RoomID string `json:"room_id"` // 房间 ID
GameID string `json:"game_id"` // 游戏 ID
Winner int64 `json:"winner"` // 获胜用户 ID,0 表示平局
Scores map[int64]int `json:"scores"` // 各用户得分,可为空
Reason string `json:"reason"` // 结束原因:normal/opponent_leave/timeout
RoomID string `json:"room_id"` // 房间 ID
GameID string `json:"game_id"` // 游戏 ID
Winner int64 `json:"winner"` // 获胜用户 ID,0 表示平局
Players []PlayerBrief `json:"players"` // 结算时的展示信息(便于直接显示「谁赢了」)
Scores map[int64]int `json:"scores"` // 各用户得分,可为空
Reason string `json:"reason"` // 结束原因:normal/opponent_leave/timeout
}
// WSRoomClosedPayload 是 room.closed 的下行体:房间已关闭。