EM_Task/CoreUObject/Private/Serialization/FindReferencersArchive.cpp

206 lines
7.4 KiB
C++
Raw Permalink Normal View History

2026-02-13 16:18:33 +08:00
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Serialization/FindReferencersArchive.h"
#include "UObject/UObjectGlobals.h"
#include "UObject/Class.h"
/*----------------------------------------------------------------------------
FFindReferencersArchive.
----------------------------------------------------------------------------*/
/**
* Constructor
*
* @param PotentialReferencer the object to serialize which may contain references to our target objects
* @param InTargetObjects array of objects to search for references to
* @param bFindAlsoWeakReferences should we also look into weak references?
*/
FFindReferencersArchive::FFindReferencersArchive(UObject* InPotentialReferencer, const TArray<UObject*>& InTargetObjects, bool bFindAlsoWeakReferences)
{
// use the optimized RefLink to skip over properties which don't contain object references
ArIsObjectReferenceCollector = true;
// look also for weak references if user asked for it (we won't modify them, but there is no archive option for that)
ArIsModifyingWeakAndStrongReferences = bFindAlsoWeakReferences;
// ALL objects reference their outers...it's just log spam here
ArIgnoreOuterRef = true;
// initialize the map
TargetObjects.Reserve(InTargetObjects.Num());
for (int32 ObjIndex = 0; ObjIndex < InTargetObjects.Num(); ObjIndex++)
{
UObject* TargetObject = InTargetObjects[ObjIndex];
if (TargetObject != nullptr)
{
TargetObjects.AddObject(TargetObject);
}
}
TargetObjects.Freeze();
PotentialReferencer = nullptr;
ResetPotentialReferencer(InPotentialReferencer);
}
void FFindReferencersArchive::ResetPotentialReferencer(UObject* InPotentialReferencer)
{
if (PotentialReferencer)
{
// Reset all reference counts
TargetObjects.ResetRefCounts();
}
PotentialReferencer = InPotentialReferencer;
if (PotentialReferencer)
{
// now start the search
PotentialReferencer->Serialize(*this);
// search for references coming from AddReferencedObjects
class FArchiveProxyCollector: public FReferenceCollector
{
/** Archive we are a proxy for */
FArchive& Archive;
public:
FArchiveProxyCollector(FArchive& InArchive)
: Archive(InArchive)
{
}
virtual void HandleObjectReference(UObject*& Object, const UObject* ReferencingObject, const FProperty* ReferencingProperty) override
{
Archive << Object;
}
virtual void HandleObjectReferences(UObject** InObjects, const int32 ObjectNum, const UObject* InReferencingObject, const FProperty* InReferencingProperty) override
{
for (int32 ObjectIndex = 0; ObjectIndex < ObjectNum; ++ObjectIndex)
{
UObject*& Object = InObjects[ObjectIndex];
Archive << Object;
}
}
virtual bool IsIgnoringArchetypeRef() const override
{
return false;
}
virtual bool IsIgnoringTransient() const override
{
return false;
}
} ArchiveProxyCollector(*this);
PotentialReferencer->GetClass()->CallAddReferencedObjects(PotentialReferencer, ArchiveProxyCollector);
}
}
/**
* Retrieves the number of references from PotentialReferencer to the object specified.
*
* @param TargetObject the object to might be referenced
* @param out_ReferencingProperties
* receives the list of properties which were holding references to TargetObject
*
* @return the number of references to TargetObject which were encountered when PotentialReferencer
* was serialized.
*/
int32 FFindReferencersArchive::GetReferenceCount(UObject* TargetObject, TArray<FProperty*>* out_ReferencingProperties /*=nullptr*/) const
{
int32 Result = 0;
if (TargetObject != nullptr && PotentialReferencer != TargetObject)
{
const int32* pCount = TargetObjects.TryGetRefCountPtr(TargetObject);
if (pCount != nullptr && (*pCount) > 0)
{
Result = *pCount;
if (out_ReferencingProperties != nullptr)
{
TArray<FProperty*> PropertiesReferencingObj;
ReferenceMap.MultiFind(TargetObject, PropertiesReferencingObj);
out_ReferencingProperties->Empty(PropertiesReferencingObj.Num());
for (int32 PropIndex = PropertiesReferencingObj.Num() - 1; PropIndex >= 0; PropIndex--)
{
out_ReferencingProperties->Add(PropertiesReferencingObj[PropIndex]);
}
}
}
}
return Result;
}
/**
* Retrieves the number of references from PotentialReferencer list of TargetObjects
*
* @param out_ReferenceCounts receives the number of references to each of the TargetObjects
*
* @return the number of objects which were referenced by PotentialReferencer.
*/
int32 FFindReferencersArchive::GetReferenceCounts(TMap<class UObject*, int32>& out_ReferenceCounts) const
{
out_ReferenceCounts.Empty();
for (int32 Index = 0; Index < TargetObjects.RefCountNum(); ++Index)
{
if (TargetObjects.GetRefCount(Index) > 0 && TargetObjects.GetObject(Index) != PotentialReferencer)
{
out_ReferenceCounts.Add(TargetObjects.GetObject(Index), TargetObjects.GetRefCount(Index));
}
}
return out_ReferenceCounts.Num();
}
/**
* Retrieves the number of references from PotentialReferencer list of TargetObjects
*
* @param out_ReferenceCounts receives the number of references to each of the TargetObjects
* @param out_ReferencingProperties receives the map of properties holding references to each referenced object.
*
* @return the number of objects which were referenced by PotentialReferencer.
*/
int32 FFindReferencersArchive::GetReferenceCounts(TMap<class UObject*, int32>& out_ReferenceCounts, TMultiMap<class UObject*, class FProperty*>& out_ReferencingProperties) const
{
GetReferenceCounts(out_ReferenceCounts);
if (out_ReferenceCounts.Num() > 0)
{
out_ReferencingProperties.Empty();
for (TMap<UObject*, int32>::TIterator It(out_ReferenceCounts); It; ++It)
{
UObject* Object = It.Key();
TArray<FProperty*> PropertiesReferencingObj;
ReferenceMap.MultiFind(Object, PropertiesReferencingObj);
for (int32 PropIndex = PropertiesReferencingObj.Num() - 1; PropIndex >= 0; PropIndex--)
{
out_ReferencingProperties.Add(Object, PropertiesReferencingObj[PropIndex]);
}
}
}
return out_ReferenceCounts.Num();
}
/**
* Serializer - if Obj is one of the objects we're looking for, increments the reference count for that object
*/
FArchive& FFindReferencersArchive::operator<<(UObject*& Obj)
{
if (Obj != nullptr && Obj != PotentialReferencer)
{
int32* pReferenceCount = TargetObjects.GetRefCountPtr(Obj);
if (pReferenceCount != nullptr)
{
// if this object was serialized via a FProperty, add it to the list
if (GetSerializedProperty() != nullptr)
{
ReferenceMap.AddUnique(Obj, GetSerializedProperty());
}
// now increment the reference count for this target object
(*pReferenceCount)++;
}
}
return *this;
}