9.4 KiB
Raw Blame History

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 RewardEntryrepeated 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 创建客户端缓存
  • ANDItemType 分类放入对应子缓存resourceItems/speedupItems/...

Scenario: 增量更新单个道具

  • WHEN 服务端推送 Item_ItemInfo { item }
  • THEN 客户端按 itemIndex 找到对应缓存
  • AND 若 count > 0 更新;若 count == 0 移除
  • AND 触发 OnItemChanged(itemId) 事件

Requirement: 道具大类与堆叠规则

系统 MUST 提供 6 大类道具类型(BagItemTypeResource(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 显示穿戴/卸下按钮