Files
AIC-Project/docs/superpowers/specs/2026-06-22-remove-hello-complete-rps-design.md
T
2026-07-10 10:24:29 +08:00

7.5 KiB

删除 Hello 热更小游戏 + 完善剪刀石头布(RPS)替代它 — 设计

日期:2026-06-22 状态:已与用户对齐设计决策,待用户复核本 spec

1. 背景与目标

Hello 是 C# 热更小游戏平台早期的测试夹具:一个每 tick 计数、3 tick 自结束、单人(playerCount=1)的极简游戏。它的真正用途是验证框架通用能力(ALC 加载/卸载、跨界类型隔离、版本引用计数与淘汰、多版本并存热更、房间生命周期、game.json 解析、网关消息流、断线重连),并通过 #if HELLO_V2 编出 v1/v2 两份不同 IL 来测"多版本并存"。

剪刀石头布(RockPaperScissors / RPS)是平台的第一个真实小游戏:

  • 服务端 C# 已完整:RPS.Core(规则/状态/二进制编解码/确定性随机)+ RPS.Server(IGameServerRoom,2 人对战,AI 匹配兜底)。已被 RpsLogicTestsRpsServerRoomTestsRpsModuleLoadTestsServerLoopMatchmakingTestsRpsEndToEndTests 覆盖。
  • 客户端缺 C#:目前只有弃用的 Lua 实现(Client/main.luaServer/main.lua,及 scripts/ 下同名拷贝)。README 已声明 Lua 路线弃用,待 C# 重写。

