<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:
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;
}
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;
}