## ADDED Requirements ### Requirement: Protobuf 协议定义文件 所有客户端-服务端 Hero/Bag/Equipment 消息 MUST 在新的 proto 文件中定义,存放路径 `Packages/cn.etetet.<新业务包>/Proto/Outer_C_.proto`。MUST 遵循 ET 框架已有命名规则:消息名 `C2G_xxx` 表示客户端→Gate,`G2C_xxx` 表示 Gate→客户端,`xxx_yyy` 表示推送消息(无 RpcId)。 #### Scenario: 协议文件结构 - **WHEN** 创建 `HeroOuter_C_3000.proto` 文件 - **THEN** 文件头部 MUST 声明 `syntax = "proto3"` 和 `package ET` - **AND** 注释每个消息的 `ResponseType` 用于 ET Proto2CS 工具识别 - **AND** 该文件起始消息 ID = 3000,每个 message 顺序 +1 ### Requirement: 数据传输对象 (DTO) 协议层 MUST 定义以下核心 DTO 结构供 RPC 和推送使用: - `HeroInfo`: heroId (int64), configId (int32), level, exp, star, starExp, talentIndex, skills (repeated SkillInfo), talentTrees (repeated TalentTreeInfo), equipSlots (repeated EquipSlot) - `SkillInfo`: skillId (int32), skillLevel (int32) - `TalentTreeInfo`: pageIndex (int32), name (string), nodes (repeated TalentNodeInfo) - `TalentNodeInfo`: nodeId (int32), level (int32) - `EquipSlot`: subType (int32), itemIndex (int64, 0 表示空) - `ItemInfo`: itemIndex (int64), itemId (int32), count (int64), itemType (int32), heroId (int64) #### Scenario: 序列化 HeroInfo - **WHEN** 服务端构造 HeroInfo 并通过 `MessageHelper.SendToClient` 发送 - **THEN** ET 框架自动使用 MemoryPack 序列化 - **AND** 客户端反序列化得到等价 HeroInfo 实例 ### Requirement: 客户端→服务端 RPC 消息 协议层 MUST 包含以下 12 个 Hero/Equipment 业务 RPC(每个有 `ResponseType` 声明): | RPC 名 | 说明 | |---|---| | C2G_SummonHero | 召唤英雄 | | C2G_HeroAddExp | 加经验升级 | | C2G_HeroStarUp | 升星 | | C2G_HeroSkillUp | 技能升级 | | C2G_HeroAwake | 觉醒 | | C2G_TalentUp | 学天赋 | | C2G_ChangeTalentIndex | 切换天赋页 | | C2G_ResetTalent | 重置天赋页 | | C2G_ModifyTalentName | 修改天赋页名 | | C2G_HeroWearEquip | 穿装备 | | C2G_TakeOffEquip | 卸装备 | | C2G_ExchangeHeroItem | 雕像兑换碎片 | Bag/Equipment 业务额外 RPC: | RPC 名 | 说明 | |---|---| | C2G_UseItem | 使用道具 | | C2G_MakeEquipment | 锻造装备 | | C2G_ResolveEquipment | 分解装备 | | C2G_MixMaterial | 合成材料 | #### Scenario: 每个 RPC 都有错误码字段 - **WHEN** 定义任一 `G2C_xxx` Response - **THEN** MUST 包含 `int32 Error` 和 `string Message` 字段 - **AND** Error 0 = 成功,非 0 = 失败码 ### Requirement: 服务端→客户端推送消息 协议层 MUST 包含以下推送消息(无 RpcId、不需要回应): - `Hero_HeroInfo { HeroInfo hero }` - 单个英雄数据变化 - `Hero_HeroInfoList { repeated HeroInfo heroes }` - 全量英雄列表(登录后) - `Item_ItemInfo { ItemInfo item }` - 单个道具数量变化 - `Item_ItemInfoList { repeated ItemInfo items }` - 全量道具列表(登录后) - `Item_RemoveItem { int64 itemIndex }` - 道具被完全移除 #### Scenario: 登录后全量同步 - **WHEN** 玩家通过 `C2G_LoginGate` 登录到 Gate 成功 - **THEN** 服务端 MUST 在 200ms 内推送 `Hero_HeroInfoList` 和 `Item_ItemInfoList` - **AND** 客户端按顺序更新两个 Component 缓存 #### Scenario: 业务操作后增量推送 - **WHEN** 服务端处理任意 Hero/Bag 业务请求成功后 - **THEN** MUST 在响应中或之后立刻推送相关 `Hero_HeroInfo` / `Item_ItemInfo` - **AND** 推送的数据是该操作影响的完整快照(不是 delta diff) ### Requirement: 错误码统一定义 所有 Hero/Bag/Equipment 错误码 MUST 在 `Packages/cn.etetet.login/Scripts/Model/Share/ErrorCode.cs` 或新增 `HeroBagErrorCode.cs` 中集中定义为 `public const int xxx`。命名规则:`ERR__`。 #### Scenario: 错误码示例 - **WHEN** 服务端拒绝因碎片不足的招募请求 - **THEN** 返回 `error = ERR_HERO_ITEM_NOT_ENOUGH` - **AND** 客户端按错误码查表显示本地化文案 ### Requirement: 消息 ID 分配 新协议 MUST 占用尚未使用的消息 ID 段(避开 1000 Login / 1100 Router / 11001 StateSync 等已用段)。建议使用 3000-3999 段。 #### Scenario: ID 段不冲突 - **WHEN** 通过 `ET/Proto/Proto2CS` 工具生成代码 - **THEN** 工具 MUST 检查 ID 不与现有 proto 冲突 - **AND** 若冲突则编译失败并提示 ### Requirement: 协议代码生成 新增 proto 文件后 MUST 通过 ET 工具菜单 `ET/Proto/Proto2CS` 生成 C# 代码到 `Packages/cn.etetet.proto/CodeMode/Model/{Client|Server|ClientServer}/Outer_C_.cs`。生成的代码 MUST 自动注册到 ET 的 MessageDispatcher。 #### Scenario: 重新生成不破坏现有代码 - **WHEN** 修改 proto 文件后再次运行 Proto2CS - **THEN** 工具 MUST 完全覆盖旧的生成 .cs 文件 - **AND** 不影响业务 Handler 代码(Handler 是手写的) ### Requirement: Handler 注册 所有 RPC 消息 MUST 有对应的服务端 Handler 类,命名规则 `C2G_Handler`,挂 `[MessageHandler(SceneType.Gate)]` 特性。Handler 类 MUST 实现 `MessageSessionHandler` 模板。 #### Scenario: 消息路由 - **WHEN** 客户端发送 `C2G_SummonHero` - **THEN** Gate Scene 的 MessageDispatcher 路由到 `C2G_SummonHeroHandler.Run()` - **AND** Handler 通过 `session.GetComponent().Player` 获取玩家 - **AND** 修改业务后返回 Response