DEV Community

Cover image for Relational Data Tables in Unreal Engine 4
Nick Lucas
Nick Lucas

Posted on • Edited on

Relational Data Tables in Unreal Engine 4

I had an interesting problem with Unreal Engine today. I have a Mech character which I want to attach stuff to, maybe it's segments of armour, or internal components, or weapons and other "stuff". Managing all these attach points and attachments is a pain, so I wanted to codify it in a data model, using Data Assets and Data Tables. This way I can have 100 mechs in the future with different skeletons and varieties of attachments, and codify them entirely as data with a single "MechCharacter".

Given my background as a full stack software engineer, my instinct it to reach for a relational database of sorts, which can:

  1. Drive common behaviour with data
  2. Tie together multiple data sources
  3. Self validate and restrict inputs

This isn't necessarily a complete or cohesive list. I'm writing this quite quickly. But basically I want to build a data model and code which gives me an amazing developer experience while building future assets. No weird bugs because I made a minor typo in one row somewhere!

Lastly, maybe there's even more to this I haven't found yet? Maybe there's a superior way to do it? Maybe a best practices issue I'm going to hit down the line? Let me know in the comments!


So let's say I have these 3 structs and an overarching Data Asset. Each struct will be used to create a Data Table in the editor,

USTRUCT(BlueprintType)
struct FAttachPoint : public FTableRowBase
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        FName Bone;
};

USTRUCT(BlueprintType)
struct FArmorPiece : public FTableRowBase
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        FName AttachPointRowKey;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        UStaticMesh* Mesh;
};

USTRUCT(BlueprintType)
struct FHardpoint : public FTableRowBase
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        FName AttachPointRowKey;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        UStaticMesh* Mesh;
};

UCLASS()
class MECHGAME_API UDA_MechDefinition : public UDataAsset
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadOnly)
        USkeletalMesh* Mesh;

    UPROPERTY(EditAnywhere, BlueprintReadOnly)
        UDataTable* ArmorTable;

    UPROPERTY(EditAnywhere, BlueprintReadOnly)
        UDataTable* HardpointsTable;
};
Enter fullscreen mode Exit fullscreen mode

This is not ideal, because ArmorPiece and Hardpoint Data Tables just expect a row key of an AttachPoint, but I could make a typo, or rename a row and forget to update other data. What if UE4's editor could restrict those FNames to only keys found in a particular AttachPoint Data Table?

Well UE4 actually has some buried ways to achieve this.

// For a reference to a table which uses a particular struct:

UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (RequiredAssetDataTags = "RowStructure=ArmorPiece"))
UDataTable* ArmorTable;
Enter fullscreen mode Exit fullscreen mode
// For a handle to a single row within a table which uses a particular struct:

UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (RowType = "AttachPoint"))
FDataTableRowHandle AttachPoint;
Enter fullscreen mode Exit fullscreen mode

The new meta information informs the editor how to provide lists of data, restricted by struct type which makes it harder to make mistakes when configuring data models later.

Top comments (0)