<aside> 🗒️ Part of Ari's Unreal Engine Notes.

</aside>

Untracked is a property metadata that allows you to make a soft pointer to an asset without that soft pointer counting as a cooking dependency. Currently it can only be added in C++ for non-arrays.

A good use case example for using Untracked is if you want to make a soft pointer to a Primary Asset (like a Map) without it messing with the Primary Asset's chunking rules (actor in a level with high prio chunking rule will override the chunking rule of another level which it points to with a soft pointer).

// A sample of a soft pointer to some primary asset that's been set to be "Untracked".
UPROPERTY(Meta=(Untracked))
TSoftObjectPtr<ASomePrimaryAssetType> SomePrimaryAssetSoftPtr;

Here are instructions for how to enable support for setting this metadata in blueprints in the editor, and for supporting untracked arrays of soft pointers:

To add support for arrays of soft pointers

In FSoftObjectPathThreadContext::GetSerializationOptions in SoftObjectPath.cpp change the part handling Untracked to:

static FName UntrackedName = TEXT("Untracked");
FField* ParentField = CurrentProperty ? CurrentProperty->Owner.ToField() : nullptr;
bool bIsPropertyUntracked = CurrentProperty && CurrentProperty->HasMetaData(UntrackedName);
bool bIsParentArrayPropertyUntracked = 
	ParentField
	&& ParentField->IsA(FArrayProperty::StaticClass())
	&& ParentField->HasMetaData(UntrackedName);
if (bIsPropertyUntracked || bIsParentArrayPropertyUntracked)
{
	// Property has the Untracked metadata, so set to never collect references
	CurrentCollectType = ESoftObjectPathCollectType::NeverCollect;
}

To add support for adding Untracked meta to blueprints in the Editor

In BlueprintDetailsCustomization.cpp/.h copy these functions:

ECheckBoxState OnGetExposedToSpawnCheckboxState() const;
void OnExposedToSpawnChanged(ECheckBoxState InNewState);
EVisibility ExposeOnSpawnVisibility() const;

and remake them, with ExposeOnSpawn replaced with Untracked. Then to make the visibility only show on Soft properties:

EVisibility FBlueprintVarActionDetails::UntrackedVisibility() const
{
	FProperty* VariableProperty = CachedVariableProperty.Get();
	if (VariableProperty && GetPropertyOwnerBlueprint())
	{
		// If we have an array we want to know what type of array it is
		FField* TargetField = VariableProperty->IsA(FArrayProperty::StaticClass())
			? CastField<FArrayProperty>(VariableProperty)->Inner
			: VariableProperty;

		const bool bIsSoftObjectProperty = TargetField->IsA(FSoftObjectProperty::StaticClass());

		const FName StructPropertyClassName = TargetField->IsA(FStructProperty::StaticClass()) ? CastField<FStructProperty>(TargetField)->Struct->GetFName() : FName();
		const bool bIsSoftPathProperty = StructPropertyClassName == TEXT("SoftObjectPath") || StructPropertyClassName == TEXT("SoftClassPath");

		if (bIsSoftObjectProperty || bIsSoftPathProperty)
		{
			return EVisibility::Visible;
		}
	}
	return EVisibility::Collapsed;
}