5.5 KiB
背包 / 物品栏模块
脚本入口: eve.Inventory()
数据驱动的物品定义、固定格容器(背包/箱子)、跨包转移、具名装备栏,以及可插拔的接纳 / 容量 / 堆叠规则。
基本用法
local inv = eve.Inventory();
inv.registerItemsFromJson(@"[
{""id"":""potion.hp"",""displayName"":""治疗药水"",""maxStack"":20,""weight"":0.2,""tags"":[""potion""]},
{""id"":""sword.iron"",""maxStack"":1,""weight"":3.5,""equipSlot"":""weapon"",""tags"":[""weapon""]}
]");
local bag = inv.newBag(20);
bag.setId("player");
bag.setMaxWeight(50.0);
bag.addItem("potion.hp", 5);
print(bag.countItem("potion.hp") + "\n");
对象关系与调用时机
Inventory 持有进程级物品定义表,并创建 Bag / EquipmentSet。容量策略名、接纳规则名、堆叠规则名都是字符串;内置规则开箱即用,自定义规则需在 C++ 侧 InventorySystem::register*。变更事件可在操作后用 getChangeEvent* 轮询。
目标导向指南
做玩家背包与任务栏
newBag(n) 建主背包;另建一个 acceptTags 仅含 "quest" 的袋子作任务栏。主背包可 addRejectTag("quest") 拒绝任务物品误入。
穿脱装备
newEquipmentSet() 后 defineSlot("weapon"),可选 addSlotAllowedTag。从背包 findItem 得到槽位,再 equipFromBag / unequipToBag。属性加成请在脚本或 C++ registerChangeHook 里对接 rpg 模块,背包本身不依赖 RPG。
原子保存背包与装备
eve.InventorySaveSession() 通过 bind(bag, equipment) 借用两个权威容器。
snapshotJson() 生成 schema eve.inventory.save-session、版本 1 的确定性 JSON;
restoreSnapshotJson() 会先校验所有物品定义、策略名、物品实例身份、堆叠上限和装备槽契约,
再一次发布背包与装备状态。任一字段失败时两个容器都不改变,也不会产生库存事件或调用 hook。
物品定义注册表属于内容,不写入玩家存档;读档前必须先加载相同内容版本。
C++ 批量加入事务
跨系统奖励应使用 InventorySystem::prepareAddBatch() 先在私有候选背包上验证完整批次,再用
commitAddBatch() 提交。准备阶段不改变背包、不产生轮询事件、也不调用 hook;提交时如果背包自准备后
发生变化,会以结构化 Conflict 拒绝。成功提交先一次替换权威槽位,随后才发布每项 add 事件,
因此观察者不会看到半批物品。预备对象仅可移动、只能提交一次,并且只能在背包所属模拟线程使用。
需要和货币、任务等其他权威状态共同提交的移除操作使用 prepareRemove() / commitRemove();它采用
同样的候选背包、陈旧检测和提交后事件契约。RPG 商店已在此基础上提供购买与出售事务。
常见问题
- 未先
registerItemsFromJson/ C++registerItem就addItem,会放入 0 个。 canAddItem表示能否放入全部请求数量;addItem允许部分成功。- 多种物品共享容量时不要逐项
canAddItem后再添加;C++ 使用prepareAddBatch/commitAddBatch。 maxWeight/maxVolume为<=0时该维度不限制(仍受所选capacityPolicy约束)。
API 快查
addAcceptTag()、addItem()、addRejectTag()、addSlotAllowedTag()、addSlotTag()、canAddItem()、canAddItemReason()、clear()、clearAcceptTags()clearChangeEvents()、clearItemDefinitions()、clearRejectTags()、clearSlot()、clearSlotAllowedTags()、countItem()、defineSlot()、destroy()、equipFromBag()findItem()、findItemByTag()、getAcceptRule()、getAcceptTag()、getAcceptTagCount()、getCapacityPolicy()、getChangeEventAction()、getChangeEventBagId()、getChangeEventCount()getChangeEventEquipSlot()、getChangeEventItemId()、getChangeEventOtherBagId()、getChangeEventOtherSlot()、getChangeEventQuantity()、getChangeEventSlot()、getExtra()、getId()、getItemCategory()getItemDefinitionCount()、getItemDisplayName()、getItemEquipSlot()、getItemExtra()、getItemMaxStack()、getItemVolume()、getItemWeight()、getKind()、getMaxVolume()getMaxWeight()、getName()、getRejectTag()、getRejectTagCount()、getSlotCount()、getSlotDurability()、getSlotInstanceId()、getSlotItemId()、getSlotName()getSlotProp()、getSlotQuantity()、getStackRule()、getUsedSlotCount()、getUsedVolume()、getUsedWeight()、hasAcceptRule()、hasCapacityPolicy()、hasItemDefinition()hasSlot()、hasStackRule()、isSlotEmpty()、itemHasTag()、moveSlot()、newBag()、newEquipmentSet()、registerItemsFromJson()、removeAt()removeItem()、restoreSnapshotJson()、setAcceptRule()、setCapacityPolicy()、setExtra()、setId()、setKind()、setMaxVolume()、setMaxWeight()、setSlotCount()、snapshotJson()setSlotDurability()、setSlotProp()、setStackRule()、slotHasTag()、splitStack()、swapSlots()、transferItem()、transferSlot()、unequipToBag()
使用要点
- 将
Bag/EquipmentSet保存在全局或实体状态中,不要每帧newBag。 - 浮点重量/体积在脚本侧为
float。 - 自定义接纳/容量/堆叠回调只能在 C++ 注册;脚本通过策略名字符串选用。
源码: src/modules/inventory/
设计文档: docs/dev/背包系统设计.md
相关测试: 在 test/ 中搜索 inventory。