目标:彻底删除 Hello;让 RPS 完整替代 Hello 的两个角色——(a) 框架测试夹具,(b) 端到端示例游戏(含 C# 客户端薄层)。删除后 dotnet test Server/Server.sln 必须保持全绿。

2. 设计决策(已与用户确认)

  1. 不在 RPS 生产代码加任何 #if。删除唯一依赖"两份不同 IL"的测试 HotReloadEndToEndTests(v1/v2 计数差异断言)。多版本相关的其余覆盖(引用计数、淘汰、卸载)用 rps/1 + rps/2 同 IL 拷贝(version 字段不同、DLL 字节相同)保留——这些测试只关心版本号与 refcount,不关心 IL 差异。
  2. 删除弃用的 Lua 文件,由 C# 客户端取代。
  3. C# 客户端薄层落在 Client/Assets/MiniGames/RockPaperScissors/scripts/Client/(符合设计 §2.4 与 README)。
  4. 本环境无 Unity:C# 客户端与 PC 烟雾的 Unity 部分只能用 csc 编译验证,无法 Play 核对;纯 .NET 部分用 dotnet test 验证。

3. 工作分解

3.1 删除 Hello 源码与产物

  • 删目录:Server/games-src/Hello/Client/HotUpdateGames/HelloFlow.Client/
  • 删夹具:Server/Server.Host.Tests/TestGames/hello/(及各 bin/.../TestGames/hello/ 运行时拷贝,会被重建,无需手动逐个删但应清理源树内的)。
  • Server/Server.Host/GameManifest.cs 文档注释里的 Hello 示例改为 RPS。

3.2 构建脚本 Server/build-test-games.sh

  • 删除 build_variant(Hello v1/v2)及其两处调用。
  • 扩展 RPS 段:除 rps/1 外,再把同一批 RPS.Core.dll / RPS.Server.dll 拷到 rps/2,并写 version:2 的 game.json(IL 完全相同,仅供版本号/淘汰/refcount 测试)。
  • 保留既有 Private=false(Framework.Shared 不入产物)断言。

3.3 测试迁移(dotnet test Server/Server.sln 保持全绿)

按"是否已有 RPS 等价覆盖"分类处理:

文件 处理 说明
HotReloadEndToEndTests.cs 删除 唯一需两份不同 IL;按决策 1 移除
AlcUnloadTests.cs 改用 rps 卸载回收内存,RPS 无等价,迁移
GameManifestTests.cs 改用 rps manifest game.json 解析,改读 rps/1(及 rps/2 字段)
GameModuleRegistryTests.cs 改用 rps/1+rps/2 refcount/淘汰/卸载,用同 IL 双版本
GameModuleLoaderTests.cs 改用 rps,与 RpsModuleLoadTests 去重 若与现有 RPS 加载测试重复则删冗余,保留独有断言(缺版本抛错等)
RoomHostTests.cs 改用 rps 适配 2 人(AI 补位/双 player)、对局非 3-tick 结束(用多 tick / logicalDt 推进到 Finished);投递改为发 Choice 消息
ServerLoopTests.cs 框架通用用例改用 rps,与 ServerLoopMatchmakingTests 去重 心跳/重连/过期会话/无房间帧等通用用例迁移;匹配流若已被 Matchmaking 测试覆盖则删冗余
GatewayEndToEndTests.cs RpsEndToEndTests 去重 e2e 已有 RPS 版;保留独有的重连用例(改 rps)或删冗余
MatchmakerTests.cs 删 hello 引用 已含 rps 用例,移除 hello 分支
RpsModuleLoadTests.cs 删 hello 引用 同上

迁移适配要点:

  • RPS playerCount=2:需要真人+真人或真人+AI 成团;单测里可直接构造 2 个 PlayerInfo 或走匹配 AI 兜底。
  • RPS 对局靠时间推进(60s,选 5s/亮 5s):测试用大 dt 或多次 tick 推进到 RpsPhase.Finished,避免真实 60s 等待(沿用 GameServerHostlogicalDt 思路)。
  • 快照 opcode:RPS SnapshotOpcode=1(Hello 用 2),断言需相应调整。

3.4 RPS C# 客户端(对标 HelloFlowGameClient)

  • 新建 Client/Assets/MiniGames/RockPaperScissors/scripts/Client/RPS.Client.csproj:
    • netstandard2.1 / C# 9,引用 Framework.Shared + RPS.Core(均 Private=false),引用 UnityEngine/CoreModule/IMGUIModule(HintPath 同 HelloFlow.Client)。
  • 新建 RpsGameClient.cs:实现 IGameClient(OnEnter/OnNetMessage/OnUpdate/OnExit):
    • OnEnter:建 IMGUI 视图(MonoBehaviour),状态"等待匹配"。
    • OnNetMessage:用 RpsLogic.Decode 解快照,更新视图(回合数、阶段、双方比分、本回合选择/结算、最终胜负)。
    • 出招:在 Choosing 阶段由按钮/快捷键触发,PacketWriter 写 Choice,ctx.Send(new NetMessage(ChoiceOpcode, ...))
    • 镜像 Lua 客户端的交互语义(本地玩家固定左侧、选择锁定、计时进度、auto 标记、最终结算行)。受限于 C# 快照当前字段,展示按 RpsState 现有字段呈现(座位/选择/比分/胜者),不强行扩协议。
  • 验证:用 csc + Unity 引擎 DLL + Framework.Shared.dll + RPS.Core.dll 编译,要求 0 错误(沿用第 3 步的 rsp 响应文件做法)。

3.5 删除弃用 Lua

  • Client/Assets/MiniGames/RockPaperScissors/Client/main.lua.../Server/main.lua.../scripts/Client/main.lua.../scripts/Server/main.lua(及其 .meta)。
  • 更新 README.md:状态从"Lua 弃用待重写"改为"C# 客户端已落地于 scripts/Client";服务端薄层指向 Server/games-src/RPS/

3.6 PC 烟雾测试

  • Tools/PcMiniGameSmoke/Build-PcMiniGameSmoke.ps1:Hello → RPS(构建 RPS.Server + RPS.Client,产出 server/games/rps/1/client/minigame/rps/1/,2 人 + AI 兜底)。
  • Client/Assets/Script/xmain/MiniGame/PcMiniGameSmokeLauncher.cs:把 hello 引用改 rps。
  • .NET 构建段尽量验证;Unity Play 留人工核对(本环境无法验)。

4. 验证策略

  • 主锚点:dotnet test Server/Server.sln 迁移后保持全绿(当前 145/145,删 HotReload 与去重后总数会变,但必须 0 失败)。
  • 客户端:csc 编译 RPS.Client = 0 错误。
  • 构建脚本:bash Server/build-test-games.sh 成功产出 rps/1rps/2,且无 Framework.Shared.dll 泄漏。
  • 无法在本环境验证(须 Unity 真机/编辑器,明确标注遗留):RPS 客户端运行时表现、PC 烟雾 Play、HybridCLR 加载、AB 打包。

5. 非目标(YAGNI)

  • 不把 RPS.Core 源码迁到 scripts/Core(设计 §10.1 的"统一 Core 单源"是独立改造项,且本环境无法 Unity 验证,本次不动)。
  • 不深化 RPS 玩法(不加新回合规则/奖励到 C# 协议层)。客户端按现有 RpsState 字段呈现。
  • 不实现统一 AB 打包改造(设计 §10.1 待办,须 Unity)。

6. 风险

  • 测试迁移可能暴露 RPS 在某些框架路径下的差异(如 2 人匹配、时间推进),需逐个适配断言;以 dotnet test 全绿为准绳。
  • C# 客户端与 PC 烟雾的 Unity 行为无法在本环境证实,只能编译验证 + 标注人工核对。