vault backup: 2024-10-12 17:19:45

This commit is contained in:
2024-10-12 17:19:46 +08:00
parent ff94ddca61
commit 244c0c52f6
960 changed files with 31348 additions and 10 deletions

View File

@@ -0,0 +1,97 @@
# AllowAnyActor
- **功能描述:** 用在ComponentReference属性上在UseComponentPicker的情况下使得组件选取器扩大到场景里其他Actor下的其他组件。
- **使用位置:** UPROPERTY
- **引擎模块:** Component Property
- **元数据类型:** bool
- **限制类型:** FComponentReferenceFSoftComponentReference
- **关联项:** [UseComponentPicker](UseComponentPicker/UseComponentPicker.md)
- **常用程度:** ★★
用在ComponentReference属性上在UseComponentPicker的情况下使得组件选取器扩大到场景里其他Actor下的其他组件。
- 也要注意到这个AllowAnyActor影响的只是UI上的组件选择。一个ComponentReference即使不加AllowAnyActor也可以通过ReferencedActor引用到别的Actor然后手填其属下的组件名字。然后可以正常的在C++里GetComponent里出来正确的组件对象。因此AllowAnyActor跟逻辑无关。
测试代码和效果见UseComponentPicker。
## 原理:
主要是FComponentReferenceCustomization。根据源码查看bAllowAnyActor 只在已经有bUseComponentPicker的情况下生效且用来对Actor列表进行过滤。
```cpp
void FComponentReferenceCustomization::CustomizeHeader(TSharedRef<IPropertyHandle> InPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils)
{
PropertyHandle = InPropertyHandle;
CachedComponent.Reset();
CachedFirstOuterActor.Reset();
CachedPropertyAccess = FPropertyAccess::Fail;
bAllowClear = false;
bAllowAnyActor = false;
bUseComponentPicker = PropertyHandle->HasMetaData(NAME_UseComponentPicker);
bIsSoftReference = false;
if (bUseComponentPicker)
{
FProperty* Property = InPropertyHandle->GetProperty();
check(CastField<FStructProperty>(Property) &&
(FComponentReference::StaticStruct() == CastFieldChecked<const FStructProperty>(Property)->Struct ||
FSoftComponentReference::StaticStruct() == CastFieldChecked<const FStructProperty>(Property)->Struct));
bAllowClear = !(InPropertyHandle->GetMetaDataProperty()->PropertyFlags & CPF_NoClear);
bAllowAnyActor = InPropertyHandle->HasMetaData(NAME_AllowAnyActor);
bIsSoftReference = FSoftComponentReference::StaticStruct() == CastFieldChecked<const FStructProperty>(Property)->Struct;
BuildClassFilters();
BuildComboBox();
InPropertyHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FComponentReferenceCustomization::OnPropertyValueChanged));
// set cached values
{
CachedComponent.Reset();
CachedFirstOuterActor = GetFirstOuterActor();
FComponentReference TmpComponentReference;
CachedPropertyAccess = GetValue(TmpComponentReference);
if (CachedPropertyAccess == FPropertyAccess::Success)
{
CachedComponent = TmpComponentReference.GetComponent(CachedFirstOuterActor.Get());
if (!IsComponentReferenceValid(TmpComponentReference))
{
CachedComponent.Reset();
}
}
}
HeaderRow.NameContent()
[
InPropertyHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
ComponentComboButton.ToSharedRef()
]
.IsEnabled(MakeAttributeSP(this, &FComponentReferenceCustomization::CanEdit));
}
else
{
HeaderRow.NameContent()
[
InPropertyHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
InPropertyHandle->CreatePropertyValueWidget()
]
.IsEnabled(MakeAttributeSP(this, &FComponentReferenceCustomization::CanEdit));
}
}
bool FComponentReferenceCustomization::IsFilteredActor(const AActor* const Actor) const
{
return bAllowAnyActor || Actor == CachedFirstOuterActor.Get();
}
```

View File

