三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

好用的skill 1.安装 npx skills add https://github.com/mattpocock/skills --skill grill-me 2.五子棋为例子AGENTS.md

好用的skill 1.安装 npx skills add https://github.com/mattpocock/skills --skill grill-me 2.五子棋为例子AGENTS.md

1.grill-me安装方式

只询问,然后写PLAN的一个skill,比superpower轻量级很多

npx skills@latest add mattpocock/skills

2.AGENTS.md

# 五子棋平台实施计划 > 状态:等待审核 > 本文件仅定义实施方案;审核通过前不创建工程骨架、不编写业务代码。 > 参考基线:E:\03_github\antares\doc\architecture-design.md > 当前仓库状态:wzz_client、wzz_proto、wzz_server、wzz_excel 均为空目录,需要从零初始化。 ## 1. 已确认的产品规则 ### 1.1 账号与会话 - 使用“用户名 + 密码”注册和登录,不设置独立昵称,界面直接展示用户名。 - 用户名按去除首尾空格并转小写后的值做唯一性判断,保留原始大小写用于展示。 - 密码只保存 Argon2id 哈希,禁止保存或记录明文。 - 同一账号只允许一个有效在线会话;新会话登录成功后,旧连接收到顶号通知并关闭。 - 登录成功后签发可撤销的随机会话令牌,浏览器断线时用令牌自动恢复会话,无需重复传输密码。 - 一个玩家同一时间只能处于一个房间或一个匹配队列中。 ### 1.2 棋局规则 - 棋盘为 15 × 15。 - 黑方先手。 - 横、竖、两个斜线方向连续五颗或以上即获胜。 - 不实现禁手规则。 - 棋盘填满且无人获胜时为平局。 - 在线状态下每步不限时。 - 支持主动认输;对局中主动离开等同认输。 - 首局随机分配黑白;“再来一局”时双方交换黑白。 ### 1.3 断线规则 - 连接断开不立即判负,PlayerActor 保留玩家与进行中房间的绑定。 - 仅一方离线时进入 5 分钟重连宽限期;超时后离线方判负。 - 双方同时离线时暂停单方判负计时,进入 30 分钟保留期;到期后棋局作废且不计分。 - 双方离线期间若只有一方恢复,为仍离线的一方重新开始 5 分钟宽限期。 - 新会话顶掉旧会话属于原子换绑,不触发断线判负计时。 - RoomActor 必须持久化离线时间与截止时间,进程重启或分片迁移后恢复计时器。 ### 1.4 积分与匹配 - 初始积分为 1000。 - 只有自动匹配创建的排位房计算积分。 - 手动创建的房间属于友谊赛,不加减积分,避免通过指定对手对刷。 - 排位赛胜方加 5 分,负方扣 3 分,平局双方不变。 - 积分最低为 0;当剩余不足 3 分时,失败后直接归零。 - 0 分玩家不能进入排位匹配,但仍可创建或加入友谊房、观战和聊天。 - 认输和单方断线超时按正常失败结算;双方断线超时作废且不结算。 - 匹配按入队时间优先寻找积分最接近的对手:初始分差不超过 100,每等待 10 秒扩大 100,最终不限制分差。 - 匹配成功后自动建房并直接开局,不再增加准备确认步骤。 ### 1.5 手动房、观战和聊天 - 首版只提供公开房,不实现密码房和私密邀请。 - 支持创建、分页查看房间列表、加入座位、准备、取消准备、离开、认输、再来一局。 - 手动房双方都准备后开始首局。 - 创建者为初始房主;等待状态下房主离开时转移给另一名在座玩家,无玩家时关闭房间。 - 支持中途加入观战,并立即收到完整房间与棋盘快照。 - 每个房间最多 2 名对局玩家和 100 名观众。 - 房间聊天对玩家和观众开放;只保留最近 100 条,不提供跨日历史。 - 已结束房间在 10 分钟内无人发起再来一局时关闭;该时长由 Luban 游戏配置控制。 ## 2. 技术基线 | 领域 | 选型 | |---|---| | JVM | JDK 21 | | 语言 | Kotlin 2.3;实施时锁定具体 2.3.x 补丁版本 | | 应用框架 | Asteria 0.6.9 | | Actor 集群 | Apache Pekko 1.2.1、Cluster Sharding、Cluster Singleton、Management/Bootstrap | | 注册与配置中心 | Nacos 3.1 | | 持久化 | MongoDB 7.0 Replica Set、majority write concern | | 客户端协议 | proto3,二进制 WebSocket;服务端使用 Google Protobuf 4,Vue 端使用 protobuf.js | | 客户端 | Vue 3、JavaScript、Vite、Pinia、Vue Router、protobuf.js | | 游戏配置 | Luban;客户端 javascript-json,服务端 java-json,数据均为 JSON | | 构建 | Gradle 9 Kotlin DSL、KSP;前端使用 pnpm 并提交锁文件 | | 本地部署 | Docker Compose,多 JVM 进程独立运行 | | 测试 | Kotlin Test/JUnit 5、Testcontainers、Vitest、Playwright | Nacos 3.1 用于: - 非敏感运行时配置与动态监听; - JVM 节点注册和发现; - Pekko Cluster Bootstrap 接触点发现; - Gate 对外服务实例注册。 MongoDB 密码、Nacos 凭据和会话签名材料等 Secret 只通过环境变量或挂载文件注入,不以明文发布到 Nacos。 业务 ID 使用 UUIDv7。项目不引入 Asteria 的 ZooKeeper Worker ID 模块,也不在 Nacos 上模拟 ZooKeeper 顺序节点。 配置职责必须分开: - Nacos 保存端口、节点角色、Mongo 连接参数、集群发现和日志级别等运行时配置。 - Luban 保存棋盘、积分、匹配窗口、断线宽限、房间容量等前后端共享的游戏规则和数值。 - 服务端永远是游戏配置的权威执行方;客户端生成的同源配置只用于界面展示和交互提示。 ## 3. 总体架构 客户端请求链路: Vue Client │ WSS + Protobuf ▼ Gate / ChannelActor ├── PlayerActor 分片:账号会话、积分快照、当前房间 ├── LobbyDirectoryActor 单例:公开房目录 ├── MatchmakerActor 单例:排位队列与配对 └── RoomActor 分片:棋盘、座位、观众、聊天、对局状态 │ ▼ SettlementActor │ ▼ MongoDB 事务 基础设施关系: 所有 JVM 进程 ──注册/发现/配置监听── Nacos 3.1 Player/Room/Global ──权威数据与恢复── MongoDB Replica Set 浏览器 ──二进制 WebSocket── Gate 运维探针 ──HTTP── 各进程健康端口 ### 3.1 独立进程与扩容边界 | 进程角色 | 核心职责 | 扩容方式 | |---|---|---| | Gate | WebSocket、ChannelActor、鉴权前状态机、协议解码、限流和路由 | 无状态水平扩容 | | Player | PlayerActor Cluster Sharding、会话换绑、玩家状态 | 按分片水平扩容 | | Room | RoomActor Cluster Sharding、棋局与房间权威状态 | 按分片水平扩容 | | Global | LobbyDirectoryActor、MatchmakerActor Cluster Singleton、SettlementActor 分片 | 至少两个实例,单例自动故障转移 | 本地 Docker Compose 至少启动 1 个 Gate、1 个 Player、1 个 Room、2 个 Global,以及 Nacos 3.1 和 MongoDB Replica Set。每个角色是独立 JVM,不使用 Antares 的同 JVM Stardust 模式作为最终运行形态。 ### 3.2 Actor 权威边界 | Actor | 实体键 | 权威状态 | |---|---|---| | ChannelActor | connectionId | 连接、鉴权阶段、请求序号、回包、订阅关系 | | PlayerActor | playerId | 当前会话代次、当前房间/匹配状态、积分版本、在线状态 | | RoomActor | roomId | 房主、座位、准备状态、棋盘、轮次、观众、最近聊天和重连截止时间 | | LobbyDirectoryActor | Cluster Singleton | 可见房间的只读索引;可从 MongoDB 重建 | | MatchmakerActor | Cluster Singleton | 排位票据、等待时间、积分窗口和配对流程 | | SettlementActor | settlementId | 单局幂等结算状态、重试与完成确认 | 原则: - 所有 Pekko Actor 类型、架构图节点和文档引用统一使用 Actor 后缀;进程角色、Gradle 模块、Repository 和普通 Service 不使用该后缀。 - Gate 不保存权威业务数据。 - 单玩家写入只在 PlayerActor 邮箱内串行。 - 单房间写入只在 RoomActor 邮箱内串行。 - 跨玩家积分结算使用 MongoDB 事务和唯一结算 ID,不依赖“消息恰好只发送一次”。 - 所有异步数据库结果必须回到 Actor 邮箱后再改变内存状态。 - Lobby 房间目录允许最终一致,但棋盘、胜负和积分不允许仅靠广播结果决定。 ## 4. Antares 复用方式与 Nacos 改造 保留 Antares 的以下模式: - Asteria 模块化节点启动; - Player/Room Cluster Sharding; - ChannelActor 会话状态机; - 构建期 Protobuf 协议注册、消息 Dispatcher 和 Gate 路由; - Actor 加载、Active、Draining、Passivate 生命周期; - Mongo 内存态加载和停机排空; - Cluster Singleton 协调全局业务; - 请求 ID、超时、重试和幂等的跨 Actor 约束。 不照搬以下内容: - 不使用 ZooKeeper、Curator 和 ZooKeeper Worker ID; - 不使用原生 TCP、LZ4 和自定义 AES Pipeline; - 不拆独立 Rust 战斗服;五子棋权威逻辑直接位于 RoomActor; - 首版不实现 GM、热补丁、动态游戏时间和 Kubernetes; - 不使用 Antares 当前不完整的 Battle 结算链路。 ### 4.1 Nacos 适配层 新增独立 infrastructure-nacos 模块,实现并测试: 1. NacosConfigStore 适配 Asteria ConfigStore 的读取、写入、监听、版本和 CAS 语义;将 ConfigPath 映射为 Nacos namespace、group、dataId。层级查询需要显式索引,不能依赖 Nacos 模糊搜索。 2. NacosRuntimeConfigModule 继续复用 Asteria RuntimeConfigRepository 和配置编解码,只替换底层 Store。 3. NacosServiceRegistrar 注册节点地址、Pekko Management 地址、角色、版本和健康元数据,并在优雅停机时注销。 4. NacosPekkoDiscovery 实现 Pekko Discovery 查询,为 Cluster Bootstrap 返回健康接触点;Nacos 只负责发现,Pekko Cluster 本身仍负责成员关系和故障检测。 5. NacosGameClusterApplicationFactory 根据 Nacos 配置组装 ActorSystem、角色、Remoting、Management、Sharding 和 Singleton。 6. 配置初始化工具 幂等发布本地开发配置,区分 dev/test/prod namespace;不得覆盖版本更新后的远端配置。 Nacos 数据规划: | 类型 | 规划 | |---|---| | Namespace | wzz-dev、wzz-test、wzz-prod | | Config Group | WZZ_RUNTIME | | Bootstrap Service | wzz-cluster-bootstrap | | Gate Service | wzz-gate | | 元数据 | role、nodeId、appVersion、remotingPort、managementPort、startedAt | ### 4.2 第一阶段技术门槛 Nacos 适配和 WebSocket 传输是本项目相对 Antares 的最大改动。正式展开业务前必须先通过一个最小技术闭环: - 两个独立 JVM 通过 Nacos 发现并加入同一 Pekko Cluster; - Nacos 配置可读取、监听、CAS 更新并正确处理重连; - 浏览器或测试客户端通过 WebSocket 发送一个 Protobuf EchoReq; - Gate 使用生成式路由把消息发送到另一进程的分片 Actor 并收到 EchoResp; - 任一节点重启后可重新注册,Cluster 无重复节点和脑裂; - 工程中不存在 ZooKeeper/Curator 运行时依赖。 若 Asteria 0.6.9 的扩展接口不足,优先在本仓库实现薄适配模块;只有确认无法保持兼容时,才提出升级或维护 Asteria fork,并在编码前再次申请审核。 ## 5. Luban 配置工程 ### 5.1 参考实现与独立性 - Vue 端参考 E:\03_github\luban_examples-main\Projects\Javascript_NodeJs_json,使用 javascript-json 代码目标和 json 数据目标。 - Kotlin 服务端参考 E:\03_github\luban_examples-main\Projects\java_json,生成 Java 配置类并由 Kotlin 直接调用,使用 java-json 代码目标和 json 数据目标。 - 参考目录只用于核对参数和加载方式,运行时及生成时不得依赖 E:\03_github\luban_examples-main。 - wzz_excel 内置固定版本的 Luban 工具、模板和 Windows x64 .NET 8 本地运行时;在未安装系统 dotnet 的干净 Windows 环境中也能执行。 - 记录 Luban 来源版本或提交、工具 SHA-256 和许可证,升级工具必须单独评审生成差异。 ### 5.2 wzz_excel 目录 计划结构: wzz_excel/ gen.bat README.md luban.conf Datas/ __tables__.xlsx __beans__.xlsx __enums__.xlsx game/ game_config.xlsx Defines/ builtin.xml Tools/ Luban/ dotnet/ VERSION.txt scripts/ generate.ps1 verify-output.ps1 .generated-tmp/ - 所有 Excel 源文件、Luban schema 和生成入口都放在 wzz_excel 内。 - gen.bat 必须使用自身目录作为基准,不依赖当前工作目录;从资源管理器双击和从命令行执行结果一致。 - .generated-tmp 仅用于生成暂存并加入忽略规则,不作为前后端加载目录。 - README 写明表结构、字段分组、生成目的地、工具版本和常见错误。 ### 5.3 共享游戏配置 首版至少建立一张全局游戏配置表,包含: | 字段 | 初始值 | 使用方 | |---|---:|---| | boardSize | 15 | 客户端、服务端 | | winLength | 5 | 客户端、服务端 | | initialRating | 1000 | 客户端、服务端 | | winRatingDelta | 5 | 客户端、服务端 | | loseRatingDelta | 3 | 客户端、服务端 | | matchMinRating | 1 | 客户端、服务端 | | matchInitialGap | 100 | 客户端、服务端 | | matchGapStep | 100 | 客户端、服务端 | | matchExpandIntervalSeconds | 10 | 客户端、服务端 | | singleDisconnectGraceSeconds | 300 | 客户端、服务端 | | bothDisconnectAbortSeconds | 1800 | 客户端、服务端 | | finishedRoomRetentionSeconds | 600 | 服务端 | | maxSpectators | 100 | 客户端、服务端 | | roomChatHistoryLimit | 100 | 客户端、服务端 | Luban 的 client/server 分组控制字段输出范围。任何影响胜负、积分或超时的配置即使输出给客户端,也必须由服务端重新校验。 ### 5.4 一键生成流程 双击 wzz_excel\gen.bat 后按以下顺序执行: 1. 检查本地 Luban、.NET 8 运行时、luban.conf、Excel 源文件及两个目标工程是否存在。 2. 清理本次专用的 .generated-tmp 子目录,不直接删除前后端现有生成目录。 3. 执行客户端生成:target=client、code=javascript-json、data=json。 4. 执行服务端生成:target=server、code=java-json、data=json。 5. 校验两次命令退出码、JSON 可解析性、必需表、代码文件和配置关键值。 6. 以相同 Excel 输入计算并写入 config-manifest.json,包含 schemaVersion、Luban 工具版本、目标完整哈希和双方共享字段哈希,不写入会破坏确定性的生成时间。 7. 客户端与服务端均验证成功后,才以带备份回滚的事务式同步替换目标目录;任一步失败都恢复并保留整套旧产物,返回非零退出码。 8. 输出生成文件数量、目标路径和成功/失败摘要;双击运行时保留窗口以便查看结果,CI 可传入 --no-pause。 固定输出位置: | 产物 | 目标目录 | |---|---| | JavaScript 配置代码 | wzz_client/src/generated/config/code | | 客户端 JSON | wzz_client/src/generated/config/data | | Java 配置代码 | wzz_server/config/src/generated/java | | 服务端 JSON | wzz_server/config/src/main/resources/game-config | | 两端配置清单 | 各自 JSON 目录内的 config-manifest.json | 生成目录由 gen.bat 独占管理,业务代码不得手工编辑生成物。生成物提交到版本库,CI 在临时目录重新生成并检查是否存在未提交差异。 ### 5.5 前后端加载 - Vue 使用 Luban 生成的 ES module schema.js 和 JSON;在应用启动阶段加载完整配置,构造 Tables 后再挂载页面。 - Vue 虽使用 JavaScript 工程,仍启用 jsconfig 和编辑器类型检查;Luban 生成代码不手改。 - 服务端新增 config Gradle 模块,把 src/generated/java 纳入 Java SourceSet,把 game-config JSON 打包为资源。 - Kotlin 通过薄封装 GameTables 访问 Luban 生成的 Java Tables,禁止业务层散落文件路径和 Gson 解析代码。 - 每个 JVM 角色启动时加载完整 Snapshot,执行字段范围和跨字段校验;失败则 readiness=false 并拒绝加入业务服务。 - 客户端与服务端连接握手时交换 config-manifest 中按双方共享字段计算的 sharedConfigHash;版本不一致时提示刷新客户端,服务端仍按自身配置裁定。客户端和服务端各自完整产物哈希允许因分组字段不同而不同。 - 首版配置随构建发布,不实现运行时热更新;后续若需要热更,另行设计 Nacos 发布、版本切换和 Actor 追赶流程。 ### 5.6 Excel 与生成验收 - Excel 表符合 Luban 模板行、类型、分组和唯一键约束,字段说明完整。 - 配置工作簿需检查关键单元格类型、公式错误和可读性,并至少完成一次视觉渲染确认。 - game_config 的约束至少包括:boardSize 和 winLength 为正且 winLength 不大于 boardSize;积分变化非负;时间和容量为正。 - 连续执行两次 gen.bat 必须得到字节级一致的代码、JSON 和 manifest。 - 从其他目录调用 gen.bat、路径包含空格、目标目录不存在、Excel 非法和单侧生成失败都必须有自动化测试。 - wzz_client 可加载生成的 JavaScript + JSON,wzz_server 可编译生成的 Java并加载同一份配置值。 ## 6. 协议与网络设计 ### 6.1 wzz_proto 目录 计划结构: wzz_proto/ buf.yaml buf.lock proto/ wzz/client/v1/common.proto wzz/client/v1/auth.proto wzz/client/v1/player.proto wzz/client/v1/lobby.proto wzz/client/v1/match.proto wzz/client/v1/room.proto wzz/internal/v1/player_rpc.proto wzz/internal/v1/room_rpc.proto wzz/internal/v1/global_rpc.proto - client 协议供 Vue 与 Gate 使用。 - internal 协议只供 JVM Actor/RPC 使用。 - 消息 ID 分段并生成注册表,禁止手写重复 ID。 - CI 执行 Protobuf lint、breaking change 检查和生成结果一致性检查。 - Vue 端协议实现固定使用 [protobuf.js](https://github.com/protobufjs/protobuf.js.git),依赖包与 CLI 版本通过 pnpm lockfile 锁定。 - Vue 构建前通过 protobuf.js 的 pbjs 生成 ES module 静态模块;不在浏览器运行时动态解析 .proto 文件。 - Vue 生成物输出到 wzz_client/src/generated/proto,wzz_server 的 Java/Kotlin 生成物输出到 build/generated;两种语言的生成物都不放入 wzz_proto。 - Protobuf uint64 字段在 Vue 端使用 Long 或十进制字符串表示,禁止转换为可能丢失精度的 JavaScript number。 ### 6.2 WebSocket 数据包 - 只接受二进制帧,文本帧直接拒绝。 - WebSocket 自带消息边界,不重复实现 Antares 的 TCP 长度帧。 - 帧内使用 Packet Protobuf,包含协议版本、protocolId、clientSeq、requestId、payload 和 flags。 - requestId 用于端到端幂等与日志关联;clientSeq 用于检测重复和乱序请求。 - 首版不启用 LZ4;单帧解码后最大 64 KiB,房间快照也必须受该限制。 - 使用 WSS/TLS 保护传输,不实现 Antares 的自定义 AES。 - 未鉴权连接只允许注册、登录、恢复会话、心跳。 - 已鉴权路由中的 playerId 一律来自服务端 Session,不相信客户端提交的 playerId。 ### 6.3 客户端协议清单 - Common:Hello、Heartbeat、Error、ServerNotice。 - Auth:Register、Login、ResumeSession、Logout、Kicked。 - Player:Profile、ScoreChanged、CurrentRoom。 - Lobby:EnterLobby、RoomList、RoomSummary、LobbyChanged。 - Match:StartMatch、CancelMatch、MatchStatus、Matched。 - Room:Create、JoinSeat、JoinSpectator、Ready、Leave、Resign、PlaceStone、Snapshot、StateChanged、GameEnded、Rematch、Chat。 所有修改状态的请求都携带 requestId;服务端缓存或持久化最近结果,使客户端超时重发不会重复落子、重复建房或重复结算。 ## 7. MongoDB 数据与一致性 ### 7.1 集合 | 集合 | 关键字段与索引 | |---|---| | account | playerId;usernameNormalized 唯一索引;passwordHash;createdAt;lastLoginAt | | session | tokenHash 唯一索引;playerId 唯一索引;expiresAt TTL;sessionEpoch | | player_profile | playerId 唯一;rating;ratingVersion;activeRoomId;统计数据 | | room | roomId 唯一;mode;status;players;board;turn;round;version;deadlines;recentChats | | match_ticket | ticketId 唯一;playerId 唯一;rating;queuedAt;status;TTL | | game_result | settlementId 唯一;roomId + round 唯一;结果;前后积分;结算状态 | ### 7.2 房间持久化 - RoomActor 激活时从 room 文档恢复完整状态。 - 棋盘最多 225 手,首版在房间文档中保存紧凑棋盘和顺序 moveLog。 - 每次合法落子、开始、认输、判负和结束均以 room version 做乐观并发更新。 - 权威状态写入 majority 成功后才向客户端确认,避免节点硬故障后客户端已见落子却无法恢复。 - 观众连接引用不持久化;观众重连后重新订阅并获取 Snapshot。 - RoomActor handoff/passivate 前等待在途写入完成。 ### 7.3 幂等积分结算 1. RoomActor 确认终局并生成 settlementId = roomId + round。 2. SettlementActor 以 settlementId 查询或创建结算。 3. 在同一个 MongoDB 事务中插入 game_result,并更新两名玩家的积分与 ratingVersion。 4. 唯一索引保证重复请求只产生一次结算。 5. 提交后向两个 PlayerActor 发送包含绝对 afterRating 和 ratingVersion 的通知。 6. PlayerActor 按版本应用;重复或旧版本通知直接忽略。 7. RoomActor 收到结算完成后进入 Finished,并向客户端广播最终积分。 8. 进程在事务提交后、Actor 通知前崩溃时,由 SettlementActor 重试并补发通知。 友谊赛仍保存 game_result,但 rated=false,不更新积分。 ## 8. 核心状态机 ### 8.1 连接状态 Connected ├── Registering ├── Authenticating └── Resuming │ ▼ Authorized ├── 正常路由 ├── 新会话换绑 └── Closed - 登录成功前不创建业务订阅。 - 登录/恢复成功后 PlayerActor 增加 sessionEpoch,并关闭旧 ChannelActor。 - 掉线后 PlayerActor 通知当前 RoomActor;恢复后重新绑定、取消对应超时并推送最新 Snapshot。 ### 8.2 房间状态 Waiting ──双方准备/匹配建房──> Playing │ ├── Finished └── Empty -> Closed ├── Aborted └── Settling -> Finished - Waiting:管理房主、座位、准备和观众。 - Playing:RoomActor 校验座位、轮次、坐标、空位和终局。 - Settling:拒绝新落子,允许查询快照,等待幂等积分结算。 - Finished:允许观战、聊天和发起再来一局。 - Aborted:双方断线超时,不计分。 - Closed:从房间目录移除并允许 Actor 钝化。 ### 8.3 匹配流程 1. PlayerActor 校验积分大于 0、未在房间且未排队。 2. 写入唯一 match_ticket,再交给 MatchmakerActor。 3. MatchmakerActor 按等待时间和动态积分窗口选对手。 4. 分别向两个 PlayerActor 申请 reservation,避免匹配与手动入房竞态。 5. 创建排位 RoomActor,随机黑白并直接进入 Playing。 6. 成功后完成票据并通知双方;失败则释放 reservation 并恢复有效票据。 7. MatchmakerActor 故障转移后从 MongoDB 重建等待队列。 ## 9. 客户端计划 ### 9.1 页面 - 注册/登录页。 - 大厅页:当前用户名和积分、匹配按钮、公开房分页列表、创建房间。 - 匹配状态浮层:等待时长、当前允许分差、取消按钮。 - 房间页:15 × 15 棋盘、双方信息、准备/认输/离开/再来一局、观众数和聊天。 - 断线恢复遮罩:重连进度、恢复成功后的快照同步、会话失效后返回登录。 ### 9.2 客户端状态 - authStore:账号、会话令牌、顶号和退出。 - socketStore:连接、心跳、指数退避重连、requestId、请求超时。 - lobbyStore:房间列表、匹配状态。 - roomStore:房间快照、增量事件、棋盘、聊天和观战状态。 客户端只做预测性展示,不自行裁定落子合法性、胜负或积分。收到增量事件版本不连续时立即请求完整 Snapshot。 ### 9.3 棋盘交互 - 使用 Canvas 或 SVG 绘制棋盘和棋子,选择后以实际性能与可访问性测试确定。 - 显示最后一步、当前行棋方、黑白身份和终局连线。 - 落子请求未确认前锁定重复点击;服务端拒绝时回滚等待态。 - 观众没有落子控件。 ## 10. wzz_server 工程规划 ### 10.1 Gradle 多模块 计划采用 Gradle 多模块: wzz_server/ build-logic/ common/ protocol/ config/ infrastructure-nacos/ infrastructure-mongo/ gate/ player/ lobby/ match/ room/ global/ tools/ deploy/ docker-compose.yml Dockerfile - common:领域值对象、错误码、时间、请求 ID 和运行时公共能力。 - protocol:从 wzz_proto 生成 JVM Protobuf、协议注册表和内部 RPC。 - config:接收 wzz_excel 生成的 Java 代码和 JSON,提供 Kotlin GameTables 与启动校验。 - infrastructure-nacos:配置、注册发现和 Pekko Bootstrap 适配。 - infrastructure-mongo:客户端、索引、事务和 Repository。 - gate/player/room:对应可执行角色和 Actor。 - lobby/match:领域库,由 global 进程安装。 - global:安装 lobby/match 领域模块并承载 LobbyDirectoryActor、MatchmakerActor 和 SettlementActor。 - tools:Nacos 配置初始化、索引初始化和协议检查。 wzz_server 通过相对路径只读引用 ../wzz_proto/proto;不复制协议源文件。 ### 10.2 Gradle Wrapper 腾讯云镜像 - wzz_server 必须提交 gradlew、gradlew.bat 和 gradle/wrapper 下的 Wrapper 文件,所有开发、CI 和部署构建只通过 Wrapper 启动。 - Gradle 9 在阶段 0 锁定具体补丁版本后,把下方 x.x.x 替换为该版本;禁止保留动态版本或回退到 services.gradle.org。 - gradle-wrapper.properties 必须使用腾讯云发行包镜像和 all.zip: distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-x.x.x-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists - 锁定版本后补充 distributionSha256Sum,并使用官方同版本发行包 SHA-256 校验腾讯云镜像内容。 - CI 检查 URL、all.zip、10 秒超时、URL 校验和 SHA-256;Gradle Wrapper 升级后若这些属性被覆盖,构建直接失败。 ## 11. 分阶段实施顺序 ### 阶段 0:工程与技术验证 - 初始化四个工程、版本目录和统一格式化规则。 - 锁定 Gradle 9 具体版本并配置、校验腾讯云 Gradle Wrapper 镜像。 - 初始化 wzz_excel 独立 Luban 工程并打通 gen.bat 前后端双目标生成。 - 接通 Asteria、Pekko、KSP、Protobuf、Luban 配置加载和最小测试。 - 完成 Nacos 适配与跨进程 Echo WebSocket 闭环。 - 输出架构验证记录和已知限制。 验收:第 4.2 节所有技术门槛通过后才能进入业务阶段。 ### 阶段 1:协议、账号和会话 - 定义通用包、错误码、注册、登录、恢复、心跳和顶号协议。 - 实现账户索引、Argon2id、会话令牌、登录限流和 PlayerActor 换绑。 - 完成 Vue 注册登录、Socket 管理和自动重连。 验收:并发注册同名账号只有一个成功;后登录必定顶掉旧连接;重连恢复同一 PlayerActor 状态。 ### 阶段 2:手动房与基础大厅 - 实现 LobbyDirectoryActor、RoomActor、房间目录和手动房状态机。 - 实现创建、列表、入座、准备、离开和房主转移。 - 完成大厅和房间基础页面。 验收:多个 Gate 下房间列表一致;玩家不能同时占用两个座位;空房正确关闭。 ### 阶段 3:五子棋核心 - 实现纯 Kotlin、无 Actor 依赖的棋盘领域模型。 - 实现落子校验、四方向胜负、平局、认输和持久化。 - 接入 RoomActor 广播与客户端棋盘交互。 验收:边界、长连、交叉连线、重复落子、越界、非当前玩家等测试全部通过;节点重启后棋盘不丢步。 ### 阶段 4:匹配与积分结算 - 实现 MatchmakerActor、动态分差、取消、reservation 和故障恢复。 - 实现排位房自动开局。 - 实现 SettlementActor、MongoDB 事务、幂等积分和 0 分限制。 验收:同一局重复结算不会重复加减分;手动房永不改变积分;0 分无法匹配;Global 单例切换后队列可恢复。 ### 阶段 5:断线、观战、聊天和再来一局 - 实现单方/双方断线计时与恢复。 - 实现观众快照、订阅恢复、人数上限。 - 实现最近 100 条房间聊天和消息长度/频率限制。 - 实现 Finished 保留期和双方再来一局换边。 验收:Room 节点在宽限期中重启仍按原截止语义处理;顶号不误判断线;第 101 条聊天淘汰最旧消息。 ### 阶段 6:部署、可观测性和完整验收 - 完成独立角色镜像、Docker Compose、启动顺序和健康探针。 - 增加结构化日志、角色/消息/耗时标签、Prometheus 指标。 - 增加优雅停机:Gate 拒绝新连接,Player/Room 排空并 flush。 - 完成端到端、故障注入、协议兼容和基础压测。 - 编写开发启动、配置、部署、数据恢复和故障排查文档。 验收:全新环境可用一条文档化命令启动;完整用户旅程通过;进程滚动重启不造成重复结算或已确认棋步丢失。 ## 12. 测试矩阵 ### 12.1 单元测试 - 四方向五连及五连以上、边界、平局和非法落子。 - 房间所有状态迁移和权限校验。 - 匹配窗口扩展、排队公平性和取消竞态。 - 积分归零、平局、排位/友谊模式隔离。 - 用户名规范化、密码校验和协议错误码。 ### 12.2 适配与持久化测试 - Nacos ConfigStore 的读写、监听、CAS、断线重连和 namespace 隔离。 - Luban client/server 分组、双目标生成、配置校验、清单哈希和失败不覆盖旧产物。 - Pekko Discovery 的节点上下线、重复注册和缓存过期。 - Mongo 索引、事务回滚、幂等结算和 Replica Set 主节点切换。 - Room 乐观版本冲突和 Actor 重载。 ### 12.3 多进程集成测试 - Gate 到 Player、Global、Room 的生成式路由。 - 两个 Gate 下的顶号、断线和恢复。 - Player/Room 分片迁移与 handoff。 - MatchmakerActor Cluster Singleton 故障转移和队列重建。 - 结算提交后通知前强杀进程,恢复后仍只结算一次。 ### 12.4 浏览器端到端测试 - 注册、登录、进入大厅、创建/加入/准备、完整下完一局。 - 自动匹配、获胜积分 +5、失败 -3、平局不变。 - 观战中途加入、聊天、再来一局换边。 - WebSocket 断开、恢复棋局、会话过期和顶号。 ### 12.5 安全与容量 - 非法 protocolId、超大帧、畸形 Protobuf、未鉴权路由和重放 requestId。 - 注册/登录/聊天/落子的连接级和账号级限流。 - 日志不出现密码、令牌和完整凭据。 - 压测 Gate 长连接、RoomActor 活跃数、观战广播和匹配队列。 ## 13. 可观测性 必须至少提供: - WebSocket 当前连接数、鉴权连接数、重连数和顶号数; - 协议请求成功/失败/耗时,标签限制为固定角色和消息类型; - 活跃 PlayerActor、RoomActor、排队人数和匹配等待时间; - 对局开始/结束/作废、断线判负和结算重试; - Mongo 事务耗时/失败、Nacos 连接状态、Pekko Cluster 成员和分片迁移; - requestId、playerId、roomId、settlementId 的结构化日志关联。 健康接口只提供基础探针: - alive:进程存活。 - ready:已加入 Pekko Cluster,Nacos 注册完成,必需依赖可用,角色模块启动完成。 ## 14. 明确不在首版范围内 - 人机 AI、机器人补位; - 五子棋禁手、不同棋盘尺寸和每步计时; - 密码房、好友邀请、好友系统; - 大厅公共聊天、私聊、排行榜; - 邮箱/手机验证码、找回密码、第三方登录; - GM 管理后台、热补丁和脚本系统; - 独立战斗服务器; - Kubernetes 生产清单和多地域容灾。 这些能力必须在首版验收后另立计划,不在实现过程中顺手扩展。 ## 15. 最终交付验收 最终必须同时满足: 1. wzz_client、wzz_proto、wzz_server 和 wzz_excel 可独立运行或构建,并共享同一份协议与同源游戏配置。 2. JDK 21、Kotlin 2.3、Asteria、Pekko、Nacos 3.1 和 MongoDB 版本全部锁定且可复现;Gradle Wrapper 只能从指定腾讯云镜像下载并通过 SHA-256 校验。 3. Gate、Player、Room、Global 为独立 JVM 进程,并能通过 Nacos 组成集群。 4. 注册、登录、顶号、断线恢复和退出完整可用。 5. 大厅、匹配、手动房、准备、五子棋、积分、观战、聊天和再来一局完整可用。 6. 排位积分与友谊赛严格隔离,结算幂等且通过 MongoDB 事务闭环。 7. 已确认落子在 Room 节点故障和分片迁移后可恢复。 8. 所有关键状态机、事务、集群故障和浏览器主流程有自动化测试。 9. Docker Compose 能启动完整多进程开发环境,并有清晰的运行与排障文档。 10. wzz_excel 双击 gen.bat 可在不依赖外部示例仓库和系统 dotnet 的情况下,把 JavaScript/Java 代码及 JSON 原子生成到前后端。 11. 不包含 ZooKeeper/Curator 运行时依赖,不存在明文密码或令牌日志。 ## 16. 审核后执行约束 - 只有本 PLAN.md 获得明确批准后才开始编码。 - 编码按阶段提交,每一阶段先通过其验收条件再进入下一阶段。 - 若阶段 0 发现 Asteria 0.6.9 无法以兼容方式接入 Nacos 3.1 或 WebSocket,暂停业务开发,提交证据和替代方案重新审核。 - 实施中若需要改变已确认的积分、断线、匹配或房间规则,先更新本计划并再次获得批准。
← 返回列表