189 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## ADDED Requirements
### Requirement: 通用 Item 数据模型(全游戏统一)
系统 MUST 用统一的 `ItemConfig` 表示**所有**游戏内可获得的资源——包括但不限于金币、钻石、英雄碎片、装备、装备材料、装备图纸、经验书、升星石、觉醒符文、礼包、邮件附件、活动奖励。`ItemConfig` MUST 至少包含字段iditemId、name、icon、itemTypeBagItemType 大类、subType细分类如 EquipItemType 或货币子类、maxStack堆叠上限0 表示不限、useType使用行为如 HeroExp/HeroStarExp/Gift/None、quality品质 1-5、desc、sortIndex。
#### Scenario: 金币也是 Item
- **WHEN** 玩家获得 100 金币
- **THEN** 服务端调用 `BagComponentSystem.AddItem(player, itemId=1 /* 金币的固定 itemId */, 100)`
- **AND** 前端 `BagComponent` 中存在 itemId=1 的 ItemInfo
- **AND** UI 通过 `BagItemUICommon.Show(itemId=1, count=100)` 渲染图标和数量
#### Scenario: 钻石使用同一套接口
- **WHEN** 玩家抽卡消耗 10 钻石
- **THEN** 服务端调用 `BagComponentSystem.RemoveItem(player, itemId=2 /* 钻石的固定 itemId */, 10)`
- **AND** 不需要任何"特殊货币处理逻辑"
#### Scenario: 不允许新增非 Item 资源
- **WHEN** 业务需要引入新资源类型(如新货币)
- **THEN** MUST 通过新增 ItemConfig 条目实现,不允许在 Player Entity 上添加新字段
### Requirement: 通用奖励/消耗结构
系统 MUST 提供统一的奖励/消耗描述结构 `RewardEntry { itemId, count }``CostEntry { itemId, count }`(结构相同,命名上分语义)。所有"列表型奖励/消耗"业务 MUST 使用 `repeated RewardEntry``repeated CostEntry`,包括但不限于:抽卡奖励列表、升级消耗、升星消耗、技能升级消耗、礼包道具列表、邮件附件、关卡奖励、商店售卖、活动签到奖励。
#### Scenario: 升级消耗用 CostEntry
- **WHEN** `HeroSkillLevelConfig` 配置技能升级消耗
- **THEN** 字段类型 MUST 是 `repeated CostEntry`(例:`[{ itemId: 2001, count: 5 }, { itemId: 1, count: 100 }]`
- **AND** 服务端通过 `BagComponentSystem.RemoveItems(player, costs)` 批量扣除
- **AND** 任一项不足则全部失败,不扣任何道具
#### Scenario: 抽卡奖励用 RewardEntry
- **WHEN** 抽卡响应包含奖励列表
- **THEN** 字段类型 MUST 是 `repeated RewardEntry`
- **AND** 服务端通过 `BagComponentSystem.AddItems(player, rewards)` 批量发放
### Requirement: 通用道具 UI 组件
客户端 MUST 提供 `BagItemUICommon` YIUI UICommon输入 `(itemId, count, optional: showName, showCount, sizePreset)`,自动渲染图标、品质边框、数量、新道具标记。该组件 MUST 被所有道具相关 UI 复用:背包列表、抽卡结果、奖励飘字、邮件附件、商店货品、关卡结算、签到奖励。
#### Scenario: 抽卡结果显示
- **WHEN** GachaResultPanel 渲染 10 个奖励
- **THEN** 为每个奖励实例化一个 BagItemUICommon
- **AND** 调用 `Show(reward.itemId, reward.count)`
#### Scenario: 邮件附件显示
- **WHEN** 邮件面板渲染附件列表
- **THEN** 复用相同的 BagItemUICommon
- **AND** 不需要重写道具图标渲染逻辑
### Requirement: Bag 数据模型
系统 MUST 为每个玩家提供一个 `BagComponent` 挂在玩家根 Entity 下。`BagComponent` MUST 维护一个 `ItemInfo` 列表,每个 `ItemInfo` 持有itemIndex全局唯一索引、itemId对应 `ItemConfig.id`、count数量/堆叠、itemType大类、heroId仅装备类有效归属英雄
#### Scenario: 注入背包数据
- **WHEN** 玩家登录后服务端推送 `Item_ItemInfoList { items }`
- **THEN** 客户端 `BagComponent` 清空旧 items 列表
- **AND** 为每个 ItemInfo 创建客户端缓存
- **AND** 按 `ItemType` 分类放入对应子缓存resourceItems/speedupItems/...
#### Scenario: 增量更新单个道具
- **WHEN** 服务端推送 `Item_ItemInfo { item }`
- **THEN** 客户端按 itemIndex 找到对应缓存
- **AND** 若 count > 0 更新;若 count == 0 移除
- **AND** 触发 `OnItemChanged(itemId)` 事件
### Requirement: 道具大类与堆叠规则
系统 MUST 提供 6 大类道具类型(`BagItemType`Resource(1) / Speedup(2) / Boost(3) / Equipment(4) / Other(5) / Icon(6)。
- 非 Equipment 类道具 MUST 按 itemId 堆叠(同 id 累加 count
- Equipment 类道具 MUST 每个独立 itemIndex不堆叠即使同 itemId
#### Scenario: Resource 类堆叠
- **WHEN** 玩家已有 itemId=1001 数量 50
- **AND** 服务端发放 100 个 itemId=1001
- **THEN** 服务端 MUST 更新该道具 count 为 150不创建新条目
#### Scenario: Equipment 类不堆叠
- **WHEN** 玩家拥有 1 件 itemId=8001 装备
- **AND** 服务端发放另 1 件相同 itemId 装备
- **THEN** 服务端 MUST 创建新 itemIndex 条目count=1
- **AND** 两个装备实例独立存在
### Requirement: 道具数量查询
客户端 MUST 提供以下查询接口:
- `BagComponentExtensions.GetItemNum(itemId)` 返回某 itemId 的总数(非装备类)
- `BagComponentExtensions.GetItemIndex(itemId)` 返回单条目的 itemIndex非装备类
- `BagComponentExtensions.GetItemInfoListByType(BagItemType)` 返回某类下所有 ItemInfo
- `BagComponentExtensions.HasItem(itemId, requiredCount)` 判断是否足够
#### Scenario: 查询道具数量
- **WHEN** 玩家拥有 itemId=2001 数量 30
- **AND** 调用 `GetItemNum(2001)`
- **THEN** 返回 30
#### Scenario: 查询不存在的道具
- **WHEN** 玩家未拥有 itemId=9999
- **AND** 调用 `GetItemNum(9999)`
- **THEN** 返回 0不抛异常
### Requirement: 道具使用
玩家 MUST 能消耗指定数量道具触发其效果。可使用道具由 `ItemConfig.useType` 标识。服务端 MUST 是真权威,校验所有使用操作。
#### Scenario: 使用经验书
- **WHEN** 玩家发送 `C2G_UseItem { itemId, count }`
- **AND** `ItemConfig.useType == HeroExp`
- **AND** 玩家拥有 >= count
- **THEN** 服务端转发到对应处理器(如 HeroAddExp
#### Scenario: 使用礼包道具
- **WHEN** 玩家使用 useType=Gift 类道具
- **THEN** 服务端按 `ItemConfig.giftRewards` 发放奖励
- **AND** 扣除礼包道具
- **AND** 推送多个 `Item_ItemInfo` 同步所有变化
#### Scenario: 使用数量不足
- **WHEN** 玩家请求使用 5 个道具,但只有 3 个
- **THEN** 服务端 MUST 拒绝并返回 `ItemNotEnough`
### Requirement: 服务端道具增减接口
服务端 MUST 提供以下基础接口给业务调用(如 Hero/Equipment 模块),所有变更 MUST 推送 `Item_ItemInfo`
- `BagComponentSystem.AddItem(itemId, count)` 增加道具
- `BagComponentSystem.RemoveItem(itemId, count)` 减少道具,返回是否成功
- `BagComponentSystem.RemoveItemByIndex(itemIndex)` 按索引删除(用于唯一装备)
- `BagComponentSystem.SetHeroIdOnEquip(itemIndex, heroId)` 装备绑定/解绑英雄
#### Scenario: 增加道具触发同步
- **WHEN** 服务端业务调用 `AddItem(itemId=1001, 50)`
- **THEN** 修改 BagComponent
- **AND** 标记脏数据待落库
- **AND** 推送 `Item_ItemInfo { itemId=1001, count=新count }`
#### Scenario: 扣除道具失败
- **WHEN** 业务调用 `RemoveItem(itemId, count)` 但数量不足
- **THEN** 返回 false
- **AND** 不修改任何数据
- **AND** 不推送消息
### Requirement: 新道具标记
客户端 MUST 维护"新到道具"红点标记,用 ISave 本地存储(避免与服务端通信开销)。当 BagComponent 接收到新 itemId 或 count 增加时MUST 自动标记 `isNew`。当玩家在 UI 中浏览过该道具MUST 标记为已读。
#### Scenario: 获得新道具标记
- **WHEN** 服务端推送 `Item_ItemInfo` 增加 itemId=5001之前为 0
- **THEN** 客户端 MUST 在本地 ISave 中标记 `isNew[5001] = true`
#### Scenario: 浏览后清除标记
- **WHEN** 玩家在 BagPanel 中点击查看 itemId=5001
- **THEN** 客户端 MUST 调用 `SetLocalItemToOld(5001)`
- **AND** 红点消失
### Requirement: 背包红点
系统 MUST 提供按类型聚合的红点接口:
- `GetBagReddotNumByType(BagItemType)` 返回某类新道具数量
- `GetBagReddotTotal()` 返回所有类型新道具总数
- `ClearAllReddotRecord()` 清空所有红点
#### Scenario: 分类红点
- **WHEN** 玩家有 3 个新 Resource 道具 + 2 个新 Equipment 道具
- **AND** 客户端调用 `GetBagReddotNumByType(BagItemType.Resource)`
- **THEN** 返回 3
### Requirement: UI 列表分页与循环加载
背包 UI MUST 使用 `cn.etetet.yiuiloopscrollrectasync` 实现循环列表支持万级道具不卡顿。MUST 按类型分页Resource/Speedup/Boost/Equipment/Other 各为一页),每页内按 `ItemConfig.sortIndex` 排序。
#### Scenario: 切换到装备页
- **WHEN** 玩家点击 BagPanel 上"装备"分页按钮
- **THEN** UI 加载 `BagComponent.equipItems` 数据源
- **AND** 通过 `LoopScrollRect` 异步刷新可见格子
### Requirement: 道具详情 Tooltip
点击道具 MUST 弹出 `BagItemTooltip` 浮层,显示:图标、名称、品质边框、描述、堆叠数量、使用按钮(若可用)、来源跳转入口。
#### Scenario: 显示 Tooltip
- **WHEN** 玩家点击背包格子
- **THEN** 在格子位置/右侧弹出 BagItemTooltip
- **AND** 显示对应 ItemConfig 的全部信息
#### Scenario: 装备 Tooltip 显示属性
- **WHEN** 点击的是 Equipment 类道具
- **THEN** Tooltip 显示装备属性条目(攻击/防御/血量等)
- **AND** 显示穿戴/卸下按钮