@@ -0,0 +1,56 @@
# BlueprintSpawnableComponent
- **功能描述:** 允许该组件出现在Actor蓝图里Add组件的面板里。
- **使用位置:** UCLASS
- **引擎模块:** Component Property
- **元数据类型:** bool
- **限制类型:** Component类
- **常用程度:** ★★★★
允许该组件出现在Actor蓝图里Add组件的面板里。
在蓝图节点上不管有没有BlueprintSpawnableComponent则都是可以添加该组件的。
## 测试代码:
```cpp
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent))
class INSIDER_API UMyActorComponent_Spawnable : public UActorComponent
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float MyFloat;
};
UCLASS(Blueprintable)
class INSIDER_API UMyActorComponent_NotSpawnable : public UActorComponent
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float MyFloat;
};
```
## 蓝图中效果:
可以看到在Actor的左边Add的按钮下UMyActorComponent_Spawnable 可以被添加进去但是UMyActorComponent_NotSpawnable 被阻止了。但同时也要注意到如果在蓝图中AddComponent节点则是都可以的。
![Untitled](Untitled.png)
![Untitled](Untitled%201.png)
## 原理:
```cpp
bool FKismetEditorUtilities::IsClassABlueprintSpawnableComponent(const UClass* Class)
{
// @fixme: Cooked packages don't have any metadata (yet; they might become available via the sidecar editor data)
// However, all uncooked BPs that derive from ActorComponent have the BlueprintSpawnableComponent metadata set on them
// (see FBlueprintEditorUtils::RecreateClassMetaData), so include any ActorComponent BP that comes from a cooked package
return (!Class->HasAnyClassFlags(CLASS_Abstract) &&
Class->IsChildOf<UActorComponent>() &&
(Class->HasMetaData(FBlueprintMetadata::MD_BlueprintSpawnableComponent) || Class->GetPackage()->bIsCookedForEditor));
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 KiB

View File

@@ -0,0 +1,113 @@
# UseComponentPicker
- **功能描述:** 用在ComponentReference属性上使得选取器的列表里展示出Actor属下的Component以便选择。
- **使用位置:** UPROPERTY
- **引擎模块:** Component Property
- **元数据类型:** bool
- **限制类型:** FComponentReferenceFSoftComponentReference
- **关联项:** [AllowAnyActor](../AllowAnyActor.md)
- **常用程度:** ★★
用在ComponentReference属性上使得选取器的列表里展示出Actor属下的Component以便选择。
- 默认情况下FComponentReference的Referenced Actor属性展开的选择器列表是让你选择场景里的Actor因此并不会把该Actor下的组件也都显示出来。而ComponentReference下的ComponentName属性需要玩家手动填写。这种方式比较原始也容易出错。
- 因此加上UseComponentPicker后就可以显示出组件列表来选择。但是又默认限制是当前Actor属下的所有组件不包括场景里其他Actor里的组件。
- 如果想要进一步把场景里所有Actor下的所有组件都列出来则需要进一步加上AllowAnyActor以扩大筛选范围。
- ComponentReference的属性类型有两种FComponentReference和FSoftComponentReference二者都对应了FComponentReferenceCustomization。测试代码为简洁就没有列出FSoftComponentReference。
## 测试代码:
```cpp
UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Category = "UseComponentPickerTest")
FComponentReference MyComponentReference_NoUseComponentPicker;
UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Category = "UseComponentPickerTest", meta = (UseComponentPicker))
FComponentReference MyComponentReference_UseComponentPicker;
UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Category = "UseComponentPicker_AllowAnyActor_Test", meta = (UseComponentPicker,AllowAnyActor))
FComponentReference MyComponentReference_UseComponentPicker_AllowAnyActor;
```
## 测试效果:
- 可见默认的第一个列出了所有Actor但是ComponentName需要手写。
- 第二个加上UseComponentPicker后列出了当前Actor下的所有组件但是不能选择到其他Actor的组件。
- 第三个继续加上AllowAnyActor后列出了所有Actor的所有组件。
![UseComponentPicker](UseComponentPicker.jpg)
## 原理:
FComponentReference和FSoftComponentReference二者都对应了FComponentReferenceCustomization。看源码可发现用上bUseComponentPicker后会专门创建ClassFilters和ComboBox就是采用不同的类型过滤器和不同的UI来选择组件。否则else分支就是很朴素的结构属性展开编辑。
```cpp
void FComponentReferenceCustomization::CustomizeHeader(TSharedRef<IPropertyHandle> InPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils)
{
PropertyHandle = InPropertyHandle;
CachedComponent.Reset();
CachedFirstOuterActor.Reset();
CachedPropertyAccess = FPropertyAccess::Fail;
bAllowClear = false;
bAllowAnyActor = false;
bUseComponentPicker = PropertyHandle->HasMetaData(NAME_UseComponentPicker);
bIsSoftReference = false;
if (bUseComponentPicker)
{
FProperty* Property = InPropertyHandle->GetProperty();
check(CastField<FStructProperty>(Property) &&
(FComponentReference::StaticStruct() == CastFieldChecked<const FStructProperty>(Property)->Struct ||
FSoftComponentReference::StaticStruct() == CastFieldChecked<const FStructProperty>(Property)->Struct));
bAllowClear = !(InPropertyHandle->GetMetaDataProperty()->PropertyFlags & CPF_NoClear);
bAllowAnyActor = InPropertyHandle->HasMetaData(NAME_AllowAnyActor);
bIsSoftReference = FSoftComponentReference::StaticStruct() == CastFieldChecked<const FStructProperty>(Property)->Struct;
BuildClassFilters();
BuildComboBox();
InPropertyHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FComponentReferenceCustomization::OnPropertyValueChanged));
// set cached values
{
CachedComponent.Reset();
CachedFirstOuterActor = GetFirstOuterActor();
FComponentReference TmpComponentReference;
CachedPropertyAccess = GetValue(TmpComponentReference);
if (CachedPropertyAccess == FPropertyAccess::Success)
{
CachedComponent = TmpComponentReference.GetComponent(CachedFirstOuterActor.Get());
if (!IsComponentReferenceValid(TmpComponentReference))
{
CachedComponent.Reset();
}
}
}
HeaderRow.NameContent()
[
InPropertyHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
ComponentComboButton.ToSharedRef()
]
.IsEnabled(MakeAttributeSP(this, &FComponentReferenceCustomization::CanEdit));
}
else
{
HeaderRow.NameContent()
[
InPropertyHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
InPropertyHandle->CreatePropertyValueWidget()
]
.IsEnabled(MakeAttributeSP(this, &FComponentReferenceCustomization::CanEdit));
}
}
```