Files
EVEngine/docs/usr/modules/inventory.md
T

84 lines
5.5 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.
# 背包 / 物品栏模块
**脚本入口:** `eve.Inventory()`
数据驱动的物品定义、固定格容器(背包/箱子)、跨包转移、具名装备栏,以及可插拔的接纳 / 容量 / 堆叠规则。
## 基本用法
```squirrel
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/`](../../../src/modules/inventory/)
**设计文档:** [`docs/dev/背包系统设计.md`](../../dev/背包系统设计.md)
**相关测试:** 在 [`test/`](../../../test/) 中搜索 `inventory`。