vault backup: 2024-10-12 17:19:45
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
# AllowAnyActor
|
||||
|
||||
- **功能描述:** 用在ComponentReference属性上,在UseComponentPicker的情况下使得组件选取器扩大到场景里其他Actor下的其他组件。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Component Property
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** FComponentReference,FSoftComponentReference
|
||||
- **关联项:** [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();
|
||||
}
|
||||
|
||||
```
|
@@ -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节点则是都可以的。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
```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 |
@@ -0,0 +1,113 @@
|
||||
# UseComponentPicker
|
||||
|
||||
- **功能描述:** 用在ComponentReference属性上,使得选取器的列表里展示出Actor属下的Component以便选择。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Component Property
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** FComponentReference,FSoftComponentReference
|
||||
- **关联项:** [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的所有组件。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
```
|
Reference in New Issue
Block a user