Relational Data Tables in Unreal Engine 4
Published: 2022-02-26 15:50:41


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
1. Tie together multiple data sources
1. 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, 

```cpp
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;
};
```

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.

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

UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (RequiredAssetDataTags = "RowStructure=ArmorPiece"))
UDataTable* ArmorTable;
```

```cpp
// For a handle to a single row within a table which uses a particular struct:

UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (RowType = "AttachPoint"))
FDataTableRowHandle AttachPoint;
```

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.