100 lines
4.6 KiB
Markdown
Raw Normal View History

2024-10-12 17:19:46 +08:00
# 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;
}
}
```