20 KiB
20 KiB
ROK 业务规则总索引(1:1 迁移依据)
来源:
E:\Game\gmd\ROK服务端 Lua + 客户端 C# + sproto 协议 用途:移植到 Survivors 工程前的业务规则全摊牌,实现时禁止凭空发挥 调研日期:2026-05-27
0. 四份文档清单
| # | 文档 | 大小 | 摘要 |
|---|---|---|---|
| 1 | ROK-Hero-Spec.md | 70K / 1362 行 | 英雄系统完整业务(招募 / 升级 / 升星 / 技能 / 觉醒 / 天赋 / 装备 / 战力 / 排序 / 同步部队) |
| 2 | ROK-Bag-Spec.md | 48K / ~770 行 | 背包系统(道具 6 大类 / itemId 编码 / 增删使用 / 礼包 / 资源货币机制) |
| 3 | ROK-HeroAcquire-Spec.md | 34K / 456 行 | 英雄获取链路(ROK 无抽卡,是宝箱+碎片+主动召唤) |
| 4 | ROK-Equip-Spec.md | 25K | 装备系统(8 槽位 / 锻造双段 RPC / 分解 / 套装 / 材料合成) |
1. 四个核心架构结论(必读)
结论 1:ROK 没有抽卡,是"宝箱产出碎片 + 主动碎片召唤"两段式
酒馆宝箱(白银 / 黄金 / 免费 + 付费)
│ Build_Tavern 407 → 服务端 ItemPackage 随机产出
▼
碎片 / 资源 / 士兵 / 极少数英雄本体
│
▼
Captain UI → 点击"召唤" → Hero_SummonHero 601
│ 扣 HeroDefine.getItem × HeroDefine.getItemNum 个碎片
▼
英雄入手(每个 heroId 一辈子只能拥有 1 次)
对 openspec 的影响:
- ⚠️ 原
cn.etetet.gacha包不对应 ROK 任何业务(ROK 没抽卡) - ✅ 用户明确表示"想要抽卡用来验证产出",所以
cn.etetet.gacha作为 Survivors 独立扩展功能保留,但定位明确为"在 ROK 基础上新增",不是"移植" - ✅ 1:1 严格迁移的入口实际是
cn.etetet.summon(碎片召唤)+cn.etetet.tavern(酒馆宝箱),二者比抽卡更接近 ROK
结论 2:资源货币(金/木/石/粮/宝石/VIP/行动力)不进背包,是 Role 字段
ROK 把 可堆叠的玩家货币 和 进背包的道具 分得很清楚:
| 类别 | 存储方式 | 操作 API | 示例 |
|---|---|---|---|
| 货币 | Role Entity 字段 | RoleLogic.addGold/Wood/Stone/Grain/Gem/Vip/Vitality |
金币、木料、粮食、宝石、行动力、VIP |
| 资源类道具袋 | Item 入背包 | ItemLogic.addItem |
1xxxxxxxx 段的"100 金币袋",使用时调 ItemChangeResource 兑换为货币 |
| 装备 / 材料 / 经验书 / 其他 | Item 入背包 | ItemLogic.addItem |
4xxxxxxxx + 5xxxxxxxx 段 |
| 头像框 HEAD | 不进背包 | RoleLogic.unlockRoleHead |
直接挂玩家解锁列表 |
对 openspec 的影响:
- ⚠️ 之前
bag-system/spec.md写的 "通用 Item 设计原则,全部货币也用 itemId 管理" 与 ROK 不一致 - ✅ 1:1 迁移应该跟随 ROK:金币 / 钻石 在 PlayerComponent 上做整型字段,而不是 BagItem
- ✅ 但"统一奖励 / 消耗结构 RewardEntry { itemId, count }" 这个抽象层可以保留——服务端发奖时用 RewardEntry 表达,内部分发到 Role 字段或 BagComponent
结论 3:装备就是带 heroId 的 Item,不是独立 Entity
| 维度 | 真相 |
|---|---|
| 装备的存储 | 背包 ItemUnit,count=1,heroId>0 表示已穿戴 |
| 英雄持有装备 | Hero Entity 上 8 个 int 字段,存 itemIndex(引用背包) |
| 装备槽位数 | 8 个(head / breastPlate / weapon / gloves / pants / accessories1 / accessories2 / shoes) |
| 装备 subType 数 | 6 种(HELMET / BREASTPLATE / ARMS / GLOVES / PANTS / ACCESSORIES / SHOES)— accessories 两槽共享同一 subType |
| 锻造 RPC | 双段:CheckMakeEquip (50% 专属概率) → MakeEquipment (真消耗) |
| 锻造是否随机 | 必中(材料够 + 金币够 = 必出),随机的是"专属属性" |
| 分解 | 已穿戴可直接分解(前提英雄在城内),返还固定,无随机 |
对 openspec 的影响:
- ⚠️ 之前规划的"独立
cn.etetet.equip包"过度设计;改为装备子系统放在cn.etetet.bag+cn.etetet.hero协作实现 - ⚠️ 之前 spec 说"8 部位"但没说映射,实际是 8 槽 / 6 subType,accessories 双槽共享,需修正
- ⚠️ 之前漏写 CheckMakeEquip 预检 RPC,需补充
结论 4:英雄字段比 openspec 现有 spec 写的多得多
英雄 Entity 上的字段(部分):
| 之前 spec 提到 | ROK 实际还有 |
|---|---|
| heroId / level / exp / star / starExp / skills / talents | + summonTime / soldierKillNum / savageKillNum / talentPoint(遗留) / talentTrees(3 套天赋页 map) / talentIndex |
| + 8 个装备字段 |
英雄招募的真实字段名:
| openspec 用过的名字 | ROK 真名 |
|---|---|
fragmentItemId |
getItem |
recruitLimit |
不存在(每个 heroId 一辈子只能拥 1 次,重复 → HERO_ALREADY_EXIST 错误码) |
2. 与 openspec 现有 spec 的差异清单(必须修正)
以下 specs 文件需要根据本调研结果调整:
2.1 openspec/changes/port-rok-hero-bag-system/specs/hero-system/spec.md
| 需修正项 | 当前写法 | ROK 真相 | 建议改法 |
|---|---|---|---|
| 招募字段名 | fragmentItemId / recruitLimit |
getItem / getItemNum,无 recruitLimit |
字段名跟 ROK |
| 招募上限 | "上限"概念 | 每个 heroId 拥 1 次(重复报错) | 改成"重复招募校验" |
| 战力公式 | 通用描述 | 完整公式见 [Hero-Spec §4.10] | 引用 Doc/ROK-Hero-Spec.md |
| 天赋字段 | TalentIndex 单值 |
talentTrees map(1/2/3 三套)+ talentIndex |
加 3 套天赋页结构 |
| 觉醒触发 | 通用描述 | 前 4 技能满级自动解锁第 5 + 独立 RPC | 双触发机制 |
| 部队同步 | 未提 | 任意英雄改动 → 更新 RoleArmy 战斗属性 |
加同步规则 |
2.2 openspec/changes/port-rok-hero-bag-system/specs/bag-system/spec.md
| 需修正项 | 当前写法 | ROK 真相 | 建议改法 |
|---|---|---|---|
| 通用 Item 设计 | "所有货币都走 itemId" | ROK 金/木/石/粮/宝石/VIP 是 Role 字段 | 改成"统一奖励结构 RewardEntry,内部分发到 Role 字段 / BagComponent" |
| 道具脚本 | "ItemScript 注册机制" | ROK 没有脚本表,是 if/elseif 硬编码 | Survivors 可以做得更好(用 IItemUseHandler 注册),但要意识到 ROK 是硬编码 |
| 新道具标记 | "服务端 + 客户端分工" | ROK 全在客户端 PlayerPrefs | 跟 ROK:客户端 SaveManager 存 |
| BagItemType | "6 大类" | ROK Tab 只显 5 个(HEAD 类不入背包) | 改成 5 Tab |
| 头像框 | 未提 | HEAD 类不进背包,直走 unlockRoleHead | 加单独说明 |
| 资源阈值告警 | 未提 | s_GameWarning.num 大额变动通知运营 |
可保留作为 P3 |
2.3 openspec/changes/port-rok-hero-bag-system/specs/equipment-system/spec.md
| 需修正项 | 当前写法 | ROK 真相 | 建议改法 |
|---|---|---|---|
| 部位数 | "8 部位 + 4 个 EquipItemType" | 8 槽 / 6 subType(accessories 双槽共享) | 修正映射 |
| 锻造 | 单 RPC | 双 RPC(CheckMakeEquip + MakeEquipment) | 加预检 RPC |
| 专属属性 | 未提 | 50% 概率,独立 exclusive 字段 | 补充 |
| 套装 | 未提 | 2/4/6/8 件逐级叠加加成 | 补充 EquipComposeDefine |
| 千分比数值 | 未提 | 服务端 attAddEx 用千分比整数 | 数据类型澄清 |
2.4 openspec/changes/port-rok-hero-bag-system/specs/gacha-system/spec.md
| 需修正项 | 当前写法 | ROK 真相 | 建议改法 |
|---|---|---|---|
| 整体定位 | "1:1 移植 ROK 抽卡" | ROK 无抽卡 | 改为"独立扩展功能(非 ROK 移植)" |
| 类比 | 借鉴 ROK 卡池 | ROK 没卡池 | 类比常见 SLG 抽卡(COK / RoK 实际游戏)或参考 gmd 姐妹工程 |
| 优先级 | P1 | 推迟到 P3 或更后 | 降级:先做 ROK 现有的"召唤 + 酒馆",抽卡可作为 P4+ 扩展功能 |
2.5 tasks.md
需要追加的任务:
| 新增章节 | 任务 |
|---|---|
| 2.0 → 改为 2.1 | 抽卡降级到 P3+ |
| 新 2.0 | 「英雄碎片召唤 + 酒馆宝箱」(对应 ROK Hero_SummonHero + Build_Tavern) — 真正的 P1 |
| 4.1 → 替换 | 升星:星级 1-N,溢出 → 星级+1,带幸运双倍机制 |
| 3.4 → 修正 | C2G_CheckMakeEquip + C2G_MakeEquipment 双 RPC |
| 1.11 → 修正 | 通用 Item:保留 RewardEntry,但金币/钻石/资源走 Role 字段 |
3. 推荐实现路径(在 ROK 真相基础上)
3.1 包结构调整
之前 openspec 规划:
cn.etetet.hero # 英雄
cn.etetet.bag # 背包 + 装备
cn.etetet.gacha # 抽卡(ROK 无对应)
根据调研推荐:
cn.etetet.hero # 英雄养成(招募 / 升级 / 升星 / 技能 / 觉醒 / 天赋 / 战力)
cn.etetet.bag # 背包 + 装备(装备是带 heroId 的 Item,不独立分包)
# 锻造放 bag/Forge/ 子目录
cn.etetet.summon # 碎片召唤 RPC(薄薄一层,主要在 hero 内复用)— 可与 cn.etetet.hero 合并
cn.etetet.tavern # 酒馆宝箱(ROK 主要碎片来源)— P2/P3 视优先级
cn.etetet.gacha # 抽卡(独立扩展,非 ROK 移植)— P3+ 或后期
实际可以合并:把 summon 并到 hero 里、tavern 单独包(因为它是独立的 UI 入口 + Build_Tavern 协议)。
3.2 阶段重排(基于 ROK 真相)
| 阶段 | 目标 | 端到端验证 |
|---|---|---|
| P0 | 基础设施(DB / 日志 / GM / 配置 / Luban / 协议) | Login Demo 通 |
| P1 | 英雄招募(碎片召唤 RPC) + 经验升级 + 通用 Item 增删 + 货币变动 | GM AddItem 碎片 30 → SummonHero heroId → 英雄出现,升级 |
| P2 | 升星 + 技能升级 + 装备穿戴 + 战力计算(套装) | GM 完整养成链路 |
| P3 | 觉醒 + 天赋树 + 锻造(双段 RPC)+ 分解 | GM 全养成 + 装备产出闭环 |
| P3+ | 酒馆宝箱(ROK 主要碎片来源) + 雕像兑换 | UI 之前用 GM 验证酒馆 |
| P4 | UI 集中实现(YIUI Panel) | 全功能可视化 |
| P4+ / 可选 | 抽卡扩展(非 ROK 移植,独立设计) | 用户验证产出 |
4. 实现时的"防走样"检查清单
每写一个业务函数前,对照本索引文档 + 对应模块 spec:
- 数据字段名是否跟 ROK(如
getItem不要写成fragmentItemId) - RPC 个数是否对(如锻造 2 个不是 1 个)
- 公式是否照 ROK(如战力公式参考 ROK-Hero-Spec §4.10)
- 错误码段位是否对(3000-3027 Hero,6029-6031 BuildEquip)
- 货币走 Role 字段 vs Item,分得清吗
- 装备槽位映射对吗(8 槽 / 6 subType,accessories 双槽)
- 配置表字段全部翻译到 Luban 了吗(不要漏列)
5. 给用户的建议
5.1 必须先做
- 修正 openspec specs:按本索引 §2 的差异表逐项修正
hero-system/spec.md/bag-system/spec.md/equipment-system/spec.md/gacha-system/spec.md - 调整 proposal.md:抽卡定位明确为"独立扩展,非 ROK 移植"
- 调整 tasks.md:阶段重排(按本索引 §3.2),新增"召唤 + 酒馆"任务
- 调整 design.md D2 包组织:把
cn.etetet.equip合并到cn.etetet.bag
5.2 可以推迟(先不调整)
- ROK 的
雕像兑换/天赋页改名等次要功能可放最后 酒馆宝箱可在 P3 才补(先用 GMAddItem 碎片 N模拟产出)- 抽卡扩展先不做,P1-P3 用 ROK 原版机制(召唤)验证产出
5.3 决策点请确认
| 决策点 | 选项 A | 选项 B | 推荐 |
|---|---|---|---|
| 货币是否进 Item | A. 跟 ROK:金/钻是 Player 字段 | B. 统一 Item:金/钻也是 itemId | A(与 ROK 一致,便于 1:1 迁移) |
| 装备分包 | A. 跟 ROK:装备并入 Bag | B. 独立 cn.etetet.equip 包 |
A(与 ROK 一致) |
| 抽卡优先级 | A. P1 实现(用户要求) | B. P4+ 扩展(避免干扰 1:1 迁移) | B(先把 ROK 跑通,抽卡作为后续创新点) |
| 召唤 + 酒馆放哪 | A. 合并到 hero 包 | B. 独立 cn.etetet.tavern 包 |
A 合并到 hero,酒馆 UI 时再独立 |
确认这些决策后,我可以动手按结论修正 openspec 全部文档。
6. 用户最新决策与统一设计哲学(2026-05-27 确认)
这一节是 ROK 调研之后用户拍板的设计原则。与 ROK 部分实现细节不一致,但作为 Survivors 工程的最终设计哲学,后续 openspec 修改必须以此为准。
6.1 决策汇总
| # | 议题 | 决定 | 与 ROK 关系 |
|---|---|---|---|
| D1 | 货币管理 | 通用 Item:金/钻/木/粮/碎片/英雄道具/装备/材料全部 itemId 管理 | ✗ 与 ROK 不一致(ROK 把货币存 Role 字段) |
| D2 | 装备分包 | 并入 cn.etetet.bag(装备是带 heroId 的 Item) |
✓ 与 ROK 一致 |
| D3 | 抽卡优先级 | 推迟 P4+,先把 ROK 召唤+酒馆跑通 | — |
| D4 | "抽卡 / 召唤" 重新定义 | 抽卡 = 酒馆开盲盒(ItemPackage 机制);召唤 = 英雄碎片 Item → 英雄 Entity 转化 | ✓ 本质与 ROK 一致,抽象更统一 |
6.2 核心抽象:"一切皆 Item,开盲盒即抽卡"
抽象 1:通用 Item
| 范畴 | itemId 示例段位 | 例子 |
|---|---|---|
| 货币类 Item | 1xxxxx (跟 ROK itemId 编码) | itemId=1 金币 / itemId=2 钻石 / itemId=3 木料 / itemId=4 粮食 |
| 资源道具袋 | 1xxxxxxx | 100 金币袋 / 1000 钻石袋(使用时扣道具+加货币 Item) |
| 加速 / 增益 / 杂项 | 2xxx / 3xxx / 5xxx | 训练加速卷、迁城卡、经验书 |
| 装备 / 材料 / 图纸 | 4xxx | 装备本体(count=1+heroId>=0)、材料、图纸 |
| 英雄碎片 | 类似 ROK getItem 编码 |
招募关羽碎片 / 招募张飞碎片 |
| 英雄 Item(新增抽象) | 新增段位 | "直接获得 1 名关羽"道具,使用 → 转化为 Hero Entity |
统一接口(服务端 BagComponentSystem):
// 任何业务发奖、扣资源都走这两个接口
AddItems(List<RewardEntry> rewards)
RemoveItems(List<CostEntry> costs)
HasItems(List<CostEntry> costs)
GetItemCount(itemId)
抽象 2:ItemPackage(开盲盒 / 抽卡 / 礼包统一模型)
输入:消耗 CostEntry 列表 + 一个 packageId
内部:按 PackageConfig.weights 加权随机
输出:RewardEntry 列表(itemId, count)→ 调用 BagComponentSystem.AddItems
ItemPackage 的具体业务化身:
| 业务 | 实现 = 一次 ItemPackage 调用 |
|---|---|
| 酒馆白银宝箱(ROK Build_Tavern silverBox) | 消耗:免费次数 or 银币 / 输出:silverBoxItemPackage 加权产出 |
| 酒馆黄金宝箱(ROK Build_Tavern goldBox) | 消耗:钻石 / 输出:goldBoxItemPackage 加权产出 |
| 邮件附件领取 | 消耗:0 / 输出:邮件配置的 RewardEntry 列表(无随机) |
| 任务奖励 | 同上 |
| 礼包道具使用(gift box) | 消耗:1 个礼包 Item / 输出:固定 / 加权 RewardEntry |
| 未来"抽卡"扩展 | 消耗:抽卡券 or 钻石 / 输出:英雄碎片 / 英雄 Item / 资源等 |
关键洞察:上面 6 种业务底层是同一个函数
ItemPackageSystem.Open(rid, packageId),只是 UI 入口和配置不同。
抽象 3:Item → Entity 转化("召唤"机制)
玩家持有英雄碎片 Item(如关羽碎片 ×30)或英雄 Item(直接获得 1 名关羽)
│ 调用 UseItem 协议
▼
ItemUseHandler 分发(按 ItemDefine.useType / useScript)
│
▼
对于"英雄碎片"类型 Item:
- 校验数量足够(>= getItemNum)
- 校验该 heroId 未被拥有
- HeroComponentSystem.CreateHero(heroId)
- BagComponentSystem.RemoveItems(碎片 × getItemNum)
对于"英雄 Item"类型(直接给英雄):
- 校验该 heroId 未被拥有
- HeroComponentSystem.CreateHero(heroId)
- BagComponentSystem.RemoveItems(英雄 Item × 1)
对于"装备"类型 Item:不可使用(穿戴走另外的 RPC)
对于"经验书"类型 Item:调 HeroComponentSystem.AddExp
对于"金币袋"类型 Item:扣道具 + AddItem 金币 itemId
... 等
关键洞察:ROK 的"召唤" 在 Survivors 不需要独立 RPC,本质就是 UseItem 协议 的一个分支。
6.3 包结构最终方案(基于 D1-D4 决策)
cn.etetet.bag # 核心:Item + RewardEntry + ItemPackage + Forge
├── Scripts/Model/Server/
│ ├── BagComponent.cs # 玩家背包
│ ├── ItemUnit.cs # 通用 Item 单元(含 heroId / exclusive 字段供装备用)
│ ├── ItemPackageConfig.cs # ItemPackage 配置
│ └── CurrencyItemIds.cs # 货币 itemId 常量(1=金币 2=钻石 3=木料 ...)
├── Scripts/Hotfix/Server/
│ ├── BagComponentSystem.cs # AddItems / RemoveItems / HasItems / GetItemCount
│ ├── ItemPackageSystem.cs # Open(packageId) 加权随机 → RewardEntry
│ ├── ItemUseHandler.cs # UseItem 分发(按 useType)
│ ├── Forge/ # 装备锻造子目录
│ └── UseHandlers/ # 各类道具使用 Handler(IItemUseHandler)
│ ├── HeroFragmentUseHandler.cs # 英雄碎片 → 召唤
│ ├── HeroItemUseHandler.cs # 英雄 Item → 直接获得
│ ├── ExpBookUseHandler.cs # 经验书 → 英雄加经验
│ └── CurrencyBagUseHandler.cs # 金币袋 → 加货币
cn.etetet.hero # 英雄养成(升级 / 升星 / 技能 / 觉醒 / 天赋 / 装备穿戴 / 战力)
├── 没有"招募"RPC(招募通过 UseItem 触发,统一入口)
cn.etetet.tavern # 酒馆(ItemPackage 的具体业务应用 + UI 入口)
├── Scripts/Hotfix/Server/
│ └── TavernSystem.cs # OpenSilverBox / OpenGoldBox(内部调 ItemPackageSystem.Open)
(已删除:cn.etetet.gacha / cn.etetet.equip / cn.etetet.summon — 通通不需要)
6.4 设计哲学相比 ROK 的"升级点"
| 维度 | ROK 原版 | Survivors 升级 | 收益 |
|---|---|---|---|
| 货币管理 | Role 字段 + Item 双轨制 | 全部 Item(itemId 段位区分) | 接口统一,避免每种货币都写一遍 add/remove |
| 道具使用 | ItemLogic 巨型 if/elseif | IItemUseHandler 注册机制 | 新增道具类型加一个 Handler 类,零修改老代码 |
| 抽卡 / 宝箱 / 礼包 | 分散在 ItemLogic / Tavern / 各业务 | 统一 ItemPackage 机制 | 一处实现,N 处复用 |
| 召唤 | 独立 Hero_SummonHero 协议 | UseItem 分支 | 协议数量减少,玩家行为路径统一 |
6.5 与 openspec 现有 spec 的对应调整(待用户读完文档后执行)
| openspec 文档 | 主要修改 |
|---|---|
proposal.md |
抽卡定位 → 推迟 P4+;新增 ItemPackage 抽象说明;包结构按 6.3 重写 |
design.md D2 |
包列表按 6.3;删 gacha/equip/summon |
design.md 新增 D14 |
ItemPackage 设计;Item→Entity 转化机制 |
specs/bag-system/spec.md |
通用 Item 覆盖货币;新增 ItemPackage 章节;新增 ItemUseHandler 注册机制;装备并入此 spec(不再分文件) |
specs/hero-system/spec.md |
删"招募 RPC",改为"通过 UseItem 触发";字段名跟 ROK;战力公式引用 Doc/ROK-Hero-Spec.md |
specs/equipment-system/spec.md |
合并进 specs/bag-system/spec.md 作为子章节("装备子系统");删独立文件 |
specs/gacha-system/spec.md |
删除,被 ItemPackage 抽象替代;后续做扩展抽卡时再起新 change |
tasks.md |
P0/P1 阶段重排;新增 ItemPackage 任务;新增 ItemUseHandler 注册任务;删独立 gacha/equip 任务 |
7. 调研未覆盖的次要功能(按需补充)
如有需要再单独调研:
Build_Tavern协议详细(酒馆开宝箱完整流程) — 需要时去看proxy/Build.luaresponse.Tavern- 雕像兑换
Hero_ExchangeHeroItem—proxy/Hero.lua - 行动力减免与技能关联 —
HeroLogic.lua+ 战斗服务器 - 限时礼包触发
RechargeLogic.triggerLimitPackage— 与英雄关联但非英雄本身 - 红点系统在客户端 —
BagProxyPlayerPrefs 部分