# NonPIEDuplicateTransient

- **功能描述:** 在对象复制的时候,且在不是PIE的场合,忽略该属性。

- **元数据类型:** bool
- **引擎模块:** Serialization
- **作用机制:** 在PropertyFlags中加入[CPF_NonPIEDuplicateTransient](../../../../Flags/EPropertyFlags/CPF_NonPIEDuplicateTransient.md)
- **常用程度:** ★

在对象复制的时候,且在不是PIE的场合,忽略该属性。

- DuplicateTransient和NonPIEDuplicateTransient的区别是,前者在任何情况的对象复制时都忽略该属性,而后者在PIE的时候(也是在发生对象复制过程)依然会复制该属性,其他情况下的复制和前者行为一致。
- PIE的时候本质就是把当前的编辑World里Actor复制一份到PIE的世界里,会触发Actor的复制。

## 示例代码:

准备了一份DataAsset和Actor来分别验证复制行为的不同。

```cpp
UCLASS(Blueprintable, BlueprintType)
class INSIDER_API UMyProperty_Serialization :public UDataAsset
{
public:
	GENERATED_BODY()
public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		int32 MyInt_Default = 123;
		//PropertyFlags:	CPF_Edit | CPF_BlueprintVisible | CPF_ZeroConstructor | CPF_Transient | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPublic 
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Transient)
		int32 MyInt_Transient = 123;
		//PropertyFlags:	CPF_Edit | CPF_BlueprintVisible | CPF_ZeroConstructor | CPF_DuplicateTransient | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPublic 
	UPROPERTY(EditAnywhere, BlueprintReadWrite, DuplicateTransient)
		int32 MyInt_DuplicateTransient = 123;
		//PropertyFlags:	CPF_Edit | CPF_BlueprintVisible | CPF_ZeroConstructor | CPF_IsPlainOldData | CPF_NoDestructor | CPF_NonPIEDuplicateTransient | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPublic 
	UPROPERTY(EditAnywhere, BlueprintReadWrite, NonPIEDuplicateTransient)
		int32 MyInt_NonPIEDuplicateTransient = 123;
};

UCLASS(Blueprintable, BlueprintType)
class INSIDER_API AMyProperty_Serialization_TestActor :public AActor
{
public:
	GENERATED_BODY()
protected:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		int32 MyInt_Default = 123;
		//PropertyFlags:	CPF_Edit | CPF_BlueprintVisible | CPF_ZeroConstructor | CPF_Transient | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPublic 
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Transient)
		int32 MyInt_Transient = 123;
		//PropertyFlags:	CPF_Edit | CPF_BlueprintVisible | CPF_ZeroConstructor | CPF_DuplicateTransient | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPublic 
	UPROPERTY(EditAnywhere, BlueprintReadWrite, DuplicateTransient)
		int32 MyInt_DuplicateTransient = 123;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, NonPIEDuplicateTransient)
		int32 MyInt_NonPIEDuplicateTransient = 123;
};
```

## 示例效果:

在对资产进行Duplidate的时候,发生DuplicateAsset然后DuplicateObject,这个时候PortFlags=PPF_Duplicate,然后会触发ShouldSerializeValue进行判断。这个时候会跳过该属性。

可以看到NonPIEDuplicateTransient并不会被复制。

![Untitled](Untitled.png)

在点击PIE的时候,可以看到NonPIEDuplicateTransient这个时候却是会复制值过去了。这是因为这个时候PortFlags=PPF_DuplicateForPIE&PPF_Duplicate

![Untitled](Untitled%201.png)

结论是用于一些Cache数据,在复制的时候并不需要序列化复制,这样可以阻止两个不同的Actor采用同一份计算后的临时数据。但是又可以在PIE的时候,让Actor各自采用自己的一份数据,因为PIE的时候,本质就是把当前的编辑World里Actor复制一份到PIE的世界里,会触发Actor的复制。

## 原理:

在文本导出的的时候,在不是PIE里的复制的时候,不序列化该属性。

```cpp
bool FProperty::ShouldPort( uint32 PortFlags/*=0*/ ) const
{
// if we're not copying for PIE and NonPIETransient is set, don't export
	if (!(PortFlags & PPF_DuplicateForPIE) && HasAnyPropertyFlags(CPF_NonPIEDuplicateTransient))
	{
		return false;
	}
}
```

在二进制序列化的时候:

只有在PPF_Duplicate生效的时候,(DuplicateObject?或者资产复制),才会跳过该属性。但是在PIE的时候,又要继续序列化。

```cpp
bool FProperty::ShouldSerializeValue(FArchive& Ar) const
{
// Skip properties marked NonPIEDuplicateTransient when duplicating, but not when we're duplicating for PIE
	if ((PropertyFlags & CPF_NonPIEDuplicateTransient) && !(Ar.GetPortFlags() & PPF_DuplicateForPIE) && (Ar.GetPortFlags() & PPF_Duplicate))
	{
		return false;
	}
}
```