Please fix FComponentReference to allow easy reference to other child actors within a blueprint.

Please fix FComponentReference. I want to be able to use Blueprint to build level chunks. To this end, I have a defined a UActorGroupSelectorComponent which allows me to easily turn on and off different door groups. However since there are no way to refer to another child actor this is impossible.


USTRUCT(BlueprintType)
struct FCourageSelectionGroup
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere)
	FString Name = "";

	UPROPERTY(EditAnywhere)
	FString Pattern;

	UPROPERTY(EditAnywhere)
	TArray<TSoftObjectPtr<AActor>> References;

	UPROPERTY(EditAnywhere, meta=(GetOptions=GetGroupNames))
	TArray<FString> IncludedGroupNames;

	operator bool() const
	{
		return Name != "";
	}
};


UCLASS(ClassGroup =Courage, meta = (BlueprintSpawnableComponent))
class COURAGE_API UCourageGroupSelectorComponent : public UCourageActorComponent
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, Category=Courage, meta=(TitleProperty=Name))
	TArray<FCourageSelectionGroup> Groups;

	UPROPERTY(EditAnywhere, Category=Courage, meta=(GetOptions=GetGroupNames))
	TArray<FString> ActiveGroupNames;

	UCourageGroupSelectorComponent(const class FObjectInitializer& Init);

	void InitializeComponent() override;

	void PostLoad() override;

	const FCourageSelectionGroup& GetGroup(const FString& GroupName) const;

	FCourageSelectionGroup& GetGroup(const FString& GroupName);

	void ActivateGroup(FCourageSelectionGroup& Group, bool Activated);

	void SelectGroup(const TArray<FString>& GroupNames);

	void DeselectGroup(const TArray<FString>& GroupNames);

	void DestroyGroup(const FCourageSelectionGroup& Group);

	void DestroyGroup(const FString& GroupName);

	void DestroyGroupsExcept(const TSet<FString>& GroupNames);

#if WITH_EDITOR
	virtual void PostEditChangeProperty(FPropertyChangedEvent&) override;
	virtual void PostEditChangeChainProperty(FPropertyChangedChainEvent&) override;
#endif

protected:
	UFUNCTION(CallInEditor)
	TArray<FString> GetGroupNames() const;

};

Hey Olivier, the feature request to let FComponentReference point to a component in the blueprint’s hierarchy is quite common. Unfortunately we haven’t done this due to challenges with referencing components in a stable way across blueprint compilations.

The request is backlogged internally but I’ll add your request to the list of use cases internally so that we know how often it’s requested. It may help prioritizing it.

The workaround I suggest for the time being is to refer to components and child actor via a manually entered FName property and resolving it at BeginPlay with AActor::FindComponent. This is typo-prone yes, but best we have for now.

1 Like

It would be great, I am struggling to use existing solutions to create modular level pieces. Level Instances are great but do not allow per instance variations. Packed Level actors lack the ability to contain anything else but meshes (also isn’t synced with level automatically). So Blueprint, seemed like my last recourse but it is lacking the ability to reference itself (or comprehensive editor, allowing to turn on and off visibility for different static mesh components)

In the end, I have settled on using third party Prefabricator plugin, but it seems less than desirable.

Thank you for your feed back.

1 Like

On a related note, In this forum post I mentioned how Packed Level Actor could be improved by naming component appropriately.

Could we get an update on whether it would be possible to name components appropriately at least?

One of my biggest gripe with PackedLevelActor is that all the InstancedStaticMesh components lose their name correspondence with their StaticMeshActor counterpart.

This makes it difficult to write construction script referring to the components. I believe the problem is due to how unlike actors, components do not have distinct names and label.

Come on guys its such an easy fix:

	template<class T>
	T* AddPackedComponent(TSubclassOf<T> ComponentClass, const FName& InComponentName = NAME_None)
	{
		Modify();
		FName NewComponentName = InComponentName == NAME_None ? *FComponentEditorUtils::GenerateValidVariableName(ComponentClass, this) : InComponentName;
		T* NewComponent = NewObject<T>(this, ComponentClass, NewComponentName, RF_Transactional);
		AddInstanceComponent(NewComponent);
		NewComponent->ComponentTags.Add(GetPackedComponentTag());
		return NewComponent;
	}
uint32 FPackedLevelActorISMBuilder::PackActors(FPackedLevelActorBuilderContext& InContext, const FPackedLevelActorBuilderClusterID& InClusterID, const TArray<UActorComponent*>& InComponents) const
{
...

	FName ComponentName = NAME_None;
	if (InComponents.Num() > 0)
		ComponentName = FName(*InComponents[0]->GetOwner()->GetActorLabel());
	UInstancedStaticMeshComponent* PackComponent = PackingActor->AddPackedComponent<UInstancedStaticMeshComponent>(ComponentClass, ComponentName);
	PackComponent->AttachToComponent(PackingActor->GetRootComponent(), FAttachmentTransformRules::SnapToTargetIncludingScale);