Files
loneseDocument/Plugins/Item/IItemContainer.md
meishibiezb 29a3f77908 init
2026-06-04 21:44:13 +08:00

6.5 KiB
Raw Permalink Blame History

IItemContainer + UItemContainer

基本信息

  • 类型: UINTERFACE + C++ 接口
  • 父类: UInterface
  • 源文件: Plugins/Item/Source/Item/Public/ItemContainer.h
  • 模块: Item

功能概述

物品容器操作的主要C++接口。提供查询GetItemViews、GetItemCount、变更MoveItem、CreateItem和属性读写GetItemProperty、SetItemProperty使用CustomThunk。采用NVI模式通过InjectPayload/InjectPayloadImpl实现物品注入。UItemContainer带有meta=(CannotImplementInterfaceInBlueprint)标记限制实现仅限C++侧。

设计用意

插件的核心抽象层。将"可以对物品做什么"与"物品存储在何处"分离。属性读写使用CustomThunk使单个UFUNCTION支持任意Blueprint类型。NVI模式确保在注入时可自动更新Tracer。

职责范围

定义物品存储的完整契约。实现者如UDefaultContainer提供具体的存储方案。调用者通过此接口查询、移动、创建和修改物品无需了解容器类型。

项目内依赖

依赖项 关系 源文件
ItemFactory.h #include (在.cpp中) Plugins/Item/Source/Item/Public/ItemFactory.h
FItemInstance forward-declare Plugins/Item/Source/Item/Public/ItemFactory.h

对外接口

IItemContainer 是 C++ 纯虚接口(其 UINTERFACE 标记了 meta=(CannotImplementInterfaceInBlueprint)),只允许在 C++ 侧实现。调用方通过 TScriptInterface 引用容器,可调用以下方法:

查询方法BlueprintCallable

  • GetItemViews() → TArray: 返回容器中所有物品的只读视图快照。用于 UI 显示物品列表。
  • GetItemViewByID(const FGuid&) → FItemView: 根据物品 ID 查找并返回单个物品视图。未找到时返回默认构造的空视图。
  • GetItemCount() → int32: 返回容器当前持有的物品数量。

变更方法BlueprintCallable, BlueprintAuthorityOnly

  • MoveItem(const FGuid&, const TScriptInterface&) → bool: 将指定物品从当前容器移动到目标容器。内部通过 InjectPayload 传递给目标容器。移动失败返回 false。
  • CreateItem(FName, TArray&, int32 Count = 1) → bool: 根据物品类型名称创建指定数量的物品并加入本容器。新创建的物品 ID 会追加到 NewItemIDs 数组中。需要物品类型在注册表中已注册。

属性读写BlueprintCallable, BlueprintAuthorityOnly, CustomThunk

  • GetItemProperty(FGuid, FName, int32& Value) → bool: 从物品的动态属性包中读取指定名称的属性值。CustomThunk 机制使 Value 参数自动匹配实际属性类型bool/int/float/FName/FString 等)。返回值表示读取是否成功。
  • SetItemProperty(FGuid, FName, int32 Value): 向物品的动态属性包写入值。类型由蓝图引脚自动推断CustomThunk 分发到 Internal_SetPropertyRaw。

C++ 专有接口(非 UFUNCTION

  • InjectPayload(TUniquePtr): 向容器注入一个物品的所有权移动语义。NVI 模式:公开的非虚方法负责更新物品 Tracer位置 + 广播 OnItemMoved然后调用 protected 虚方法 InjectPayloadImpl 完成实际存储。
  • Internal_GetPropertyRaw / Internal_SetPropertyRaw: CustomThunk 的底层分发目标,由实现者覆写。接收原生 FProperty 指针和内存地址,完成类型兼容性检查后的值拷贝。

使用方法

IItemContainer 的实现者(如 UDefaultContainer在主模块中实现所有纯虚方法。调用方通过 TScriptInterface 操作容器。

获取容器接口: 持有 UDefaultContainer 或其子类(如 BP_DefaultContainer的对象可通过隐式转换获取 TScriptInterface

// DefaultContainer.cpp:64 - 从 this 指针构造接口引用
TScriptInterface<const IItemContainer>(this)

调用方获取注册表并查询物品:

// DefaultContainer.cpp:44-52 - 获取注册表的辅助函数
static UItemRegistrySubsystem* GetRegistry(const UObject* WorldContext)
{
    if (!WorldContext) return nullptr;
    UWorld* World = WorldContext->GetWorld();
    if (!World) return nullptr;
    UGameInstance* GI = World->GetGameInstance();
    if (!GI) return nullptr;
    return GI->GetSubsystem<UItemRegistrySubsystem>();
}

移动物品示例:

// DefaultContainer.cpp:89-111 - MoveItem 实现
bool UDefaultContainer::MoveItem(const FGuid& ItemID,
    const TScriptInterface<IItemContainer>& TargetContainer)
{
    IItemContainer* TargetInterface = TargetContainer.GetInterface();
    if (!TargetInterface) return false;
    // 查找并取出物品...
    TUniquePtr<FItemInstance> MovedItem = MoveTemp(Items[Index]);
    Items.RemoveAt(Index);
    // 通过接口注入目标容器
    TargetInterface->InjectPayload(MoveTemp(MovedItem));
    return true;
}

CustomThunk 属性读写: GetItemProperty / SetItemProperty 通过 exec 函数分发到底层的 Internal_GetPropertyRaw / Internal_SetPropertyRawItemContainer.cpp:11-43。在 Blueprint 中调用时Value 引脚自动根据属性类型展开,无需手动指定类型。

用例

  • Plugins/Item/Source/Item/Private/DefaultContainer.cpp:54-66 -- GetItemViews() 实现:遍历物品并调用 FItemViewFactory 构造视图,通过 TScriptInterface(this) 传递自身引用。
  • Plugins/Item/Source/Item/Private/DefaultContainer.cpp:69-81 -- GetItemViewByID() 实现:按 ID 查找并返回单物品视图。
  • Plugins/Item/Source/Item/Private/DefaultContainer.cpp:89-111 -- MoveItem() 实现:从 TArray 中取出 TUniquePtr调用目标容器的 InjectPayload 注入。
  • Plugins/Item/Source/Item/Private/DefaultContainer.cpp:113-127 -- CreateItem() 实现:通过注册表获取 FItemDef调用 ItemFactory::CreateItemInstance 创建,通过 InjectPayload 注入。
  • Plugins/Item/Source/Item/Private/ItemContainer.cpp:7-43 -- GetItemProperty / SetItemProperty 的 CustomThunk exec 函数实现,分发到 Internal_GetPropertyRaw / Internal_SetPropertyRaw。
  • Plugins/Item/Source/Item/Private/ItemContainer.cpp:45-67 -- InjectPayload NVI 实现:查找 Tracer → 更新位置 → 广播 OnItemMoved → 调用 InjectPayloadImpl。
  • Plugins/Item/Source/Item/Public/Inventory.h:39 -- IInventory::ReceiveItem 的参数使用 TScriptInterfaceBridge IInventory 与 IItemContainer。
  • Plugins/Item/Source/Item/Private/ItemViewFactory.cpp:57 -- FItemViewFactory::CreateView 接收 TScriptInterface 参数,设置到 FItemView::Location。