# 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):** ```cpp if (ItemDef.bHasTracer) { Instance->ItemData.AddProperty(UInternalItemProperty::ItemTracer(), EPropertyBagPropertyType::Object, UItemTracer::StaticClass()); UItemTracer* NewTracer = NewObject(); Instance->ItemData.SetValueObject( UInternalItemProperty::ItemTracer(), NewTracer); } ``` **位置更新(ItemContainer.cpp:45-67 - InjectPayload NVI):** ```cpp void IItemContainer::InjectPayload(TUniquePtr Payload) { if (!Payload.IsValid()) return; const FName PropName = UInternalItemProperty::ItemTracer(); if (const FPropertyBagPropertyDesc* Desc = Payload->ItemData.FindPropertyDescByName(PropName)) { if (UObject* SelfAsObject = Cast(this)) { TValueOrError Result = Payload->ItemData.GetValueObject(PropName); if (Result.HasValue()) { if (UItemTracer* Tracer = Cast(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 通知监听方。