80 lines
6.3 KiB
Markdown
80 lines
6.3 KiB
Markdown
# UDefaultContainer
|
||
|
||
## 基本信息
|
||
- **类型**: UCLASS(BlueprintType, Blueprintable)
|
||
- **父类**: UObject, 实现 IItemContainer
|
||
- **源文件**: Plugins/Item/Source/Item/Public/DefaultContainer.h
|
||
- **模块**: Item
|
||
|
||
## 功能概述
|
||
IItemContainer的参考实现。将物品存储在TArray<TUniquePtr<FItemInstance>>中。实现所有接口方法:查询、移动、创建、带类型检查的属性读写。Blueprintable允许设计师扩展。TODO计划切换为TMap以提升性能。
|
||
|
||
## 设计用意
|
||
默认的具体容器实现。简单的扁平数组存储。Blueprintable标记允许子类添加约束(槽位、堆叠)。为其他容器实现提供参考。
|
||
|
||
## 职责范围
|
||
完整的IItemContainer实现。处理物品存储、检索、移动、创建和属性访问。使用UItemRegistrySubsystem进行物品定义查找,使用FItemViewFactory生成视图。
|
||
|
||
## 项目内依赖
|
||
| 依赖项 | 关系 | 源文件 |
|
||
|--------|------|--------|
|
||
| ItemContainer.h | #include (实现) | Plugins/Item/Source/Item/Public/ItemContainer.h |
|
||
| ItemRegistrySubsystem.h | #include (在.cpp中) | Plugins/Item/Source/Item/Public/ItemRegistrySubsystem.h |
|
||
| ItemViewFactory.h | #include (在.cpp中) | Plugins/Item/Source/Item/Public/ItemViewFactory.h |
|
||
| ItemFactory.h | #include (在.cpp中) | Plugins/Item/Source/Item/Public/ItemFactory.h |
|
||
|
||
## 对外接口
|
||
UDefaultContainer 实现了 IItemContainer 的全部接口,对外暴露以下方法(全部继承自 IItemContainer,此处列出的均为 override 实现):
|
||
|
||
**查询接口:**
|
||
- **GetItemViews() const** → TArray<FItemView>: 遍历内部 Items 数组,通过 UItemRegistrySubsystem 获取每个物品的 FItemDef,调用 FItemViewFactory::CreateView 构造视图。注册表不可用时返回空数组(DefaultContainer.cpp:54-66)。
|
||
- **GetItemViewByID(const FGuid&) const** → FItemView: 按 ID 查找。未找到返回空 FItemView(DefaultContainer.cpp:69-81)。
|
||
- **GetItemCount() const** → int32: 返回 Items.Num()(DefaultContainer.cpp:84-86)。
|
||
|
||
**变更接口:**
|
||
- **MoveItem(const FGuid&, const TScriptInterface<IItemContainer>&)** → bool: 从内部数组取出物品(MoveTemp),调用 RemoveAt,然后通过目标容器的 InjectPayload 注入。目标容器无效或物品不存在时返回 false(DefaultContainer.cpp:89-111)。
|
||
- **CreateItem(FName, TArray<FGuid>&, int32 Count = 1)** → bool: 从注册表获取 FItemDef,检查 ItemName 非空,循环调用 ItemFactory::CreateItemInstance 创建指定数量物品,每个物品通过自身的 InjectPayload 添加。新物品 ID 追加到 NewItemIDs(DefaultContainer.cpp:113-127)。
|
||
|
||
**属性接口(CustomThunk 底层实现):**
|
||
- **Internal_GetPropertyRaw**: 按 ItemID 线性查找物品 → 从属性包中查找属性描述 → 类型兼容性检查后从属性包内存拷贝到蓝图引脚内存(DefaultContainer.cpp:137-187)。
|
||
- **Internal_SetPropertyRaw**: 相同的查找和类型检查流程,反向拷贝(从蓝图引脚写入属性包)(DefaultContainer.cpp:189-230)。
|
||
|
||
**内部接口:**
|
||
- **InjectPayloadImpl(TUniquePtr<FItemInstance>)**: 接收物品所有权,简单的 Items.Add(DefaultContainer.cpp:129-135)。
|
||
|
||
**存储:**
|
||
内部使用 TArray<TUniquePtr<FItemInstance>> Items 存储物品。当前为线性查找(O(n)),TODO 计划切换为 TMap 以提升性能。类标记为 BlueprintType 和 Blueprintable,可在编辑器中创建 BP_DefaultContainer 子类。
|
||
|
||
## 使用方法
|
||
UDefaultContainer 作为 IItemContainer 的参考实现,可直接在 C++ 中实例化,或创建 Blueprint 子类(如 BP_DefaultContainer)在编辑器中引用。
|
||
|
||
**在 C++ 中使用:**
|
||
容器需要绑定到 GameInstance 的 World 上下文才能获取注册表(通过 GetRegistry 辅助函数,DefaultContainer.cpp:44-52)。创建物品和查询都依赖注册表。
|
||
|
||
**在 Blueprint 中使用:**
|
||
BP_DefaultContainer 是 UDefaultContainer 的蓝图子类(无额外逻辑),可在编辑器中作为资产创建。BP_InventoryComp 在编辑器中持有 BP_DefaultContainer 的引用,通过它对容器进行操作:
|
||
- 调用 CreateItem 创建物品(需在 Authority 侧执行)。
|
||
- 调用 GetItemViews 获取物品列表用于 UI 显示。
|
||
- 调用 MoveItem 将物品移动到其他容器。
|
||
|
||
**实现自定义容器:**
|
||
继承 UDefaultContainer 并覆写虚方法即可创建自定义容器(如带槽位限制、堆叠功能的容器)。由于类标记了 Blueprintable,也可以在 Blueprint 中继承。
|
||
|
||
**当前实现的限制:**
|
||
- 存储使用 TArray 线性查找(O(n)),TODO 计划切换为 TMap 以提升性能(DefaultContainer.h:32)。
|
||
- 属性读写中的名称清理(点号→下划线)当前在 Internal_GetPropertyRaw / Internal_SetPropertyRaw 中处理,TODO 计划提取到 NVI 层。
|
||
|
||
## 用例
|
||
- `Plugins/Item/Source/Item/Public/DefaultContainer.h:15-34` -- UDefaultContainer 类声明(继承 UObject + IItemContainer,声明所有接口方法和 Items 成员)。
|
||
- `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:44-52` -- GetRegistry 静态辅助函数,从 WorldContext 获取 UItemRegistrySubsystem。
|
||
- `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:54-66` -- GetItemViews 实现:遍历 Items 并为每个物品调用 FItemViewFactory::CreateView。
|
||
- `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:69-81` -- GetItemViewByID 实现。
|
||
- `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:84-86` -- GetItemCount 实现。
|
||
- `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:89-111` -- MoveItem 实现:MoveTemp + RemoveAt + InjectPayload。
|
||
- `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:113-127` -- CreateItem 实现:获取定义 → 工厂创建 → InjectPayload。
|
||
- `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:129-134` -- InjectPayloadImpl 实现。
|
||
- `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:137-187` -- Internal_GetPropertyRaw 实现(属性包读取 + 类型兼容性检查)。
|
||
- `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:189-230` -- Internal_SetPropertyRaw 实现(属性包写入 + 类型兼容性检查)。
|
||
- `Document/Content/Blueprints/BP_DefaultContainer.md` -- BP_DefaultContainer 是 UDefaultContainer 的 Blueprint 子类,在编辑器中作为可引用资产使用。
|
||
- `Document/Content/Blueprints/BP_InventoryComp.md` -- BP_InventoryComp 持有 BP_DefaultContainer 引用并包装其操作。
|