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

4.8 KiB
Raw Blame History

UItemTracer

基本信息

  • 类型: UCLASS(BlueprintType)
  • 父类: UObject
  • 源文件: Plugins/Item/Source/Item/Public/ItemFactory.h
  • 模块: Item

功能概述

嵌入在FItemInstance属性包中的轻量级追踪对象。存储当前容器位置并暴露OnItemMoved多播委托。提供Blueprint查询函数用于查询物品位置。

设计用意

解决"物品在哪"的问题无需全局注册表。存在于物品的属性包中随物品迁移。由IItemContainer::InjectPayload NVI包装自动更新。OnItemMoved委托使UI/任务系统能响应物品移动事件。

职责范围

追踪和广播物品位置变化。由InjectPayload在插入时更新位置。UPROPERTY位置使用TObjectPtr非强引用避免泄漏。

项目内依赖

(无项目内依赖)

对外接口

UItemTracer 是 BlueprintType嵌入在物品的属性包中键名为 Internal_ItemTracer随物品在容器间迁移。外部代码通过属性包获取 Tracer 引用后,可调用以下接口:

Blueprint 可调用:

  • GetItemLocation() (BlueprintPure, BlueprintAuthorityOnly) → const UObject*: 返回物品当前所在的 UObject 位置。在 InjectPayload NVI 中此位置被设置为容器对象Cast(this))。返回值可能为空(物品尚未被注入任何容器)。
  • FindActorInOuterChain() (BlueprintPure, BlueprintAuthorityOnly) → const AActor*: 从物品位置出发,沿 Outer 链向上查找第一个 AActor。如果物品容器是 Actor 的组件/子对象,此方法可追溯到所属 Actor。找不到则返回 nullptr。

委托:

  • OnItemMoved (FOnItemMoved, BlueprintAssignable): DYNAMIC_MULTICAST_DELEGATE_OneParam 类型的动态多播委托。在 IItemContainer::InjectPayload 中被广播(参数为 Tracer 自身。UI 或任务系统可绑定此委托以响应物品移动事件。

C++ 专用:

  • SetItemLocation(UObject)*: 设置 Tracer 的位置引用。不暴露到 Blueprint。仅由 IItemContainer::InjectPayload NVI 调用ItemContainer.cpp:59确保位置更新与移动广播的原子性。

使用方法

UItemTracer 由 ItemFactory 创建并嵌入物品属性包,由 InjectPayload 自动更新。外部代码(如 Blueprint UI从物品属性包中获取 Tracer 引用后使用。

创建ItemFactory.cpp:17-22

if (ItemDef.bHasTracer)
{
    Instance->ItemData.AddProperty(UInternalItemProperty::ItemTracer(),
        EPropertyBagPropertyType::Object, UItemTracer::StaticClass());
    UItemTracer* NewTracer = NewObject<UItemTracer>();
    Instance->ItemData.SetValueObject(
        UInternalItemProperty::ItemTracer(), NewTracer);
}

位置更新ItemContainer.cpp:45-67 - InjectPayload NVI

void IItemContainer::InjectPayload(TUniquePtr<struct FItemInstance> Payload)
{
    if (!Payload.IsValid()) return;
    const FName PropName = UInternalItemProperty::ItemTracer();
    if (const FPropertyBagPropertyDesc* Desc =
        Payload->ItemData.FindPropertyDescByName(PropName))
    {
        if (UObject* SelfAsObject = Cast<UObject>(this))
        {
            TValueOrError<UObject*, EPropertyBagResult> Result =
                Payload->ItemData.GetValueObject(PropName);
            if (Result.HasValue())
            {
                if (UItemTracer* Tracer = Cast<UItemTracer>(Result.GetValue()))
                {
                    Tracer->SetItemLocation(SelfAsObject);
                    Tracer->OnItemMoved.Broadcast(Tracer);  // 广播移动事件
                }
            }
        }
    }
    InjectPayloadImpl(MoveTemp(Payload));
}

在 Blueprint 中绑定移动事件: UI 或任务系统通过获取物品属性包中的 Internal_ItemTracer 对象,绑定其 OnItemMoved 委托来响应物品移动。当容器调用 InjectPayload 时,委托被广播,绑定的监听方收到通知。

查询位置: 在 Blueprint 中调用 GetItemLocation 获取物品当前所在 UObject或调用 FindActorInOuterChain 追溯到所属 Actor。

用例

  • Plugins/Item/Source/Item/Public/ItemFactory.h:27 -- FOnItemMoved 委托类型声明DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam
  • Plugins/Item/Source/Item/Public/ItemFactory.h:29-57 -- UItemTracer 类定义OnItemMoved 成员 + GetItemLocation / FindActorInOuterChain / SetItemLocation 方法)。
  • Plugins/Item/Source/Item/Private/ItemFactory.cpp:17-22 -- CreateItemInstance 中当 bHasTracer 为 true 时创建 UItemTracer 并添加到属性包。
  • Plugins/Item/Source/Item/Private/ItemContainer.cpp:49 -- InjectPayload NVI 中通过 UInternalItemProperty::ItemTracer() 键名查找 Tracer。
  • Plugins/Item/Source/Item/Private/ItemContainer.cpp:57-60 -- InjectPayload 中 Cast 到 UItemTracer调用 SetItemLocation 更新位置Broadcast OnItemMoved 通知监听方。