/** * Adds the object reference to the asset list if it supports thumbnails. * Recursively searches through its references for more assets * * @param Obj the object to inspect */ FArchive& FFindAssetsArchive::operator<<(UObject*& Obj) { // Don't check null references or objects already visited if ( Obj != NULL && // if we wish to filter out assets referenced through script, we need to ignore // all class objects, not just the UObject::Class reference (!ArIgnoreClassRef || (Cast<UClass>(Obj) == NULL)) ) { bool bUnvisited = Obj->HasAnyMarks(OBJECTMARK_TagExp); // Clear the search flag so we don't revisit objects Obj->UnMark(OBJECTMARK_TagExp); if ( Obj->IsA(UField::StaticClass()) ) { // skip all of the other stuff because the serialization of UFields will quickly overflow // our stack given the number of temporary variables we create in the below code if (bUnvisited) { Obj->Serialize(*this); } } else { bool bRecurse = true; const bool bCDO = Obj->HasAnyFlags(RF_ClassDefaultObject); const bool bIsContent = Obj->IsAsset(); const bool bIncludeAnyway = (Obj->GetOuter() == CurrentObject) && (Cast<UClass>(CurrentObject) == NULL); const bool bShouldReportAsset = !bCDO && (bIsContent || bIncludeAnyway); // remember which object we were serializing UObject* PreviousObject = CurrentObject; if ( bShouldReportAsset ) { CurrentObject = Obj; // Add this object to the list to display AssetList.Add(CurrentObject); if ( CurrentReferenceGraph != NULL ) { UObject* Key = bUseReverseReferenceGraph? CurrentObject: PreviousObject; UObject* Value = bUseReverseReferenceGraph? PreviousObject: CurrentObject; TSet<UObject*>* CurrentObjectAssets = GetAssetList(Key); check(CurrentObjectAssets); // add this object to the list of objects referenced by the object currently being serialized CurrentObjectAssets->Add(Value); if (bUnvisited) { HandleReferencedObject(CurrentObject); } } } else if ( Obj == StartObject ) { if (bUnvisited) { HandleReferencedObject(Obj); } } else if (Obj->GetOuter() && PreviousObject != Obj->GetOuter() && Obj->GetOuter()->HasAnyMarks(OBJECTMARK_TagExp)) { Obj->Mark(OBJECTMARK_TagExp); bRecurse = false; } if ( bRecurse && ( MaxRecursionDepth == 0 || CurrentDepth < MaxRecursionDepth ) ) { CurrentDepth++; // Now recursively search this object for more references if (bUnvisited) { Obj->Serialize(*this); } CurrentDepth--; } // restore the previous object that was being serialized CurrentObject = PreviousObject; } } return *this; }
/** * Manually serializes the class and archetype for the specified object so that assets which are referenced * through the object's class/archetype can be differentiated. */ void FFindAssetsArchive::HandleReferencedObject(UObject* Obj ) { if ( CurrentReferenceGraph != NULL ) { // here we allow recursion if the current depth is less-than-equal (as opposed to less-than) because the archetype and class are treated as transparent objects // serialization of the class and object are controlled by the "show class refs" and "show default refs" buttons if ( MaxRecursionDepth == 0 || CurrentDepth < MaxRecursionDepth ) { // now change the current reference list to the one for this object if ( bIncludeDefaultRefs == true ) { UObject* ObjectArc = Obj->GetArchetype(); UObject* Key = bUseReverseReferenceGraph? ObjectArc: Obj; UObject* Value = bUseReverseReferenceGraph? Obj: ObjectArc; TSet<UObject*>* ReferencedAssets = GetAssetList(Key); // @see the comment for the bIncludeScriptRefs block ReferencedAssets->Add(Value); UObject* PreviousObject = CurrentObject; CurrentObject = ObjectArc; if ( ObjectArc->HasAnyMarks(OBJECTMARK_TagExp) ) { // temporarily disable serialization of the class, as we need to specially handle that as well bool bSkipClassSerialization = ArIgnoreClassRef; ArIgnoreClassRef = true; ObjectArc->UnMark(OBJECTMARK_TagExp); ObjectArc->Serialize(*this); ArIgnoreClassRef = bSkipClassSerialization; } CurrentObject = PreviousObject; } if ( bIncludeScriptRefs == true ) { UClass* ObjectClass = Obj->GetClass(); UObject* Key = bUseReverseReferenceGraph? ObjectClass: Obj; UObject* Value = bUseReverseReferenceGraph? Obj: ObjectClass; TSet<UObject*>* ReferencedAssets = GetAssetList(Key); // we want to see assets referenced by this object's class, but classes don't have associated thumbnail rendering info // so we'll need to serialize the class manually in order to get the object references encountered through the class to fal // under the appropriate tree item // serializing the class will result in serializing the class default object; but we need to do this manually (for the same reason // that we do it for the class), so temporarily prevent the CDO from being serialized by this archive ReferencedAssets->Add(Value); UObject* PreviousObject = CurrentObject; CurrentObject = ObjectClass; if ( ObjectClass->HasAnyMarks(OBJECTMARK_TagExp) ) { ObjectClass->UnMark(OBJECTMARK_TagExp); ObjectClass->Serialize(*this); } CurrentObject = PreviousObject; } } } }
/** * Adds the object reference to the asset list if it supports thumbnails * Recursively searches through its references for more assets */ FArchive& operator<<(UObject*& Obj) { // Don't check null references or objects already visited if (Obj != NULL && Obj->HasAnyMarks(OBJECTMARK_TagExp) && // Ff we wish to filter out assets referenced through script, we need to ignore all class objects, not just the UObject::Class reference (!ArIgnoreClassRef || (Cast<UClass>(Obj) == NULL))) { // Clear the search flag so we don't revisit objects Obj->UnMark(OBJECTMARK_TagExp); if (Obj->IsA(UField::StaticClass())) { // Skip all of the other stuff because the serialization of UFields will quickly overflow our stack given the number of temporary variables we create in the below code Obj->Serialize(*this); } else { // Only report this object reference if it supports thumbnail display this eliminates all of the random objects like functions, properties, etc. const bool bCDO = Obj->HasAnyFlags(RF_ClassDefaultObject); const bool bIsContent = GUnrealEd->GetThumbnailManager()->GetRenderingInfo(Obj) != NULL; const bool bIncludeAnyway = (Obj->GetOuter() == CurrentObject) && (Cast<UClass>(CurrentObject) == NULL); const bool bShouldReportAsset = !bCDO && (bIsContent || bIncludeAnyway); // Remember which object we were serializing UObject* PreviousObject = CurrentObject; if (bShouldReportAsset) { CurrentObject = Obj; // Add this object to the list to display AssetList.Add(CurrentObject); if (CurrentReferenceGraph != NULL) { TArray<UObject*>* CurrentObjectAssets = GetAssetList(PreviousObject); check(CurrentObjectAssets); // Add this object to the list of objects referenced by the object currently being serialized CurrentObjectAssets->Add(CurrentObject); HandleReferencedObject(CurrentObject); } } else if (Obj == StartObject) { HandleReferencedObject(Obj); } if (MaxRecursionDepth == 0 || CurrentDepth < MaxRecursionDepth) { CurrentDepth++; // Now recursively search this object for more references Obj->Serialize(*this); CurrentDepth--; } // Restore the previous object that was being serialized CurrentObject = PreviousObject; } } return *this; }