I’m creating a Actor Action Utility to find all referencing and referenced actors from an actor.
I’ve digged in and found the “GetReferencers” from the FWorldPartitionActorDescInstance struct.
To get all referenced actors, I use directly the GetReferencers method and to get all referencing, I’m using GetReferencers on all the actors in the world to see if my actor is referenced
Works pretty well but with one issue:
GetReferencers doesn’t find the SoftObjectPtr. I can see the SoftRefCount set to the right value when debugging in VS but I can’t find the info on which actors are referenced via SoftObjectPtr.
Is it an info that is simply lacking?
Is there any way for me to find it?
I’ve tried using the Reference Viewer for comparison and here too I can only find the Hard Refs between actors.
Given the fact that in World Partition we’re supposed to use Soft Ptr as much as possible because of loading etc. : I believe it could be quite valuable
You’re correct in saying GetReferencers doesn’t find SoftObjectPtrs, it only returns loaded and registered hard refs.
The SoftRefCount you are seeing is incremented/decremented and only tracked numerically.
In order to find an actor referenced by a soft object ptr, you’d need to go in a different direction using AssetToolsModule and Unreal Property System (reflection).
Basically what it would do is we give it an object, and it gives us a list of everything that soft references it.
Something along the lines of:
FSoftObjectPath SoftPath(actor->GetPathName());
TArray<UObject*> SoftReferences;
FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked<FAssetToolsModule>("AssetTools");
AssetToolsModule.Get().FindSoftReferencesToObject(SoftPath, SoftReferences);
FString RefrencingAssets = "";
for (UObject* Obj : SoftReferences) //Go through all the soft references
{
if (Obj == actor)
{
continue; //Most things hold a soft reference to themselves, we don't care about this, so let's move on
}
RefrencingAssets.Append("\t" + Obj->GetFullName() + "\n");
}
Edit: The reflection part would come in to find what things the target actor is referencing.
Please let me know if the above is suffice or if you have additional questions.
Thanks for your answer : does that work with Actors ? It seems to be done for assets
Also, this will force load the asset to validate (as per comment) and the benefit of using GetReferences was to not have to load all the referenced actors and parse the entire map very quickly
Would it be possible to escalate to Epic? I’m wondering why they chose not to add a “SoftReferences” field along with the References : since they can count the number of soft refs, feels like it’s just one step away
First of all, I want to make sure you can use Reference Viewer to view soft references. You have to toggle “Show Soft References” on for that.
[Image Removed]
The GetReferences() function in FWorldPartitionActorDescInstance is created for world partition tasks specifically, so knowing the exact soft reference isn’t needed. The comment above TWorldPartitionHandle describes why WP is counting soft references at all:
/**
* FWorldPartitionHandle will increment/decrement the soft reference count on the actor descriptor.
* This won't trigger any loading, but will prevent cleanup of the actor descriptor when destroying an
* actor in the editor.
*/
typedef TWorldPartitionHandle<FWorldPartitionHandleImpl> FWorldPartitionHandle;
Tracking the source of a soft reference is more than one step away. We won’t add that to FWorldPartitionActorDescInstance since that’s not the purpose of that class.
The FindSoftReferencesToObject function that John mentions is a solid way to find soft references to something from unloaded assets. Just be aware that the implementation will load those assets.
FYI: Find-in-Blueprints (Ctrl+Shift+F) can also find some specific soft references: if they are blueprint node pins or if they are default values of BP defined variables. But blueprint search won’t cover all cases.
The SoftRefCount and HardRefCount members of FWorldPartitionActorDescInstance are not related to asset referencing.
The soft references are be in the Asset Registry for the external actors. The following should get you close to what you need:
TArray<FName> Referencers;
TArray<FName> Dependencies;
IAssetRegistry& AssetRegistry = IAssetRegistry::GetChecked();
//Query for all type of references
UE::AssetRegistry::EDependencyQuery QueryFlags = UE::AssetRegistry::EDependencyQuery::Game;
//you can specify the Hard\Soft flags if you want to restrict the search
//UE::AssetRegistry::EDependencyQuery QueryFlags |= UE::AssetRegistry::EDependencyQuery::Hard;
//UE::AssetRegistry::EDependencyQuery QueryFlags |= UE::AssetRegistry::EDependencyQuery::Soft;
//Get the list of referencers to that Actor package
AssetRegistry.GetReferencers(actorDescInstance.GetActorPackage(), Referencers, UE::AssetRegistry::EDependencyCategory::Package, QueryFlags);
//Get the list of Dependencies that are referenced by the Actor package
AssetRegistry.GetDependencies(actorDescInstance.GetActorPackage(), Dependencies, UE::AssetRegistry::EDependencyCategory::Package, QueryFlags);
It should still work for actors, I tested it out and in the debugger the string var had the name of the object that was soft referencing the target actor.
That being said, for finding what things reference the target object without force loading is something I am unsure of and can go ahead and escalate this to Epic for additional ideas if the former method is undesirable.
I wanted to add/edit my earlier reply about reflection to be more precise - we can use reflection to find what things the target actor is referencing. It would look something like this.
for (TFieldIterator<FProperty> PropIt(actor->GetClass()); PropIt; ++PropIt) //Reflect through this object's properties to find where the soft references are
{
FProperty* Property = *PropIt;
void* Value = Property->ContainerPtrToValuePtr<void>(Obj);
if (Value != nullptr)
{
if (CastField<const FMapProperty>(Property)) //Is this Property a Map?
{
FScriptMapHelper MapHelper(CastField<const FMapProperty>(Property), Value);
if (CastField<const FSoftObjectProperty>(MapHelper.ValueProp)) //Is the Value pair to this map a soft object property
{
for (int i = 0; i < MapHelper.Num(); i++)
{
if (!MapHelper.IsValidIndex(i))
{
continue;
}
FSoftObjectPtr SoftProp = FSoftObjectProperty::GetPropertyValue(MapHelper.GetValuePtr(i));
if (SoftProp != nullptr)
{
//Found a soft object ptr
}
}
}
}
else if (CastField<const FSoftObjectProperty>(Property)) //Is this Property a soft object pointer?
{
FSoftObjectPtr SoftProp = FSoftObjectProperty::GetPropertyValue(Value);
if (SoftProp != nullptr)
{
//Found a soft object ptr
}
}
}
}
What I’m trying to get is a way to retrieve all the references, soft and hard, from an actor to any actors in the world and from any actors in this world to that actor
Using the FindSoftReferencesToObject can work to find soft references to that Actor but I won’t be able to get the references from that actor this way (without loading all the other actors in the world partition) if I understand correctly
But maybe there’s a hidden gem somewhere already to do that? I’ve looked but couldn’t find it
Objective for me is to offer a way for my LDs to find actor’s references easily