# FItemInstance ## 基本信息 - **类型**: USTRUCT - **父类**: (无) - **源文件**: Plugins/Item/Source/Item/Public/ItemFactory.h - **模块**: Item ## 功能概述 单个运行时物品的内部重量级表示。包含唯一GUID、类型键,以及FInstancedPropertyBag中的动态属性。由容器通过TUniquePtr独占拥有。具有friend class ItemFactory用于受控构造。 ## 设计用意 物品的运行时真值源。刻意不作为BlueprintType公开。TUniquePtr所有权确保清晰的单拥有者语义。FInstancedPropertyBag允许每个物品拥有任意的动态属性。友元控制构造防止产生孤立物品。 ## 职责范围 持有单个物品实例的所有运行时状态。通过TUniquePtr在容器间经由InjectPayload传递。不向容器/工厂外部暴露修改接口。 ## 项目内依赖 (无项目内依赖) ## 对外接口 FItemInstance 是内部使用的 USTRUCT(非 BlueprintType),不作为公共 API 直接暴露给外部代码。其字段均标记为 UPROPERTY()(无 BlueprintReadOnly),供容器和工厂内部访问。 外部调用方不应直接创建或修改 FItemInstance。与 FItemInstance 交互的唯一入口是通过以下间接途径: - **创建**: 通过 UDefaultContainer::CreateItem(或 IItemContainer::CreateItem),内部调用 ItemFactory::CreateItemInstance。 - **查询**: 通过 IItemContainer::GetItemViews() 获取 FItemView 快照,而非直接访问 FItemInstance。 - **属性读写**: 通过 IItemContainer::GetItemProperty / SetItemProperty,而非直接操作 FItemInstance::ItemData。 内部字段供 ItemFactory 和容器实现者使用: - **ItemID** (FGuid): 物品唯一标识,由工厂在创建时通过 FGuid::NewGuid() 生成。 - **ItemType** (FName): 物品类型名称,对应 DataTable 中的行名,用于在注册表中查找 FItemDef。 - **ItemData** (FInstancedPropertyBag): 物品的动态属性包。包含从 FItemDef::DefaultItemProps 转换来的属性,以及可选的 OverrideProps 合并值。当 bHasTracer 为 true 时还包含 Internal_ItemTracer 键。 所有权模型:FItemInstance 只能通过 TUniquePtr 持有,禁止复制(拷贝构造 / 赋值运算符保留但标记为 default,实际应避免使用)。移动语义开放(移动构造和移动赋值 = default),支持在容器间转移所有权。 ## 使用方法 FItemInstance 不直接被外部代码创建或操作。外部代码通过容器接口间接交互。 **创建(仅通过 ItemFactory):** ```cpp // ItemFactory.cpp:6-24 TUniquePtr ItemFactory::CreateItemInstance( const FItemDef& ItemDef, FName ItemType, const FInstancedPropertyBag* OverrideProps) { TUniquePtr Instance = MakeUnique(); Instance->ItemID = FGuid::NewGuid(); Instance->ItemType = ItemType; ConvertDefaultProps(ItemDef.DefaultItemProps, Instance->ItemData); if (OverrideProps) MergePropertyBag(*OverrideProps, Instance->ItemData); if (ItemDef.bHasTracer) { Instance->ItemData.AddProperty(UInternalItemProperty::ItemTracer(), EPropertyBagPropertyType::Object, UItemTracer::StaticClass()); UItemTracer* NewTracer = NewObject(); Instance->ItemData.SetValueObject( UInternalItemProperty::ItemTracer(), NewTracer); } return Instance; } ``` **存储(由 UDefaultContainer 管理):** ```cpp // DefaultContainer.h:33 TArray> Items; // DefaultContainer.cpp:129-135 - 注入存储 void UDefaultContainer::InjectPayloadImpl(TUniquePtr Payload) { if (Payload.IsValid()) Items.Add(MoveTemp(Payload)); } ``` **读取属性(由容器内部处理):** 容器通过 ItemData 读取属性值和描述符。例如 DefaultContainer.cpp:137-187 的 Internal_GetPropertyRaw 中: ```cpp const FPropertyBagPropertyDesc* Desc = Bag->FindPropertyDescByName(FixedName); void* BagMemory = FoundItem->ItemData.GetMutableValue().GetMemory(); void* SourceAddr = Desc->CachedProperty->ContainerPtrToValuePtr(BagMemory); ``` **在所有容器间转移所有权:** 通过 MoveTemp + InjectPayload 组合操作。物品的 TUniquePtr 所有权从源容器移至目标容器(DefaultContainer.cpp:104-108)。 ## 用例 - `Plugins/Item/Source/Item/Public/ItemFactory.h:60-82` -- FItemInstance 结构体定义(ItemID、ItemType、ItemData 三个字段 + 友元声明 + 构造/移动/拷贝控制)。 - `Plugins/Item/Source/Item/Private/ItemFactory.cpp:6-24` -- ItemFactory::CreateItemInstance 创建 FItemInstance 的唯一入口(MakeUnique + 填充字段 + 属性转换 + Tracer 创建)。 - `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:60-64` -- GetItemViews 遍历 Items 数组中的 TUniquePtr 并解引用传递给 FItemViewFactory。 - `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:73-78` -- GetItemViewByID 按 ID 匹配 Items 中的 FItemInstance 指针。 - `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:96-108` -- MoveItem 通过 MoveTemp 转移 FItemInstance 所有权,从源数组 RemoveAt 后注入目标容器。 - `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:121-124` -- CreateItem 接收工厂返回的 TUniquePtr 并注入自身。 - `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:129-134` -- InjectPayloadImpl 接收 TUniquePtr 并 Add 到 Items 数组。 - `Plugins/Item/Source/Item/Private/DefaultContainer.cpp:140-186` -- Internal_GetPropertyRaw 从 FoundItem->ItemData 中按属性名称读取值。 - `Plugins/Item/Source/Item/Private/ItemContainer.cpp:45-67` -- InjectPayload NVI 从 Payload->ItemData 中读取 Tracer 并更新位置。 - `Plugins/Item/Source/Item/Private/ItemViewFactory.cpp:11-19` -- PopulateCommon 从 Instance.ItemID / Instance.ItemType 读取字段填入 FItemView。