/**
 * 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;
			}
		}
	}
}
Esempio n. 3
0
		/**
		 * 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;
		}