Storing an array of different structures

So I’m trying to develop a way for a user to design a message, which has components attached to it using structures.

Here’s my structure that will contain the entire message:

USTRUCT(BlueprintType)
struct FMessageData
{
	GENERATED_USTRUCT_BODY();

        UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Data")
        WhatGoesHere Components;
};

The message would contain an array of components, but each component has a different structure defintion. For example:

USTRUCT(BlueprintType)
struct FButtonComponent
{
	GENERATED_USTRUCT_BODY();

	int Type = 2;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Data")
	int Style = 1;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Data")
	FString Label;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Data")
	FEmoji Emoji = FEmoji();
};

USTRUCT(BlueprintType)
struct FStringSelectComponent: public FMessageComponent
{
	GENERATED_USTRUCT_BODY();

	int Type = 3;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Data")
	FString CustomID;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Data")
	TArray<FSelectOptions> Options;
};

Is there a way for me to allow the user to add the different types of structure to the Components array or is there another approach I can take?

I have tried:

  1. Using a base class and use TArray<FBaseComponent> Components so the other components inherit from it.
  2. Using Unions but they cannot be used on a UPROPERTY.
  3. Using templates but they cannot be used on a USTRUCT.
    but none of these work.

Polymorphic structs are not trivial to do in unreal.

The only example of it, that I know of, is the FGameplayAbilityTargetData you can look into the ability system on how it’s created and used.

Creating an array out of TSharedPtr would allow C++ users to add custom data to it and use this data somewhere else.

Unreal is way more easy going when it is concerned with objects. So depending on your usecase it might be easier to create a new object and use this to send data around. You could create a base type UBaseMessageData inheriting from UOnject and the message has an array of those.

If you have data to be generated in the editor you can make the type instanced which would allow you to create the data inside the Array.

UObjects

Advantages:

  • Easy to create
  • Easy to use
  • Blueprints integration some what easy

Disadvantages:

  • Slower on creation, so if you need to create a lot of messages every frame this might become an issue
  • Can’t use it to send messages between client - server in multiplayer

Structs

Advantages:

  • Easier to send over network
  • Faster (should only matter if it’s a big amount)

Disadvantages:

  • Hard to create
  • Hard to use
  • No Blueprints integration would need to write helper ufunctions for everything