The Games DevProgramming and Game Development. Tips, Tricks and Tutorials.

Custom Asset Filtering (GetAssetFilter)

· Updated Random Bits

Updated for UE 5.8: corrected how the filter function is looked up (it is not searched up the outer chain), spelled out that returning true hides the asset, and fixed the RowStructure tag handling.

GetAssetFilter (added in UE 5.5) lets you filter an asset picker with your own UFUNCTION, for things you can’t express with the usual UPROPERTY meta such as AllowedClasses.
One use case I saw recently is a DataTable picker that should also accept tables whose row struct is a child of a given struct, which the default RowType meta doesn’t do.

UPROPERTY(EditAnywhere, Category = "Data", meta = (GetAssetFilter = "MyTableRowsFilter"))
TObjectPtr<UDataTable> MyDataTable;

UFUNCTION()
bool MyTableRowsFilter(const FAssetData& AssetData) const;

How it works

The property editor (SPropertyEditorAsset) takes the objects that own the property being edited and calls FindFunction with the name from the meta on each of them. So the function must live on the same object (or its class hierarchy) that owns the property. It does not walk up the outer chain looking for a match, and an ensure fires if the function can’t be found. If the property lives inside a struct, the function goes on the UObject that contains that struct. For components the function is called on the component.

The return value is easy to get backwards: return true to filter the asset out, return false to keep it in the list.
The function is only needed in the editor, so wrap it in #if WITH_EDITOR if the class also ships in game builds (the engine does this for e.g. URectLightComponent::ShouldFilterSourceTexture).

Example filter

The RowStructure asset registry tag on a DataTable holds the row struct’s full path name (/Script/MyModule.ParentDataTableRow), so compare against GetPathName().

bool UMyObject::MyTableRowsFilter(const FAssetData& AssetData) const
{
    const UScriptStruct* ParentStruct = FParentDataTableRow::StaticStruct();

    static const FName RowStructureTagName("RowStructure");
    FString RowStructure;
    if (AssetData.GetTagValue<FString>(RowStructureTagName, RowStructure))
    {
        if (RowStructure == ParentStruct->GetPathName())
        {
            return false;
        }

        // Slow lookup, fine for an editor-only picker.
        const UScriptStruct* RowStruct = UClass::TryFindTypeSlow<UScriptStruct>(RowStructure);
        if (RowStruct && RowStruct->IsChildOf(ParentStruct))
        {
            return false;
        }
    }
    return true;
}

This allows picking DataTables whose row struct is, or inherits from, FParentDataTableRow. Struct example below.

USTRUCT(BlueprintType)
struct FParentDataTableRow : public FTableRowBase
{
    GENERATED_BODY()
};

USTRUCT(BlueprintType)
struct FChildParentRow : public FParentDataTableRow
{
    GENERATED_BODY()
};

Notes

  • TryFindTypeSlow is documented as slow and warns when given a short name rather than a path. Since the tag holds a path name here, it is fine for a picker, but it is still called for every candidate asset.
  • Meta only affects the picker UI; it doesn’t stop a bad value being set from code or pasted in.
  • I haven’t checked whether FDataTableRowHandle accepts child structs on its own, so test that before adding a filter for it.
  • There is a sibling meta, GetActorFilter, for actor pickers, taking a const AActor* instead.