XtGameKit/Doc/ROK-Bag-Spec.md

47 KiB
Raw Blame History

ROK 背包/道具系统业务规则1:1 迁移依据)

来源:E:\Game\gmd\ROK 服务端 LuaItemLogic.lua / Item.lua proxy+ 客户端 C#BagProxy.cs / BagMediator.cs / PlayerCmd.cs / ItemConfig.cs / ItemEnum.lua / Common.sproto / ErrorCode.cs 用途:作为 Survivors 工程 cn.etetet.bag 包实现的业务依据,不直接复制源代码,只摊开业务规则与数据结构 调研时间2026-05-27 关键约定:表名加 s_ 前缀(如 s_Item)的为服务端 ConfigEntity客户端对应 ItemDefineItemPackageDefine


1. 整体业务范围

# 子模块 一句话定位
1 通用道具增/删 ItemLogic:addItem / delItem / delItemById / checkItemEnough,所有业务发奖/扣道具的唯一入口
2 道具分类 服务端 Enum.ItemType6 类HEAD 不入背包);客户端 BagItemType5 个 Tab
3 堆叠规则 非装备同 itemId 合并到同一 itemIndex;装备每件独立 itemIndexoverlay=1
4 道具使用 Item.lua:response.ItemUse,按 s_Item.itemFunction 分支 if/elseif 处理(无独立脚本表
5 资源类道具兑换 Item.lua:response.ItemChangeResource,把"资源类道具"换成等额玩家货币(金币/木料/粮食/VIP/行动力)
6 礼包/选包奖励 ItemLogic:getGroupPackage / giveReward / getItemPackage + s_ItemPackage + s_ItemRewardChoice
7 新道具/红点标记 服务端不存,全部用 PlayerPrefs 在客户端持久化(按 rid + itemIndex
8 头像框解锁 Enum.ItemType.HEAD 类型道具不进背包,直接走 RoleLogic:unlockRoleHead
9 资源货币 粮/木/石/金/宝石/行动力/VIP/远征币等作为 Role 字段存储,不进 Item 表(详见 §5.7
10 同步推送 唯一同步协议 Item_ItemInfo30101增量推
11 创角初始道具 s_Config.initialItemType + initialItemNum 硬编码 8 个道具
12 资源阈值告警 s_GameWarning.num 单道具数量超阈值时 Common.sendResourceAlarm 给运营
13 日志审计 每次增删都 LogLogic:itemChange(rid, iggid, itemId, changeNum, oldNum, newNum, logType, logType2)

⚠️ ROK 工程中没有 ItemScript.lua 实质实现——同名文件只剩 3 个空函数。所有"道具使用脚本"逻辑都在 Item.lua proxy 的 ItemUse 函数里用 if/elseif (sitem.itemFunction) 巨型分支硬编码。


2. 道具分类 BagItemType

2.1 服务端 Enum.ItemTypeItemEnum.lua

名称 含义 是否入背包 备注
RESOURCE 1 资源(金/木/石/粮/宝石/VIP/行动力类道具袋) 通过 Item_ItemChangeResource 兑换玩家货币字段
SPEED 2 加速(建筑/训练/研究/治疗/通用 5 类) 在各功能界面用,背包 Tab2
GAIN 3 增益(采集加成/护盾/反侦察/部队扩编等) 大多对应 City BuffTab3
EQUIP 4 装备(武器/头盔/胸甲/手套/裤/鞋/饰品 + 装备材料 + 图纸) 每件独立 itemIndex
OTHER 5 其他(改名卡、迁城卡、经验书、英雄雕像、钥匙等) 杂项 Tab
HEAD 6 头像框 addItem直接走 RoleLogic:unlockRoleHead 返回空 syncInfo

itemId 编码约定:客户端 BagProxy.GetItemTypeById(itemId) = (int)itemId / 100000000,即 itemId 最高位决定 type。

  • 1xxxxxxxx → RESOURCE101010001
  • 2xxxxxxxx → SPEED (如 201010010
  • 3xxxxxxxx → GAIN
  • 4xxxxxxxx → EQUIP (如 401010001 材料、401020001 装备)
  • 5xxxxxxxx → OTHER (如 502030004 改名卡、502070001 经验书)

2.2 客户端 BagItemTypeBagProxy.cs

名称 UI Tab 与服务端关系
Resource 1 资源 == ItemType.RESOURCE
Speedup 2 加速 == ItemType.SPEED
Boost 3 增益 == ItemType.GAIN
Equipment 4 装备 == ItemType.EQUIP
Other 5 其他 == ItemType.OTHER
Icon 6 不显示 == ItemType.HEAD实际客户端 BagPanel 只 5 个 Tab

BagMediator 实测只显示 5 个 Tab1-5HEAD 类型在 for i = 1; i < 6 循环里被略过。

2.3 Enum.ItemSubType46 个细分子类型,关键值)

ItemEnum.lua 中所有 subType 都是 5 位数:

段位 含义 示例
101xx RESOURCE 子类 10101=VIP, 10102=GOLD, 10103=STONE, 10104=WOOD, 10105=GRAIN
201xx SPEED 子类 20101=全加速, 20102=建筑, 20103=训练, 20104=研究, 20105=治疗
301xx GAIN 子类 30101-30111 各种产出/Buff
401xx 装备材料 40101 羽毛 / 40102 皮革 / 40103 铁石矿 / 40104 兽骨 / 40105 水晶 / 40106 丝绸 / 40107 乌木
402xx 装备本体 40201=武器/40202=头盔/40203=胸甲/40204=手套/40205=裤/40206=鞋/40207=饰品
403xx 装备图纸 40301-40307 对应 7 个部位
501xx-509xx OTHER 杂项 50101=经验书 / 50201=改名卡 / 50202=工人招募 / 50203=迁城 / 50204=钥匙 / 50205=文明更换 / 50206=天赋重置 / 50207=建筑升级 / 50208=行动力 / 50301-50304=升星材料 / 50305=技能材料 / 50901=英雄雕像

2.4 每类道具的堆叠/唯一性特征

堆叠 maxStack 唯一字段
装备 (isEquipItem(subType) == true,即 40201/40202/40203/40204/40205/40206/40207) 每件独立 1强制 itemIndex + exclusive(专属英雄)+ heroId(穿戴者)
其他全部 无限叠 代码中无 maxStack 限制overlay int 累加) 只按 itemId 合并到同一 itemIndex

⚠️ 没有 maxStack 限制addItem 只在装备分支才循环创建多条;其他都是 overlay = oldOverlay + itemNum 直接累加。配置表 ItemDefine没有 maxStack 字段


3. Item 数据模型

3.1 .ItemInfo sprotoCommon.sproto L308

字段 类型 含义
itemIndex integer 背包槽位,自增正整数,玩家维度唯一(getFreeItemIndex 找最小空位)
uniqueIndex integer 唯一索引(实测 Lua 中未使用,可能为后续扩展预留)
itemId integer 道具配置 ID关联 s_Item.ID
overlay integer 叠加数量(装备恒为 1
exclusive integer 装备专属标志,0 不专属;非 0 时表示绑定英雄 ID影响装备分解和穿戴
heroId integer 当前穿戴此装备的英雄 ID0 = 未穿戴)

3.2 服务端存储(MSM.d_item[rid] snax service

MSM.d_item[rid].req 提供的操作:

  • Get(rid) → 全部 items dict
  • Get(rid, itemIndex) → 单条
  • Get(rid, itemIndex, fields) → 部分字段
  • Set(rid, itemIndex, field, value) → 改单字段
  • Add(rid, itemIndex, itemInfo) → 新增
  • Delete(rid, itemIndex) → 删除

Enum.Item 字段名常量:itemIndex / itemId / overlay / exclusive / heroId(即 ItemInfo 5 字段)

3.3 客户端缓存(BagProxy.cs

public Dictionary<Int64, ItemInfoEntity> Items;     // itemIndex → 道具实体
private List<ItemInfoEntity> m_itemList;            // 顺序列表
private Dictionary<Int64, int> m_itemNumMap;        // itemId → 累计数量(懒计算,-1 表示需重算)
private Dictionary<long, ItemInfo> m_materialItemInfos; // 装备材料分组
private Dictionary<long, ItemInfo> m_equipItemInfos;    // 装备本体分组
private Dictionary<int, Dictionary<long, long>> m_reddotRecord;  // type → (itemIndex → 新增数量)
private Dictionary<int, long> m_reddotTotalDic;     // type → 红点总数缓存

派生类:

  • ItemInfo 基础:ItemIndex / ItemID / ItemNum / ItemType / HeroID
  • EquipItemInfo : ItemInfo 额外:Exclusive / Order / Group(来自 EquipDefine
  • MaterialItem : ItemInfo 额外:MaterialDefine + MaterialTypeMaterial / Equip / Drawing / DrawingMaterial

3.4 新道具标记存储(纯客户端 PlayerPrefs

Key 格式:{rid}/itemIndex:{itemIndex} → int

含义
不存在 还没在客户端被看到
1 新道具(红点亮)
-1 旧道具(已被标记/查看过)
0 已清除

特殊情况:装备 heroId != 0(已穿戴)→ 强制 SetLocalItemToOld,不亮红点。


4. 配置表清单

4.1 ItemDefineItemConfig.cs,对应服务端 s_Item

字段 类型 含义
ID int 主键,道具 ID同 itemId
l_nameID int 道具名称语言包 ID
l_tipsID int tips 道具名称语言包 ID
subType int 子分组标签(Enum.ItemSubType5 位数)
type int 功能分组(Enum.ItemType1-6
l_typeDes int 功能分组语言包
typeGroup int 类型组装备页用1=Material 2=Equip 3=Drawing 4=DrawingMaterial
itemIcon string 道具图标资源路径
lv int 使用等级要求(实测大部分==0
quality int 品质 1-5白/绿/蓝/紫/橙,对应 Enum.ItemQualityType
batchUse int 是否可批量使用(Enum.ItemBatchUse0/1
l_buttonDes int 按钮文字语言包(<1 表示无按钮)
itemFunction int 道具功能类型,对应 Enum.ItemFunctionType(见 §4.2
data1 int 功能参数 1数值如 VIP 加多少点/兑换比例)
data2 int 功能参数 2关联 IDs_ItemPackage group ID / s_ItemRewardChoice ID / cityBuff ID
l_desID int 道具描述语言包(string.format(text, desData1, desData2)
desData1 int 描述参数 1
desData2 int 描述参数 2
l_topID int 图标顶部信息语言包(<1 不显示)
topData int 顶部信息参数
get List<int> 获得途径列表,关联 s_ItemGet
shortcutPrice int 快捷使用价格(钻石购买后直接使用,用于行动力/VIP 道具)
shopPrice int 商城道具价格
redDotPrompt int 是否要红点提示0/1
rank int 显示排序(背包内同 type 按 rank 升序rank 相同按 itemId 升序)

⚠️ 没有 maxStack / bind / tradeable 字段(与同名 IGG 老项目 item.json 形成对比,那个有 MaxNum / CanTrade / IsDecompose,但不是 ROK 用的)。

4.2 Enum.ItemFunctionType 枚举(核心扩展点

名称 服务端处理(Item.lua:ItemUse 客户端处理(BagMediator.BtnOperate + PlayerCmd
0 NOT_USE 直接返回 ITEM_NOT_USE 错误 无按钮
1 OPEN_ITEMPACKAGE 调用 getItemPackage(data2) 发奖(data2 = s_ItemPackage group 直接发请求
2 CHOOSE_ITEMPACKAGE 校验 s_ItemRewardChoice[data2][id],按选择 ID 发对应 reward BagGiftOpenViewShowType=1让玩家选
3 RECYCLE 同 OPEN_ITEMPACKAGE用 data2 兑换包) BagGiftOpenViewShowType=2确认兑换
4 CITY_BUFF RoleLogic:addCityBuff(data2) 加 buff m_cityBuffProxy.SendUseItem(data2, 1, cb)
5 VIP RoleLogic:addVip(data1 * itemNum) 走 VIP 满级校验后直接发
6 ACTION_FORCE RoleLogic:addActionForce(data1 * itemNum) 直接发
10 KINGDOM_MAP DenseFogLogic:openNearDenseFog(pos),开雾失败则 getItemPackage(data2) 补偿 检测迷雾,否则弹 OpenFogShow 让玩家选位置;返回奖励则弹 ItemCollection
12 SUMMON_MONSTER MSM.MonsterSummonMgr.req.summonMonster(data2) 召唤野怪 关闭背包,相机飞向召唤点,播放召唤特效
13 SECONDE_QUEUE 工人小屋:满建造队列则发 data2 补偿;否则 BuildingLogic:unlockQueue(workQueueTime) 根据 result.status 分别提示成功/延长/补偿
14 TRAIN_NUM 预备部队增容:itemAddTroopsCapacity = data1itemAddTroopsCapacityCount += itemNum 若已有不同档位 data1 则二次确认
35 LEAGUE_POINTS 校验入盟后 GuildLogic:addGuildCurrency(leaguePoints, data1*num),返回 rewardInfo.leaguePoints 直接发
7 (客户端独有)跳转界面 SystemOpen.IsCanOpenByUiId(data1) + OpenUI2(data1, data2)
17 (客户端独有)暂未实现 Tip 提示"暂未开放"
30 (客户端独有)通用迁城 MoveCity 界面
31 (客户端独有)随机迁城 二次确认后发 Map_MoveCity{type=4}

关键约束:服务端枚举值与客户端的 BtnOperate 分支必须一一对应,新增 itemFunction 时两边都要改。

4.3 其他 Item 相关 Define

客户端类 服务端表 用途
ItemPackageDefine s_ItemPackage 奖励组(按 randomGroup 分组随机,含 type/typeData/odds/number/civilization_limit/numberStep_lv/numberStep_increment/numberFloat_min/numberFloat_max
ItemRewardChoiceDefine s_ItemRewardChoice 选包奖励配置(按 data2 关联,每条 {id, reward} 表示一个选项对应的 itemPackage group
ItemHeroDefine s_Hero 关联 英雄相关道具映射(英雄碎片 → 英雄 ID
ItemGetDefine s_ItemGet 获得途径配置(关联 ItemDefine.get[]
ItemPackageShowDefine s_ItemPackageShow 礼包展示配置
ItemPlayerHeadDefine s_ItemPlayerHead 头像框配置
EquipDefine s_Equip 装备本体配置(含 makeMaterial / makeMaterialNum / order / group
EquipMaterialDefine s_EquipMaterial 装备材料配置(含 mix / split / mixCostNum 用于合成分解)

4.4 配置条目数

ROK 客户端使用 SQLite/Bin 序列化(Assets/StreamingAssets/Config/Bin/Item.bin ≈ 87KB没有可读的 item.jsongmd/Unity/Assets/Bundles/Config/item.json 是另一个老项目残留(字段为 MaxNum / CanTrade / FunctionID 等,与 ROK 完全不同结构),不属于本次调研范围

实际条目数无法从源代码直接计数,但根据 itemId 编码5 个一级类 × 数百子分类)+ initialItemType 已出现 502070003201010013 等量级,估算总条目数在 200-500 范围

4.5 ItemPackageType 奖励类型枚举(s_ItemPackage.type

名称 typeData 含义
0 NONE
100 CURRENCY Enum.CurrencyTypefood/wood/stone/gold/denar/actionForce/vip/expeditionCoin/individualPoints/leaguePoints/activityActivePoint
200 ITEM s_Item.ID(普通道具)
300 SOLDIER s_Arms.ID
400 HERO s_Hero.ID
500 SUB_ITEM_TYPE Enum.ZeroEmptyType.SUB_ITEM_TYPE 关联表 ID再从子表 Random 出具体 itemId
600 GUILD_GIFT 联盟礼物类型

4.6 CurrencyTypeOtherEnum.lua L101不属于 Item是 Role 字段

名称 含义
100 food 粮食
101 wood 木材
102 stone 石料
103 gold 金币
104 denar 宝石(钻石)
105 actionForce 行动力
106 individualPoints 联盟个人积分
107 leaguePoints 联盟积分
108-111 allianceFood/Wood/Stone/Gold 联盟资源
112+ vip / expeditionCoin / activityActivePoint VIP 点 / 远征币 / 活动积分

5. 业务规则详细

5.1 添加道具 ItemLogic:addItem(args)

入参 args 表:{rid, itemId, itemNum=1, exclusive=nil, noSync=nil, eventType=nil, eventArg=nil}

流程ItemLogic.lua L69-164

  1. s_Item:Get(itemId),不存在 → LOG_ERROR 返回 nil
  2. 特殊分支:若 sitemInfo.type == HEAD,调 RoleLogic:unlockRoleHead(rid, itemId) 解锁头像框后直接返回 {},不进背包
  3. 是否堆叠
    • 装备类isEquipItem(subType) = subType 在 ARMS/HELMET/BREASTPLATE/GLOVES/PANTS/ACCESSORIES/SHOES 中)→ 跳过查找,必新增
    • 其他:遍历 getItem(rid) 查同 itemId 的现有 itemIndex
  4. 堆叠分支:找到现有同 itemId → overlay = oldOverlay + itemNumSet(rid, itemIndex, overlay, newNum)
  5. 新建分支
    • 非装备:getFreeItemIndex(rid) 取最小空 index新建一条 {itemId, overlay=itemNum, rid, itemIndex, exclusive, heroId=0}Add(rid, itemIndex, itemInfo)
    • 装备:循环 itemNum 次,每次 getFreeItemIndex + overlay=1 单独建条目(装备永远不堆叠
  6. 同步:syncItem(rid, nil, syncItemInfo, true)Item_ItemInfo
  7. 日志:若 eventType 非空,调 LogLogic:itemChange({rid, iggid, itemId, changeNum, oldNum, newNum, logType, logType2})
  8. 资源阈值告警:若 s_GameWarning:Get(itemId, "num") 存在且 newNum > 阈值Common.sendResourceAlarm(rid, itemId, newNum)

返回值syncItemInfo dictitemIndex → 新建/更新后的 ItemInfo

触发新道具标记:服务端不主动标,客户端 BagProxy.UpdateItemInfo 收到推送时根据 m_isFirstGetItemInfo == false(即非首次登录) + redDotPrompt == 1 + isNewItem 或 overlay 增加,则在 m_reddotRecord[type][itemIndex] 写入新增数量。

协议Item_ItemInfo (30101) 增量推送

错误码addItem 自身只 LOG_ERROR不返回错误码


5.2 移除道具

5.2.1 按 itemIndex 移除:ItemLogic:delItem(rid, itemIndex, itemNum, noSync, logType, logExtraType)

流程ItemLogic.lua L167-198

  1. getItem(rid, itemIndex) 取道具实体
  2. 数量判定
    • overlay <= itemNum → 整条删除:MSM.d_item[rid].req.Delete(rid, itemIndex)newNum = 0
    • overlay > itemNum → 扣减:Set(rid, itemIndex, overlay, overlay - itemNum)
  3. 同步推送 {[Enum.Item.overlay] = newNum}
  4. 日志:LogLogic:itemChange({rid, iggid, logType, logType2, itemId, changeNum, oldNum, newNum})

返回值syncItems dict

⚠️ delItem 不校验 itemNum > overlay,传过量会直接清零(业务方需自己先 checkItemEnough)。

5.2.2 按 itemId 移除:ItemLogic:delItemById(rid, itemId, itemNum, noSync, logType, logExtraType)

流程ItemLogic.lua L241-250遍历所有 items 找第一个匹配 itemId转发到 delItem

⚠️ 业务侧约束:因为非装备同 itemId 必合并在同一 itemIndex所以只有一条匹配装备类不应该用 delItemById(每个 itemIndex 独立)。

5.2.3 数量检查:ItemLogic:checkItemEnough(rid, itemId, itemNum)

返回(boolean, overlay)特点:因为非装备无限叠加 + 必合并,只检查第一条匹配的 itemId.overlay 是否 >= itemNum

装备移除前是否校验穿戴delItem 本身不校验 heroId != 0;具体校验由调用方在装备分解逻辑里处理(Build_DecompositionEquipment proxy handler 校验,本次未深入展开)。

RPC:无独立移除 RPC移除都从其他业务里调用如使用消耗、装备分解、资源兑换扣道具等

错误码delItem 不报错);上层有 ITEM_NOT_ENOUGH(8000) ITEM_NOT_EXIST(8002)


5.3 通用奖励/消耗结构

5.3.1 数据结构

名称 结构
奖励项sproto .RewardItem { itemId, itemNum }
完整奖励信息 .RewardInfo { food, wood, stone, gold, denar, items:*RewardItem, soldiers:*SoldierInfo, groupId, actionForce, guildGifts, heros:*Heros, expeditionCoin, guildPoint, vip, leaguePoints, activityActivePoint }
消耗项sproto .Items { itemId, itemNum }(用于商店购买/合成消耗)

注意ROK 没有统一的 CostInfo,消耗信息分散在各 RPC 的 request 里(如 Shop_BuyShopItem.itemId/itemNum)。

5.3.2 批量接口

函数 用途
ItemLogic:giveReward(rid, rewards, groupId, noSync, noHeroShow, block, isBuyGift, packageNameId) 核心发奖入口,遍历 RewardInfo 各字段调对应 RoleLogic:add* / addItem / ArmyTrainLogic:addSoldiers / HeroLogic:addHero
ItemLogic:getItemPackage(rid, groupId, noAdd, noSync, noHeroShow, noMerge, block, isBuyGift, openNum, mergeHero, packageNameId) 打开礼包:调 getGroupPackage 计算实际奖励,再调 giveReward 发放
ItemLogic:getGroupPackage(rid, groupId, noMerge, openNum, mergeHero) 奖励计算:按 randomGroup 加权随机 + 等级增量 + 浮动比例,输出合并后的 reward 结构
ItemLogic:mergeReward(rawReward, addReward) 奖励合并:把两个 RewardInfo 累加货币求和items/soldiers/heros 按 ID 合并)
ItemLogic:checkItemEnough(rid, itemId, itemNum) 单道具数量校验

5.3.3 事务性

ROK 没有事务giveReward 遍历各字段顺序发放,任一中途失败:

  • 货币 add* 失败:仅 LOG_ERROR已发的不会回滚
  • addItem 失败:同上
  • 业务方需保证 reward 结构合法(数量 > 0 / itemId 存在),失败属于配置错误

业务实现"先检查再扣除"模式:典型如 Shop_BuyShopItem

  1. checkItemEnough(rid, costItemId, costNum) → false 返回 ITEM_NOT_ENOUGH
  2. delItemById(rid, costItemId, costNum) 扣除
  3. addItem(rid, productItemId, productNum) 发放

约束:检查/扣除/发放之间没有锁(单线程 Lua 协程模型actor 内串行执行天然安全;跨 actor 调用需 RPC 等待)


5.4 道具使用 Item.lua:response.ItemUse(msg)

5.4.1 触发流程(客户端)

玩家点击道具 → BagMediator.RefreshItemDetail 显示按钮
       ↓ 玩家点"使用"
BagMediator.BtnOperate 按 itemFunction 分支:
  ├─ itemFunction == 2 → 弹 BagGiftOpenView选包用户选完调 Send(itemIndex, num, selectId)
  ├─ itemFunction == 3 → 弹 BagGiftOpenView兑换确认用户确认后 Send(itemIndex, num, 0)
  ├─ itemFunction == 4 → cityBuffProxy.SendUseItem(data2) → Send(itemIndex, 1, 0)
  ├─ itemFunction == 10 → 检测迷雾,否则弹 OpenFogShow 选坐标后发请求(含 pos
  ├─ itemFunction == 14 → 若已有不同档位预备部队 buff二次确认
  ├─ itemFunction == 31 → 二次确认后发 Map_MoveCity非 Item_ItemUse
  └─ 其他 → Send(itemIndex, num, 0) → 发 Item_ItemUse.request

Send 实现:

var sp = new Item_ItemUse.request {
    itemIndex = itemIndex,
    itemNum = itemNum,
    id = id,  // >0 时才赋值,给 CHOOSE_ITEMPACKAGE 选包用
};
AppFacade.GetInstance().SendSproto(sp);

5.4.2 服务端校验流程

Item.lua:response.ItemUse 完整流程L82-221

  1. 参数校验itemIndex / itemNum 必填 → 否则 ITEM_ARG_ERROR
  2. 道具存在getItem(rid, itemIndex) → 空则 ITEM_NOT_EXIST
  3. 可用性sitem.itemFunction == NOT_USE(0)ITEM_NOT_USE
  4. 批量限制itemNum > 1 && sitem.batchUse == NO(0)ITEM_NOT_BATCH_USE
  5. 业务前置
    • LEAGUE_POINTS未入盟 → ITEM_NOT_JOIN_GUILD
  6. 数量足够itemInfo.overlay < itemNumITEM_NOT_ENOUGH
  7. 召唤怪物分支SUMMON_MONSTER 时先 MonsterSummonMgr.req.summonMonster 校验成功,失败 → ITEM_SOMMON_MONSTER_FAILED
  8. 选包校验CHOOSE_ITEMPACKAGE 时 s_ItemRewardChoice[data2][id] 不存在 → ITEM_PACKAGEID_NOT_EXIST
  9. 扣除道具delItem(rid, itemIndex, itemNum, nil, USE_BAG_ITEM_COST_ITEM)
  10. 任务进度TaskLogic:updateItemUseTaskSchedule(rid, nil, itemNum, sitem)
  11. 按 itemFunction 分发
    • OPEN_ITEMPACKAGE / RECYCLE → rewardId = data2
    • CHOOSE_ITEMPACKAGE → rewardId = s_ItemRewardChoice[data2][id].reward
    • CITY_BUFF → addCityBuff(data2) 直接返回
    • VIP / ACTION_FORCE / LEAGUE_POINTS → 调 add* 直接返回
    • KINGDOM_MAP → openNearDenseFog(pos),开雾失败则 getItemPackage(data2) 补偿,含 rewardInfo 返回
    • SECONDE_QUEUE → 满队列返补偿包,否则 unlockQueue
    • TRAIN_NUM → 修改 itemAddTroopsCapacity + CountsyncSelf 推送
  12. 最终发奖:若 rewardId > 0getItemPackage(rid, rewardId, openNum=itemNum) 发放
  13. 响应{itemId, itemNum, rewardInfo, objectIndex(召怪用), pos(召怪位置), status(队列状态)}

5.4.3 选择数量使用 / 选择目标使用

模式 实现
批量数量 request.itemNum 字段;服务端 batchUse == YES 时支持;getItemPackage 内部 openNum = itemNum 表示开 N 次抽奖
选包 ID request.id 字段;只在 CHOOSE_ITEMPACKAGE 时传,对应 s_ItemRewardChoice[data2][id].reward 之 itemPackage group
选择坐标 request.pos 字段;只用于 KINGDOM_MAP开迷雾选位置
选择英雄 不支持——经验书等给英雄加经验的道具走的是 Hero_ExchangeHeroItem602等独立 RPC不走 ItemUse

5.4.4 涉及 RPC

RPC ID request response
Item_ItemUse 852 itemIndex, itemNum, id(选包), pos(王国地图) itemId, itemNum, rewardInfo, status, objectIndex, pos

5.4.5 错误码

错误码 含义
ITEM_NOT_ENOUGH 8000 道具不足
ITEM_ARG_ERROR 8001 参数错误
ITEM_NOT_EXIST 8002 道具不存在
ITEM_NOT_BATCH_USE 8004 不支持批量使用
ITEM_NOT_USE 8005 不可使用
ITEM_PACKAGEID_NOT_EXIST 8006 所选礼包组不存在
ITEM_KINGDOM_MAP_NO_POS 8007 王国地图未传坐标(实测代码中未使用,预留)
ITEM_NOT_JOIN_GUILD 8008 未加入联盟
ITEM_SOMMON_MONSTER_FAILED 8009 召怪失败(周围乱军太多)

5.5 道具"脚本"机制(实际上没有独立脚本表

5.5.1 真实实现

ItemScript.lua 仅有 3 个空函数(requireAllScript / useItem / dropItem没有任何注册机制。所有"脚本"逻辑都是 Item.lua:ItemUse 函数内的 if/elseif (sitem.itemFunction) 巨型分支。

没有的东西

  • 没有 itemId → Lua 函数的映射表
  • 没有动态加载脚本
  • 没有 s_ItemScript 配置表

有的东西

  • ItemDefine.itemFunctionint 枚举)一一对应硬编码 if 分支
  • ItemDefine.data1 / data2 作为该分支的参数

5.5.2 "脚本类型"清单(即 §4.2 ItemFunctionType 表)

按业务能力归类:

业务能力 itemFunction 实现位置
直接发奖励组 1 / 3 getItemPackage(data2)
选包奖励 2 s_ItemRewardChoice[data2][id].rewardgetItemPackage
时效 Buff 4 (CITY_BUFF) RoleLogic:addCityBuff(data2)
加 VIP / 行动力 5 / 6 RoleLogic:addVip / addActionForce
解锁迷雾 10 DenseFogLogic:openNearDenseFog(pos)
召唤野怪 12 MonsterSummonMgr.req.summonMonster(data2)
工人小屋扩展 13 BuildingLogic:unlockQueue
预备部队增容 14 修改 Role 字段
联盟积分 35 GuildLogic:addGuildCurrency(leaguePoints)

5.5.3 选包奖励的客户端选择流程

点击使用 → BagMediator.BtnOperate 检测 itemFunction == 2
  → 弹 BagGiftOpenView (ShowType=1)
  → m_rewardGroupProxy.GetChoiceRewardDataByGroup(define.data2)
     // 查 s_ItemRewardChoice[data2] 列表,每条 {id, reward(=itemPackage group)}
  → 用户点击某选项 → m_selectId = data.id
  → 点确定 → Item_ItemUse.request { itemIndex, itemNum, id = m_selectId }
  → 服务端按 id 查到具体 reward group → getItemPackage 发放

5.6 新道具标记 / 红点

5.6.1 服务端/客户端分工

  • 服务端完全不维护新道具状态,只负责增量推 Item_ItemInfo
  • 客户端:完全在 BagProxy 中维护:
    • 持久化:PlayerPrefs{rid}/itemIndex:{itemIndex} 存"新/旧/已清"三态
    • 内存:m_reddotRecord[type][itemIndex] = 新增数量 + m_reddotTotalDic[type] = 红点总数

5.6.2 触发时机(BagProxy.UpdateItemInfo + ReddotRecord

  1. 首次登录m_isFirstGetItemInfo == true全部不算新道具(避免登录时所有道具都亮红点),并强制 SetLocalItemToOld 把所有 itemIndex 标为 -1
  2. 非首次:服务端推来一条 ItemInfoItemDefine.redDotPrompt == 1,且:
    • 新增 itemIndex → 红点+=overlay
    • itemIndex overlay 增加 → 红点+=增量
    • itemIndex overlay 减少 → 移除红点记录
  3. 装备已穿戴heroId != 0):直接 SetLocalItemToOld,不亮

5.6.3 清除时机

函数 时机
ClearReddotRecordByIndex(index, itemId) 用户在 BagPanel 选中该道具看详情时(RefreshItemDetail 内调)
ClearReddotRecordByType(type) 用户切换 Bag Tab 时(SwitchMenu 内对原 type 调)
ClearAllReddotRecord() BagPanel 关闭时(BagMediator.OnRemove

⚠️ 设计后果:只要打开过背包并选了道具,红点就消。不需要服务端记账。

5.6.4 红点数量统计

GetBagReddotTotal() = sum over type GetBagReddotNumByType(type) = sum over reddotRecord[type][index]


5.7 资源类道具(金币 / 钻石 / 等)

5.7.1 双轨制设计(关键决策点

ROK 采取双轨制

维度 玩家货币Role 字段) 资源类道具Bag Item
存储位置 Role.food / wood / stone / gold / denar / vip / actionForce / expeditionCoin / individualPoints / leaguePoints / activityActivePoint s_Item 配置 + 背包 Item 条目
操作接口 RoleLogic:addGold / addStone / addFood / addVip / addActionForce … ItemLogic:addItem / delItem
同步协议 Role_RoleInfo 推送 Item_ItemInfo 推送
上限 单字段 int64配置表内有 individualPointsLimit/alliancePointsLimit 等业务上限 s_GameWarning.num 仅做告警,无硬上限
红点 有(按 type 统计)
例子 玩家身上的"500 金币"是 Role.gold 字段 背包里"金币袋 x3每袋可换 1000 金币)"是 itemId 在 RESOURCE 类下的 Item

5.7.2 资源类道具如何转成货币

Item_ItemChangeResource851

request: { itemIndex, itemNum }
→ getItem(rid, itemIndex) 取 itemInfo
→ 校验 s_Item.type == RESOURCE 或 subType == ACTION_FORCE → 否则 ITEM_NOT_RESOURCE_ITEM
→ checkOverlay >= itemNum → 否则 ITEM_NOT_ENOUGH
→ delItem 扣除
→ 按 subType 分支调对应 RoleLogic:add*
   - GOLD → addGold(data1 * itemNum)
   - STONE → addStone
   - WOOD → addWood
   - GRAIN → addFood
   - VIP → addVip
   - ACTION_FORCE → addActionForce
→ updateItemUseTaskSchedule
response: { result, itemId, itemNum }

⚠️ 没有 DENAR钻石/ DIAMOND 这条分支——钻石不能通过道具兑换得来(设计上钻石是付费货币)。

5.7.3 资源大额变动审计

  • 全部走 LogLogic:itemChange / LogLogic:roleChange(每个 RoleLogic:add* 内部都会调)
  • 阈值告警:s_GameWarning.num 配置单 itemId 阈值 → Common.sendResourceAlarm(rid, itemId, newNum) 发给监控

5.8 初始资源发放

ItemLogic:createRoleGiveItems(rid)L49-66

读取 s_Config:Get("initialItemType") 和 ("initialItemNum")
两个 list 长度必须一致(不一致以小的为准)
循环调 addItem(rid, itemId, itemNum, eventType=GUILD_CREATE_ROLE_GAIN_ITEM)

实际配置值Server/common/config/gen/Configs.data L13376 s_Config[0]

initialItemType = { 502030004, 502010001, 502020001, 502040002, 201010010, 201010013, 502070001, 502070003 }
initialItemNum  = { 8,         1,         1,         1,         30,        8,         10,        10        }

initialFood     = 100000
initialWood     = 100000
initialStone    = 0
initialGold     = 0
initialDiamond  = 300   // 钻石denar
initialArmsType = { 10101 }  // 士兵类型
initialArmsNum  = { 1000 }   // 士兵数
initialBuff     = 30105      // 初始 City Buff治疗加速
  • 道具初始有 8 种 × 各若干(共 69 个道具实例)
  • 货币初始:粮 10W、木 10W、钻 300金/石/行动力默认 0
  • 士兵初始10101 类型 1000 个

资源发放走 RoleLogic:createRole(或 setRole 直接赋值字段),不走 addItem


6. 协议清单

6.1 RPC 协议(请求-响应)

协议名 ID 方向 request response 用途
Item_ItemChangeResource 851 C→S itemIndex, itemNum result, itemId, itemNum 使用资源类道具兑换玩家货币(金/木/石/粮/VIP/行动力)
Item_ItemUse 852 C→S itemIndex, itemNum, id, pos itemId, itemNum, rewardInfo, status, objectIndex, pos 使用任意可用道具(按 itemFunction 分发)

6.2 推送协议(服务端 → 客户端)

协议名 ID 方向 request 用途
Item_ItemInfo 30101 S→C itemInfo : *ItemInfo(itemIndex) 增量推送道具变更(新增/数量变更/删除),客户端按 itemIndex 合并到本地 Items dict

6.3 间接相关协议(涉及道具但不属于 Item 模块)

协议 用途
Shop_BuyShopItem (901) 普通商店购买,含 itemId/itemNum
Shop_BuyPostItem (902) 驿站道具
Shop_BuyVipStore (904) VIP 商店购买
Shop_BuyExpeditionStore (905) 远征商店购买
Build_ProduceMaterial / Build_MaterialDecomposition / Build_MaterialSynthesis / Build_MakeEquipment / Build_DecompositionEquipment / Build_CheckMakeEquip 装备/材料生产/合成/分解
Hero_ExchangeHeroItem (605) 英雄碎片兑换
Role_RoleInfo (30251) 含 RoleInfo货币字段 food/wood/stone/gold/denar 等)

7. 错误码清单(ITEM_ 前缀)

错误码 含义
ITEM_NOT_ENOUGH 8000 道具不足
ITEM_ARG_ERROR 8001 道具模块参数错误
ITEM_NOT_EXIST 8002 道具不存在
ITEM_NOT_RESOURCE_ITEM 8003 不是资源类型道具ChangeResource 用)
ITEM_NOT_BATCH_USE 8004 道具不支持批量使用
ITEM_NOT_USE 8005 道具无法使用itemFunction=0 或前置不满足)
ITEM_PACKAGEID_NOT_EXIST 8006 所选道具礼包组不存在
ITEM_KINGDOM_MAP_NO_POS 8007 使用王国地图未上传坐标(代码中预留,未实际触发)
ITEM_NOT_JOIN_GUILD 8008 未加入任何联盟(用 LEAGUE_POINTS 道具时)
ITEM_SOMMON_MONSTER_FAILED 8009 召唤怪物失败

7.1 关联模块道具相关错误码(散落在其他模块前缀)

错误码 含义
ROLE_NAME_ITEM_DENAR_NOT_ENOUGH 1046 改名道具+钻石都不足
ROLE_BUFF_ITEM_NOT_ENOUGH 1048 buff 道具不足
ROLE_SPEED_ITEM_NOT_ENOUGH 1066 加速道具不足
MAP_MOVE_CITY_ITEM_NOT_ENOUGH 2030 迁城道具不足
HERO_SUMMON_ITEM_NOT_ENOUGH 3001 召唤统帅道具不足
HERO_LEVEL_ITEM_NOT_ENOUGH 3005 升级技能道具不足
HERO_EXCHANGE_ITEM_NOT_ENOUGH 3010 通用雕像不足
HERO_ITEM_ERROR 3015 升星材料类型错误
HERO_ITEM_TO_MUCH 3016 道具不足无法升星
BUILDING_ITEM_ERROR 6021 解锁建筑道具类型错误
BUILDING_SMITHY_ITEM_ERROR 6024 无法生产该道具
BUILDING_SMITHY_ITEM_NOT_ENOUGH 6027 该材料不足
BUILDING_EQUIP_ITEM_NO_ENOUGH 6030 装备道具不足
SHOP_ITEM_NOT_SELL 10000 商品没在商店售卖
SHOP_POST_ITEM_NOT_EXIST 10001 驿站道具不存在
SHOP_POST_ITEM_HAVE_BUY 10002 驿站道具已购买
SHOP_EXPEDITION_ITEM_COUNT_MAX 10007 远征商店购买超上限
GUILD_SHOP_ITEM_NOT_EXIST 12073 联盟商店商品不存在
GUILD_SHOP_ITEM_NOT_ENOUGH 12074 联盟商店商品不足

⚠️ BAG_ 前缀错误码不存在——背包功能复用 ITEM_ 前缀。


8. UI 流程(BagMediator / BagGiftOpenMediator / UI_Win_UseItemMediator

8.1 BagPanel 分页

  • 5 个 Tab:资源(1) / 加速(2) / 增益(3) / 装备(4) / 其他(5)
  • Tab 切换:OnMenuRes/Speed/Gain/Equip/OtherSwitchMenu(type) → 切 Tab 时自动清除当前 Tab 的红点记录
  • 每个 Tab 显示4 列 × N 行(m_itemCol = 4m_itemLineCount = ceil(count/4)
  • 数据源:m_bagProxy.Items 全部过滤 overlay > 0,按 type = itemId / 100000000 分组
  • Tab 角标红点数:m_pageReddotImgList[i] + GetBagReddotNumByType(i+1)

8.2 排序规则

DataSort 在每个 Tab 数据列表上:

  1. ItemDefine.rank 升序
  2. rank 相同则按 itemId 升序

8.3 道具详情 Tooltip 显示内容

RefreshItemDetail 渲染:

  • 品质背景图(m_qualityDic[quality]5 档)
  • 道具图标(itemDefine.itemIcon
  • 顶部小卡描述(仅 l_topID >= 1 时显示,格式 format(text, topData)
  • 名称(l_nameID
  • 装备typeGroup == 2)→ 显示 UI_Item_EquipAtt 属性卡片
  • 非装备 → 显示 l_desID 格式化文本 format(text, desData1, desData2)
  • 可批量使用batchUse == 1)→ 显示 +/- 数量调整 + 输入框 + Max 按钮
  • 使用按钮:仅 l_buttonDes >= 1 时显示(文字来自语言包)

8.4 使用流程的二次确认

情况 是否二次确认
普通礼包itemFunction=1 无确认,直接发请求
选包奖励itemFunction=2 BagGiftOpenView 必选,本身就是确认界面
兑换确认itemFunction=3 BagGiftOpenView 显示前后对比
王国地图itemFunction=10 选坐标本身就是确认
预备部队itemFunction=14 若已有不同档位 buff 弹 Alert 二次确认
VIP 道具UseItemView 计算 overflow超出时弹 Alert 二次确认
随机迁城itemFunction=31 强制弹 Alert 二次确认
其他

8.5 ItemUse 响应处理(PlayerCmd.cs:Item_ItemUse.TagName

  1. 错误响应 → ErrorCodeHelper.ShowErrorCodeTip
  2. 成功:Tip.CreateTip("使用了 {道具名} x{数量}")
  3. itemFunction 分发后续 UI
    • 10/13 → 弹 s_itemCollection 显示奖励
    • 12 → 相机飞向召唤点 + 召唤特效
    • 其他 → 若 HasRewardInfos_rewardGetWin 奖励展示

9. 与 Survivors 实现的对照点

9.1 模块对应表

ROK 模块 Survivors 对应(计划) 说明
BagProxy.cs + 客户端缓存 BagComponent(挂玩家 Entity + BagComponentSystem ET 风格的 Component/System业务逻辑放 System
ItemLogic.lua:addItem/delItem BagComponentSystem.AddItems / RemoveItems 统一入口,但 Survivors 设计是"所有奖励都走 Item",比 ROK 更激进
Item.lua:ItemUse 巨型 if/elseif C# Dictionary<int, IItemUseHandler> 注册机制 比 Lua 硬编码更可扩展,便于单测
s_Item + ItemDefine Luban 配置 ItemConfig 字段保留 quality/type/subType/itemFunction/data1/data2删掉 ROK 残留(exclusive 改名 bindType 等)
Item_ItemInfo 增量推送 M2C_ItemInfoSyncprotobuf 用 MemoryPack 序列化
Item_ItemUse (852) C2M_UseItem / M2C_UseItemResponse RPC + 推送分离
BagPanel.prefab5 Tab BagPanel.prefabYIUI4 Tab资源/装备/道具/材料) Survivors 设计简化成 4 Tab
BagGiftOpenView(选包) GiftOpenPanel 同流程
红点 PlayerPrefs ET RedDotComponent + 持久化到 Mongo 服务端记账,多端同步
创角初始道具 initialItemType/Num InitialResourceConfigLuban 列表配置,启动时遍历 AddItems
错误码 8000-8009 ErrorCode.cs 同段位 直接复用 8000-8009

9.2 关键差异决策

维度 ROK Survivors 设计
货币/道具是否合并 分离(双轨制) 合并(所有可获得资源 = Item金币也是 itemId
使用脚本机制 硬编码 if/elseifitemFunction 枚举) C# IItemUseHandler 注册(每个 itemFunction 一个 handler 类)
新道具红点 客户端 PlayerPrefs 服务端 Mongo + 客户端缓存
配置表 SQLite + 自研 Define Luban 生成
协议 sproto protobuf3 + MemoryPack
持久化 服务端 Redis + 落 SQL MongoIDBComponent
装备穿戴 item.heroId 字段
奖励合并 mergeReward Lua C# 通用 RewardEntry 列表

9.3 设计陷阱(迁移时易踩)

  1. 不要直接搬"双轨制"Survivors 设计目标是统一 Item。金币/钻石如果也作为 Item则没有 Item_ItemChangeResource 这个 RPC相关 ItemType.RESOURCE 子类型大量道具变成"普通礼包道具"
  2. exclusive 字段ROK 是装备专属英雄 IDSurvivors 设计中可能不需要装备绑定,可去除
  3. uniqueIndex 字段ROK 中预留未用Survivors 直接删掉
  4. maxStack 缺失:必须新增(防溢出 int 攻击)
  5. itemFunction 拆分ROK 的 35 个值分散且历史包袱重Survivors 应只实现 P1-P3 核心 5-8 个
  6. itemId 编码约定ROK 用 itemId / 100000000 划分 typeSurvivors 应改为 ItemConfig 显式 type 字段itemId 不再有语义)

10. 实现优先级建议

P1 必须(核心基础设施,无 UI

# 任务 对应 ROK 备注
1 ItemConfig Luban 配置定义(含 type/subType/quality/itemFunction/data1/data2/icon/name/desc/maxStack s_Item + ItemDefine 删 exclusive/uniqueIndex加 maxStack
2 BagComponent(玩家身上挂) + ItemUnit(子 EntityitemIndex 主键) MSM.d_item[rid] Mongo 持久化
3 BagComponentSystem.AddItems / RemoveItems / HasItems / GetItemNum addItem / delItem / checkItemEnough 统一发奖/扣资源入口,所有业务都调它
4 M2C_ItemInfoSync 增量推送 Item_ItemInfo (30101) 客户端 BagComponentClient 合并
5 RewardEntry { itemId, count } 通用结构 .RewardItem 一切奖励/消耗都用它
6 InitialResourceConfig + 创角发放 s_Config.initialItemType/Num Login 时调
7 错误码 8000-8009 ErrorCode.cs 直接复用

P2 必须(道具使用 + 核心 itemFunction

# 任务 对应 ROK 备注
1 C2M_UseItem Handler Item.lua:ItemUse 校验/扣道具/调 handler/返回结果
2 IItemUseHandler 注册机制 + ItemUseHandlerComponent 巨型 if/elseif C# 字典查找替代硬编码
3 ItemUseHandler_OpenPackageitemFunction=1 OPEN_ITEMPACKAGE ItemPackageSystem.GetReward
4 ItemUseHandler_ChoosePackageitemFunction=2 CHOOSE_ITEMPACKAGE 含 request.id 参数
5 ItemPackageConfig + ItemPackageSystem.GetReward(groupId, openNum) s_ItemPackage + getItemPackage 加权随机
6 ItemRewardChoiceConfig s_ItemRewardChoice 选包配置
7 操作日志 LogLogic:itemChange 等效 LogLogic jsonl 落盘

P3 可推迟(业务扩展类 itemFunction

# 任务 备注
1 itemFunction=5/6 VIP/行动力(如果 Survivors 把它们作为 Item,则这俩 handler 不需要,直接发 itemId
2 itemFunction=4 CityBuff如果 Survivors 有 buff 系统才做)
3 itemFunction=10 解锁迷雾Survivors 无大地图,跳过
4 itemFunction=12 召唤怪物(跳过
5 itemFunction=13/14 工人/部队SLG 专有,跳过
6 itemFunction=30/31 迁城(跳过
7 itemFunction=35 联盟积分(无联盟,跳过

P4 UI 集中实现

# 任务 对应 ROK
1 BagPanel4 Tab资源/装备/道具/材料) BagView
2 BagItemUICommon 通用道具显示组件 UI_Item_Bag + UI_Model_Item
3 BagItemTooltip 道具详情浮层 RefreshItemDetail 内的详情面板
4 GiftOpenPanel 选包/兑换 UI BagGiftOpenView
5 RewardGetPanel 奖励展示弹窗 s_rewardGetWin
6 Tab 红点 m_pageReddotImgList

P5 后续完善

# 任务
1 资源阈值告警(GameWarning 配置 + Alarm
2 大额变动审计日志
3 装备分解/合成(如果做装备系统)
4 装备图纸(如果做装备系统)

附录 AROK 关键源代码位置索引

内容 路径
服务端 ItemLogicaddItem/delItem/giveReward/getItemPackage Server/server/game_server/logic/lualib/ItemLogic.lua
服务端 Item proxyItemUse/ItemChangeResource RPC handler Server/server/game_server/logic/service/proxy/Item.lua
服务端 Item 数据 service Server/server/game_server/logic/service/data/d_item.luasnax 服务,本次未深入)
道具枚举ItemType/SubType/FunctionType/PackageType/BatchUse Server/common/lualib/enum/ItemEnum.lua
CurrencyType 枚举(货币不是 Item Server/common/lualib/enum/OtherEnum.lua L101
ItemScript空壳,无实质内容) Server/server/game_server/logic/lualib/itemscript/ItemScript.lua
Common.sprotoItemInfo / RewardInfo / RewardItem Server/common/protocol/Common.sproto L308 / L381 / L362
Protocol.sprotoItem_ItemUse 852 / Item_ItemChangeResource 851 / Item_ItemInfo 30101 Server/common/protocol/Protocol.sproto
服务端 s_Config 初始道具配置initialItemType/Num Server/common/config/gen/Configs.data L13376id=0 行)
客户端 BagProxy增量同步/红点/装备/材料) Client/Assets/Scripts/Hotfix/MVC/Proxy/BagProxy.cs
客户端 BagMediator5 Tab + 使用按钮分支) Client/Assets/Scripts/Hotfix/MVC/View_Mediator/Bag/BagMediator.cs
客户端 BagGiftOpenMediator选包/兑换 UI Client/Assets/Scripts/Hotfix/MVC/View_Mediator/Bag/BagGiftOpenMediator.cs
客户端 UI_Win_UseItemMediator行动力/VIP 快捷使用) Client/Assets/Scripts/Hotfix/MVC/View_Mediator/UseItem/UI_Win_UseItemMediator.cs
客户端 PlayerCmd.csItem_ItemUse 响应处理) Client/Assets/Scripts/Hotfix/MVC/CMD/PlayerCmd.cs L38-128
客户端 ItemDefine25 字段) Client/Assets/Scripts/Hotfix/Config/ItemConfig.cs
客户端 ItemPackageConfig / ItemRewardChoiceConfig 等 Client/Assets/Scripts/Hotfix/Config/Item*Config.cs7 个)
错误码 ITEM_ 前缀8000-8009 Client/Assets/Scripts/Hotfix/MVC/CMD/ErrorCode.cs L255-264
客户端配置 Bin 文件 Client/Assets/StreamingAssets/Config/Bin/Item.bin87 KB

附录 B未深入调研的边角

  • s_Item.lua 的 ConfigEntity 加载机制(只看了 stub没看 ConfigEntity 父类)
  • MSM.d_item[rid] snax 服务实现细节
  • Build_* 装备制造/合成 RPC 详细参数(涉及 EquipDefine + EquipMaterialDefine 联动)
  • Hero_ExchangeHeroItem 等英雄相关道具用法(属于 Hero 模块)
  • 钻石denar的付费充值入口RechargeLogic属于充值模块
  • 联盟礼物 guildGifts 在奖励组中的具体发放机制(属于 Guild 模块)
  • LogLogic:itemChange 的具体日志格式(输出到 log_server