void UExporter::ExportComponentDefinitions(const FExportObjectInnerContext* Context, const TArray<UObject*>& Components, FOutputDevice& Ar, uint32 PortFlags)
{
	PortFlags |= PPF_ExportsNotFullyQualified;

	if (!(PortFlags & PPF_SeparateDefine))
	{
		// export forward declarations
		// technically we only need to do this if there are circular references but it doesn't seem worth it
		// to complicate this code for a minor speed improvement in the text import path
		for (int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++)
		{
			UObject* Component = Components[ComponentIndex];
			FName ComponentName = Component->GetFName();
			if (!Component->HasAnyMarks(OBJECTMARK_TagImp) && !Component->HasAnyFlags(RF_TextExportTransient))
			{
				if (Component->HasAnyFlags(RF_ClassDefaultObject) || Component->GetArchetype()->HasAllFlags(RF_ClassDefaultObject))
				{
					Ar.Logf(TEXT("%sBegin Object Class=%s Name=%s ObjName=%s%s"), FCString::Spc(TextIndent), *Component->GetClass()->GetName(), *ComponentName.ToString(), *Component->GetName(), LINE_TERMINATOR);
				}
				else
				{
					Ar.Logf(TEXT("%sBegin Object Class=%s Name=%s ObjName=%s Archetype=%s'%s'%s"),FCString::Spc(TextIndent),*Component->GetClass()->GetName(), *ComponentName.ToString(), *Component->GetName(), *Component->GetArchetype()->GetClass()->GetName(), *Component->GetArchetype()->GetPathName(), LINE_TERMINATOR);
				}
				if (PortFlags & PPF_SeparateDeclare)
				{
					ExportObjectInner(Context, Component, Ar, PortFlags, false);
				}
				Ar.Logf(TEXT("%sEnd Object%s"), FCString::Spc(TextIndent), LINE_TERMINATOR);
			}
		}
	}

	if (!(PortFlags & PPF_SeparateDeclare))
	{
		// export property definitions
		for (int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++)
		{
			UObject* Component = Components[ComponentIndex];
			FName ComponentName = Component->GetFName();
			if (!Component->HasAnyMarks(OBJECTMARK_TagImp) && !Component->HasAnyFlags(RF_TextExportTransient))
			{
				Ar.Logf(TEXT("%sBegin Object Name=%s%s"), FCString::Spc(TextIndent), *ComponentName.ToString(), LINE_TERMINATOR);

				uint32 OldPortFlags = PortFlags;

				if (!(Component->HasAnyFlags(RF_ClassDefaultObject) || Component->GetArchetype()->HasAllFlags(RF_ClassDefaultObject)))
				{
					// we created this thing with an archetype (see archetype=, above), so we don't want to list the archetype because it is unqualified and will clash, resetting the archetype pointer to something silly
					PortFlags |= PPF_NoInternalArcheType;
				}
				ExportObjectInner(Context, Component, Ar, PortFlags, false);

				PortFlags = OldPortFlags;
				Ar.Logf(TEXT("%sEnd Object%s"), FCString::Spc(TextIndent), LINE_TERMINATOR);

				Component->Mark(OBJECTMARK_TagImp);
			}
		}
	}
}
Example #2
0
bool FFrontendFilter_InUseByLoadedLevels::PassesFilter(FAssetFilterType InItem) const
{
	bool bObjectInUse = false;
	
	if ( InItem.IsAssetLoaded() )
	{
		UObject* Asset = InItem.GetAsset();

		const bool bUnreferenced = !Asset->HasAnyMarks( OBJECTMARK_TagExp );
		const bool bIndirectlyReferencedObject = Asset->HasAnyMarks( OBJECTMARK_TagImp );
		const bool bRejectObject =
			Asset->GetOuter() == NULL || // Skip objects with null outers
			Asset->HasAnyFlags( RF_Transient ) || // Skip transient objects (these shouldn't show up in the CB anyway)
			Asset->IsPendingKill() || // Objects that will be garbage collected 
			bUnreferenced || // Unreferenced objects 
			bIndirectlyReferencedObject; // Indirectly referenced objects

		if( !bRejectObject && Asset->HasAnyFlags( RF_Public ) )
		{
			// The object is in use 
			bObjectInUse = true;
		}
	}

	return bObjectInUse;
}
Example #3
0
FArchiveGenerateReferenceGraph::FArchiveGenerateReferenceGraph( FReferenceGraph& OutGraph ) 
	: CurrentObject(NULL),
	  ObjectGraph(OutGraph)
{

	ArIsObjectReferenceCollector = true;
	ArIgnoreOuterRef = true;

	// Iterate over each object..
	for( FObjectIterator It; It; ++It )
	{
		UObject* Object	= *It;

		// Skip transient and those about to be deleted
		if( !Object->HasAnyFlags( RF_Transient | RF_PendingKill ) )
		{
			// only serialize non actors objects which have not been visited.
			// actors are skipped because we have don't need them to show the reference tree
			// @todo, may need to serialize them later for full reference graph.
			if( !VisitedObjects.Find( Object ) && !Object->IsA( AActor::StaticClass() ) )
			{
				// Set the current object to the one we are about to serialize
				CurrentObject = Object;
				// This object has been visited.  Any serializations after this should skip this object
				VisitedObjects.Add( Object );
				Object->Serialize( *this );
			}
		}
	}
}
void FComponentEditorUtils::GetArchetypeInstances( UObject* Object, TArray<UObject*>& ArchetypeInstances )
{
	if (Object->HasAnyFlags(RF_ClassDefaultObject))
	{
		// Determine if the object is owned by a Blueprint
		UBlueprint* Blueprint = Cast<UBlueprint>(Object->GetOuter());
		if(Blueprint != NULL)
		{
			if(Blueprint->GeneratedClass != NULL && Blueprint->GeneratedClass->ClassDefaultObject != NULL)
			{
				// Collect all instances of the Blueprint
				Blueprint->GeneratedClass->ClassDefaultObject->GetArchetypeInstances(ArchetypeInstances);
			}
		}
		else
		{
			// Object is a default object, collect all instances.
			Object->GetArchetypeInstances(ArchetypeInstances);
		}
	}
	else if (Object->HasAnyFlags(RF_DefaultSubObject))
	{
		UObject* DefaultObject = Object->GetOuter();
		if(DefaultObject != NULL && DefaultObject->HasAnyFlags(RF_ClassDefaultObject))
		{
			// Object is a default subobject, collect all instances of the default object that owns it.
			DefaultObject->GetArchetypeInstances(ArchetypeInstances);
		}
	}
}
UObject* FBlueprintNativeCodeGenModule::FindReplacedNameAndOuter(UObject* Object, FName& OutName) const
{
	OutName = NAME_None;
	UObject* Outer = nullptr;

	UActorComponent* ActorComponent = Cast<UActorComponent>(Object);
	if (ActorComponent)
	{
		//if is child of a BPGC and not child of a CDO
		UBlueprintGeneratedClass* BPGC = nullptr;
		for (UObject* OuterObject = ActorComponent->GetOuter(); OuterObject && !BPGC; OuterObject = OuterObject->GetOuter())
		{
			if (OuterObject->HasAnyFlags(RF_ClassDefaultObject))
			{
				return Outer;
			}
			BPGC = Cast<UBlueprintGeneratedClass>(OuterObject);
		}

		for (UBlueprintGeneratedClass* SuperBPGC = BPGC; SuperBPGC && (OutName == NAME_None); SuperBPGC = Cast<UBlueprintGeneratedClass>(SuperBPGC->GetSuperClass()))
		{
			if (SuperBPGC->InheritableComponentHandler)
			{
				FComponentKey FoundKey = SuperBPGC->InheritableComponentHandler->FindKey(ActorComponent);
				if (FoundKey.IsValid())
				{
					OutName = FoundKey.IsSCSKey() ? FoundKey.GetSCSVariableName() : ActorComponent->GetFName();
					Outer = BPGC->GetDefaultObject(false);
					break;
				}
			}
			if (SuperBPGC->SimpleConstructionScript)
			{
				for (auto Node : SuperBPGC->SimpleConstructionScript->GetAllNodes())
				{
					if (Node->ComponentTemplate == ActorComponent)
					{
						OutName = Node->VariableName;
						if (OutName != NAME_None)
						{
							Outer = BPGC->GetDefaultObject(false);
							break;
						}
					}
				}
			}
		}
	}

	if (Outer && (EReplacementResult::ReplaceCompletely == IsTargetedForReplacement(Object->GetClass())))
	{
		UE_LOG(LogBlueprintCodeGen, Log, TEXT("Object '%s' has replaced name '%s' and outer: '%s'"), *GetPathNameSafe(Object), *OutName.ToString(), *GetPathNameSafe(Outer));
		return Outer;
	}

	return nullptr;
}
Example #6
0
UObject* UBlueprint::GetObjectBeingDebugged()
{
	UObject* DebugObj = CurrentObjectBeingDebugged.Get();
	if(DebugObj)
	{
		//Check whether the object has been deleted.
		if(DebugObj->HasAnyFlags(RF_PendingKill))
		{
			SetObjectBeingDebugged(NULL);
			DebugObj = NULL;
		}
	}
	return DebugObj;
}
// This is from FArchiveTraceRoute -This only creates object graph of all objects 
// This can be used by other classes such as FTraceReferences - trace references of one object
FArchiveObjectGraph::FArchiveObjectGraph(bool IncludeTransients, EObjectFlags	KeepFlags)
:	CurrentReferencer(NULL),
	bIncludeTransients(IncludeTransients), 
	RequiredFlags(KeepFlags)
{
	ArIsObjectReferenceCollector = true;

	// ALL objects reference their outers...it's just log spam here
	//ArIgnoreOuterRef = true;

	TArray<UObject*> RootObjects;

	// allocate enough memory for all objects
	ObjectGraph.Empty(GetUObjectArray().GetObjectArrayNum());
	RootObjects.Empty(GetUObjectArray().GetObjectArrayNum());

	// search for objects that have the right flags and add them to the list of objects that we're going to start with
	// all other objects need to be tagged so that we can tell whether they've been serialized or not.
	for( FObjectIterator It; It; ++It )
	{
		UObject* CurrentObject = *It;
		if ( CurrentObject->HasAnyFlags(RequiredFlags) )
		{
			// make sure it isn't tagged
			// ASKRON: WHY do we need this?
			CurrentObject->UnMark(OBJECTMARK_TagExp);
			RootObjects.Add(CurrentObject);
			ObjectGraph.Add(CurrentObject, new FObjectGraphNode(CurrentObject));
		}
		else
		{
			// ASKRON: WHY do we need this?
			CurrentObject->Mark(OBJECTMARK_TagExp);
		}
	}

	// Populate the ObjectGraph - this serializes our root set to map out the relationships between all rooted objects
	GenerateObjectGraph(RootObjects);

	// we won't be adding any additional objects for the arrays and graphs, so free up any memory not being used.
	RootObjects.Shrink();
	ObjectGraph.Shrink();

	// we're done with serialization; clear the tags so that we don't interfere with anything else
	for( FObjectIterator It; It; ++It )
	{
		It->UnMark(OBJECTMARK_TagExp);
	}
}
void SPropertyEditorEditInline::OnClassPicked(UClass* InClass)
{
	TArray<FObjectBaseAddress> ObjectsToModify;
	TArray<FString> NewValues;

	const TSharedRef< FPropertyNode > PropertyNode = PropertyEditor->GetPropertyNode();
	FObjectPropertyNode* ObjectNode = PropertyNode->FindObjectItemParent();

	if( ObjectNode )
	{
		for ( TPropObjectIterator Itor( ObjectNode->ObjectIterator() ) ; Itor ; ++Itor )
		{
			FString NewValue;
			if (InClass)
			{
				UObject*		Object = Itor->Get();
				UObject*		UseOuter = (InClass->IsChildOf(UClass::StaticClass()) ? Cast<UClass>(Object)->GetDefaultObject() : Object);
				EObjectFlags	MaskedOuterFlags = UseOuter ? UseOuter->GetMaskedFlags(RF_PropagateToSubObjects) : RF_NoFlags;
				if (UseOuter && UseOuter->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
				{
					MaskedOuterFlags |= RF_ArchetypeObject;
				}
				UObject*		NewObject = StaticConstructObject(InClass, UseOuter, NAME_None, MaskedOuterFlags, NULL);

				NewValue = NewObject->GetPathName();
			}
			else
			{
				NewValue = FName(NAME_None).ToString();
			}
			NewValues.Add(NewValue);
		}

		const TSharedRef< IPropertyHandle > PropertyHandle = PropertyEditor->GetPropertyHandle();
		PropertyHandle->SetPerObjectValues( NewValues );

		// Force a rebuild of the children when this node changes
		PropertyNode->RequestRebuildChildren();

		ComboButton->SetIsOpen(false);
	}
}
Example #9
0
void GetObjectsWithAnyMarks(TArray<UObject *>& Results, EObjectMark Marks)
{
	// We don't want to return any objects that are currently being background loaded unless we're using the object iterator during async loading.
	EObjectFlags ExclusionFlags = RF_Unreachable;
	if (!IsInAsyncLoadingThread())
	{
		ExclusionFlags = EObjectFlags(ExclusionFlags | RF_AsyncLoading);
	}
	const TMap<const UObjectBase *, FObjectMark>& Map = MarkAnnotation.GetAnnotationMap();
	Results.Empty(Map.Num());
	for (TMap<const UObjectBase *, FObjectMark>::TConstIterator It(Map); It; ++It)
	{
		if (It.Value().Marks & Marks)
		{
			UObject* Item = (UObject*)It.Key();
			if (!Item->HasAnyFlags(ExclusionFlags))
			{
				Results.Add(Item);
			}
		}
	}
}
void FMovieSceneSequenceInstance::PreUpdate(class IMovieScenePlayer& Player)
{
	// Remove any stale runtime objects
	TMap<FGuid, FMovieSceneObjectBindingInstance>::TIterator ObjectIt = ObjectBindingInstances.CreateIterator();
	for(; ObjectIt; ++ObjectIt )
	{
		FMovieSceneObjectBindingInstance& ObjectBindingInstance = ObjectIt.Value();
		for (int32 ObjectIndex = 0; ObjectIndex < ObjectBindingInstance.RuntimeObjects.Num(); )
		{
			UObject* RuntimeObject = ObjectBindingInstance.RuntimeObjects[ObjectIndex].Get();
			if (RuntimeObject == nullptr || RuntimeObject->HasAnyFlags(RF_BeginDestroyed|RF_FinishDestroyed) || RuntimeObject->IsPendingKill())
			{
				ObjectBindingInstance.RuntimeObjects.RemoveAt(ObjectIndex);
			}
			else
			{
				++ObjectIndex;
			}
		}
	}

	Player.GetSpawnRegister().PreUpdateSequenceInstance(*this, Player);
}
void UExporter::ExportObjectInner(const FExportObjectInnerContext* Context, UObject* Object, FOutputDevice& Ar, uint32 PortFlags, bool bSkipComponents)
{
	// indent all the text in here
	TextIndent += 3;

	FExportObjectInnerContext::InnerList ObjectInners;
	if ( Context )
	{
		const FExportObjectInnerContext::InnerList* Inners = Context->ObjectToInnerMap.Find( Object );
		if ( Inners )
		{
			ObjectInners = *Inners;
		}
	}
	else
	{
		for (TObjectIterator<UObject> It; It; ++It)
		{
			if ( It->GetOuter() == Object )
			{
				ObjectInners.Add( *It );
			}
		}
	}


	TArray<UObject*> Components;
	if (!bSkipComponents)
	{
		// first export the components
		Object->CollectDefaultSubobjects(Components, false);
	}

	if (!(PortFlags & PPF_SeparateDefine))
	{
		for ( int32 ObjIndex = 0 ; ObjIndex < ObjectInners.Num() ; ++ObjIndex )
		{
			// NOTE: We ignore inner objects that have been tagged for death
			UObject* Obj = ObjectInners[ObjIndex];
			if ( !Obj->IsPendingKill() && !Obj->IsDefaultSubobject() && !Obj->HasAnyFlags(RF_TextExportTransient) && FCString::Stricmp(*Obj->GetClass()->GetName(), TEXT("Model")) != 0)
			{
				// export the object
				UExporter::ExportToOutputDevice( Context, Obj, NULL, Ar, (PortFlags & PPF_Copy) ? TEXT("Copy") : TEXT("T3D"), TextIndent, PortFlags | PPF_SeparateDeclare, false, ExportRootScope );
			}
		}

		if (!bSkipComponents)
		{
			ExportComponentDefinitions(Context, Components, Ar, PortFlags | PPF_SeparateDeclare);
		}
	}

	if (!(PortFlags & PPF_SeparateDeclare))
	{
		for ( int32 ObjIndex = 0 ; ObjIndex < ObjectInners.Num() ; ++ObjIndex )
		{
			// NOTE: We ignore inner objects that have been tagged for death
			UObject* Obj = ObjectInners[ObjIndex];
			if ( !Obj->IsPendingKill() && !Obj->IsDefaultSubobject() && !Obj->HasAnyFlags(RF_TextExportTransient) && FCString::Stricmp(*Obj->GetClass()->GetName(), TEXT("Model")) != 0)
			{
				// export the object
				UExporter::ExportToOutputDevice( Context, Obj, NULL, Ar, (PortFlags & PPF_Copy) ? TEXT("Copy") : TEXT("T3D"), TextIndent, PortFlags | PPF_SeparateDefine, false, ExportRootScope );

				// don't reexport below in ExportProperties
				Obj->Mark(OBJECTMARK_TagImp);
			}
		}

		if (!bSkipComponents)
		{
			ExportComponentDefinitions(Context, Components, Ar, PortFlags | PPF_SeparateDefine);
		}

		// export the object's properties
		// Note: we use archetype as the object to diff properties against before they exported. When object is created, they should create from archetype
		// and using this system, it should recover all properties it needs to copy
		uint8 *CompareObject;
		if (Object->HasAnyFlags(RF_ClassDefaultObject))
		{
			CompareObject = (uint8*)Object;
		}
		else
		{
			CompareObject = (uint8*)Object->GetArchetype();
		}
		ExportProperties( Context, Ar, Object->GetClass(), (uint8*)Object, TextIndent, Object->GetClass(), CompareObject, Object, PortFlags, ExportRootScope );

		if (!bSkipComponents)
		{
			// Export anything extra for the components. Used for instanced foliage.
			// This is done after the actor properties so these are set when regenerating the extra data objects.
			ExportComponentExtra( Context, Components, Ar, PortFlags );
		}
	}

	// remove indent
	TextIndent -= 3;
}
void SBlueprintEditorSelectedDebugObjectWidget::GenerateDebugObjectNames(bool bRestoreSelection)
{
	TSharedPtr<FString> OldSelection;

	// Store off the old selection
	if (bRestoreSelection && DebugObjectsComboBox.IsValid())
	{
		OldSelection = DebugObjectsComboBox->GetSelectedItem();
	}

	// Empty the lists of actors and regenerate them
	DebugObjects.Empty();
	DebugObjectNames.Empty();
	DebugObjects.Add(NULL);
	DebugObjectNames.Add(MakeShareable(new FString(GetNoDebugString())));

	// Grab custom objects that should always be visible, regardless of the world
	TArray<FCustomDebugObject> CustomDebugObjects;
	BlueprintEditor.Pin()->GetCustomDebugObjects(/*inout*/ CustomDebugObjects);

	for (const FCustomDebugObject& Entry : CustomDebugObjects)
	{
		if (Entry.NameOverride.IsEmpty())
		{
			AddDebugObject(Entry.Object);
		}
		else
		{
			AddDebugObjectWithName(Entry.Object, Entry.NameOverride);
		}
	}

	// Check for a specific debug world. If DebugWorld=NULL we take that as "any PIE world"
	UWorld* DebugWorld = NULL;
	if (DebugWorldsComboBox.IsValid())
	{
		TSharedPtr<FString> CurrentWorldSelection = DebugWorldsComboBox->GetSelectedItem();
		int32 SelectedIndex = DebugWorldNames.Find(CurrentWorldSelection);
		if (SelectedIndex > 0 && DebugWorldNames.IsValidIndex(SelectedIndex))
		{
			DebugWorld = DebugWorlds[SelectedIndex].Get();
		}
	}

	UWorld* PreviewWorld = NULL;
	TSharedPtr<SSCSEditorViewport> PreviewViewportPtr = BlueprintEditor.Pin()->GetSCSViewport();
	if (PreviewViewportPtr.IsValid())
	{
		PreviewWorld = PreviewViewportPtr->GetPreviewScene().GetWorld();
	}

	for (TObjectIterator<UObject> It; It; ++It)
	{
		UObject* TestObject = *It;

		// Skip Blueprint preview objects (don't allow them to be selected for debugging)
		if (PreviewWorld != NULL && TestObject->IsIn(PreviewWorld))
		{
			continue;
		}

		const bool bPassesFlags = !TestObject->HasAnyFlags(RF_PendingKill | RF_ClassDefaultObject);
		const bool bGeneratedByBlueprint = TestObject->GetClass()->ClassGeneratedBy == GetBlueprintObj();
		if (bPassesFlags && bGeneratedByBlueprint)
		{

			UObject *ObjOuter = TestObject;
			UWorld *ObjWorld = NULL;
			while (ObjWorld == NULL && ObjOuter != NULL)
			{
				ObjOuter = ObjOuter->GetOuter();
				ObjWorld = Cast<UWorld>(ObjOuter);
			}

			// Object not in any world
			if (!ObjWorld)
			{
				continue;
			}

			// Make check on owning level (not streaming level)
			if (ObjWorld->PersistentLevel && ObjWorld->PersistentLevel->OwningWorld)
			{
				ObjWorld = ObjWorld->PersistentLevel->OwningWorld;
			}

			// We have a specific debug world and the object isnt in it
			if (DebugWorld && ObjWorld != DebugWorld)
			{
				continue;
			}

			// We don't have a specific debug world, but the object isnt in a PIE world
			if (ObjWorld->WorldType != EWorldType::PIE)
			{
				continue;
			}

			AddDebugObject(TestObject);
		}
	}

	// Attempt to restore the old selection
	if (bRestoreSelection && DebugObjectsComboBox.IsValid())
	{
		bool bMatchFound = false;
		for (int32 ObjectIndex = 0; ObjectIndex < DebugObjectNames.Num(); ++ObjectIndex)
		{
			if (*DebugObjectNames[ObjectIndex] == *OldSelection)
			{
				DebugObjectsComboBox->SetSelectedItem(DebugObjectNames[ObjectIndex]);
				bMatchFound = true;
				break;
			}
		}

		// No match found, use the default option
		if (!bMatchFound)
		{
			DebugObjectsComboBox->SetSelectedItem(DebugObjectNames[0]);
		}
	}

	// Finally ensure we have a valid selection
	if (DebugObjectsComboBox.IsValid())
	{
		TSharedPtr<FString> CurrentSelection = DebugObjectsComboBox->GetSelectedItem();
		if (DebugObjectNames.Find(CurrentSelection) == INDEX_NONE)
		{
			if (DebugObjectNames.Num() > 0)
			{
				DebugObjectsComboBox->SetSelectedItem(DebugObjectNames[0]);
			}
			else
			{
				DebugObjectsComboBox->ClearSelection();
			}
		}

		DebugObjectsComboBox->RefreshOptions();
	}
}
	virtual void HandleObjectReference(UObject*& InObject, const UObject* InReferencingObject, const UProperty* InReferencingProperty) override
	{
		UObject* Object = InObject;
		if (!Object || Object->IsA<UBlueprint>())
		{
			return;
		}

		UClass* ActualClass = Cast<UClass>(Dependencies.GetActualStruct());
		UStruct* CurrentlyConvertedStruct = ActualClass ? Dependencies.FindOriginalClass(ActualClass) : Dependencies.GetActualStruct();
		ensure(CurrentlyConvertedStruct);
		if (Object == CurrentlyConvertedStruct)
		{
			return;
		}

		if (Object->HasAnyFlags(RF_ClassDefaultObject))
		{
			// Static functions from libraries are called on CDO. (The functions is stored as a name not an object).
			UClass* OwnerClass = Object->GetClass();
			if (OwnerClass && (OwnerClass != CurrentlyConvertedStruct))
			{
				UBlueprintGeneratedClass* OwnerAsBPGC = Cast<UBlueprintGeneratedClass>(OwnerClass);
				if (OwnerAsBPGC && !Dependencies.ConvertedClasses.Contains(OwnerAsBPGC) && Dependencies.WillClassBeConverted(OwnerAsBPGC))
				{
					Dependencies.ConvertedClasses.Add(OwnerAsBPGC);
				}
			}
		}

		const bool bUseZConstructorInGeneratedCode = false;
		//TODO: What About Delegates?
		auto ObjAsBPGC = Cast<UBlueprintGeneratedClass>(Object);
		const bool bWillBeConvetedAsBPGC = ObjAsBPGC && Dependencies.WillClassBeConverted(ObjAsBPGC);
		if (bWillBeConvetedAsBPGC)
		{
			if (ObjAsBPGC != CurrentlyConvertedStruct)
			{
				Dependencies.ConvertedClasses.Add(ObjAsBPGC);
				if(!bUseZConstructorInGeneratedCode)
				{
					IncludeTheHeaderInBody(ObjAsBPGC);
				}
			}
		}
		else if (UUserDefinedStruct* UDS = Cast<UUserDefinedStruct>(Object))
		{
			if (!UDS->HasAnyFlags(RF_ClassDefaultObject))
			{
				Dependencies.ConvertedStructs.Add(UDS);
				if(!bUseZConstructorInGeneratedCode)
				{
					IncludeTheHeaderInBody(UDS);
				}
			}
		}
		else if (UUserDefinedEnum* UDE = Cast<UUserDefinedEnum>(Object))
		{
			if (!UDE->HasAnyFlags(RF_ClassDefaultObject))
			{
				Dependencies.ConvertedEnum.Add(UDE);
			}
		}
		else if ((Object->IsAsset() || ObjAsBPGC) && !Object->IsIn(CurrentlyConvertedStruct))
		{
			// include all not converted super classes
			for (auto SuperBPGC = ObjAsBPGC ? Cast<UBlueprintGeneratedClass>(ObjAsBPGC->GetSuperClass()) : nullptr;
				SuperBPGC && !Dependencies.WillClassBeConverted(SuperBPGC);
				SuperBPGC = Cast<UBlueprintGeneratedClass>(SuperBPGC->GetSuperClass()))
			{
				Dependencies.Assets.AddUnique(SuperBPGC);
			}

			Dependencies.Assets.AddUnique(Object);
			return;
		}
		else if (auto ObjAsClass = Cast<UClass>(Object))
		{
			if (ObjAsClass->HasAnyClassFlags(CLASS_Native))
			{
				return;
			}
		}
		else if (Object->IsA<UScriptStruct>())
		{
			return;
		}

		FindReferencesForNewObject(Object);
	}
void FEditorUtilityInstanceDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayoutBuilder)
{
    SelectedObjectsList = DetailLayoutBuilder.GetDetailsView().GetSelectedObjects();

    // Hide some useless categories
    //@TODO: How to hide Actors, Layers, etc...?

    // Build a list of unique selected blutilities
    TArray<UClass*> UniqueBlutilityClasses;
    bool bFoundAnyCDOs = false;

    for (auto SelectedObjectIt = SelectedObjectsList.CreateConstIterator(); SelectedObjectIt; ++SelectedObjectIt)
    {
        UObject* Object = (*SelectedObjectIt).Get();

        if (!Object->HasAnyFlags(RF_ClassDefaultObject))
        {
            UClass* ObjectClass = Object->GetClass();

            if (UEditorUtilityBlueprint* Blutility = Cast<UEditorUtilityBlueprint>(ObjectClass->ClassGeneratedBy))
            {
                UniqueBlutilityClasses.Add(ObjectClass);
            }
        }
        else
        {
            bFoundAnyCDOs = true;
        }
    }

    // Run thru each one
    UniqueBlutilityClasses.Sort(FCompareClassNames());
    for (auto ClassIt = UniqueBlutilityClasses.CreateIterator(); ClassIt; ++ClassIt)
    {
        UClass* Class = *ClassIt;

        FString CategoryName = FString::Printf(TEXT("%sActions"), *Class->ClassGeneratedBy->GetName());
        IDetailCategoryBuilder& ActionsCategory = DetailLayoutBuilder.EditCategory(*CategoryName);

        const APlacedEditorUtilityBase* PlacedActorCDO = Cast<const APlacedEditorUtilityBase>(Class->GetDefaultObject());
        if (PlacedActorCDO)
        {
            ActionsCategory.AddCustomRow( PlacedActorCDO->HelpText )
            [
                SNew(STextBlock)
                .Text(PlacedActorCDO->HelpText)
            ];
        }

        const UGlobalEditorUtilityBase* GlobalBlutilityCDO = Cast<const UGlobalEditorUtilityBase>(Class->GetDefaultObject());
        if (GlobalBlutilityCDO)
        {
            ActionsCategory.AddCustomRow( GlobalBlutilityCDO->HelpText )
            [
                SNew(STextBlock)
                .Text(GlobalBlutilityCDO->HelpText)
            ];
        }

        TSharedRef<SWrapBox> WrapBox = SNew(SWrapBox).UseAllottedWidth(true);
        int32 NumButtons = 0;

        for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::IncludeSuper); FuncIt; ++FuncIt)
        {
            UFunction* Function = *FuncIt;

            const bool bCanExecute = (Function->NumParms == 0) && Function->HasAllFunctionFlags(FUNC_Exec);

            if (bCanExecute)
            {
                ++NumButtons;

                const FString ButtonCaption = FName::NameToDisplayString(*Function->GetName(), false);

                //@TODO: Expose the code in UK2Node_CallFunction::GetUserFacingFunctionName / etc...
                FString Tooltip = Function->GetToolTipText().ToString();
                if (Tooltip.IsEmpty())
                {
                    Tooltip = Function->GetName();
                }

                TWeakObjectPtr<UFunction> WeakFunctionPtr(Function);

                WrapBox->AddSlot()
                [
                    SNew(SButton)
                    .Text(ButtonCaption)
                    .OnClicked(	FOnClicked::CreateSP(this, &FEditorUtilityInstanceDetails::OnExecuteAction, WeakFunctionPtr) )
                    .ToolTipText(Tooltip)
                ];

            }
        }

        if (NumButtons > 0)
        {
            ActionsCategory.AddCustomRow(TEXT(""))
            [
                WrapBox
            ];
        }
    }

    // Hide the hint property
    if (!bFoundAnyCDOs)
    {
        DetailLayoutBuilder.HideProperty(TEXT("HelpText"));
    }
}
UObject* UObjectPropertyBase::FindImportedObject( const UProperty* Property, UObject* OwnerObject, UClass* ObjectClass, UClass* RequiredMetaClass, const TCHAR* Text, uint32 PortFlags/*=0*/ )
{
	UObject*	Result = NULL;
	check( ObjectClass->IsChildOf(RequiredMetaClass) );

	bool AttemptNonQualifiedSearch = (PortFlags & PPF_AttemptNonQualifiedSearch) != 0; 

	// if we are importing default properties, first look for a matching subobject by
	// looking through the archetype chain at each outer and stop once the outer chain reaches the owning class's default object
	if (PortFlags & PPF_ParsingDefaultProperties)
	{
		for (UObject* SearchStart = OwnerObject; Result == NULL && SearchStart != NULL; SearchStart = SearchStart->GetOuter())
		{
			UObject* ScopedSearchRoot = SearchStart;
			while (Result == NULL && ScopedSearchRoot != NULL)
			{
				Result = StaticFindObject(ObjectClass, ScopedSearchRoot, Text);
				// don't think it's possible to get a non-subobject here, but it doesn't hurt to check
				if (Result != NULL && !Result->IsTemplate(RF_ClassDefaultObject))
				{
					Result = NULL;
				}

				ScopedSearchRoot = ScopedSearchRoot->GetArchetype();
			}
			if (SearchStart->HasAnyFlags(RF_ClassDefaultObject))
			{
				break;
			}
		}
	}
	
	// if we have a parent, look in the parent, then it's outer, then it's outer, ... 
	// this is because exported object properties that point to objects in the level aren't
	// fully qualified, and this will step up the nested object chain to solve any name
	// collisions within a nested object tree
	UObject* ScopedSearchRoot = OwnerObject;
	while (Result == NULL && ScopedSearchRoot != NULL)
	{
		Result = StaticFindObject(ObjectClass, ScopedSearchRoot, Text);
		// disallow class default subobjects here while importing defaults
		// this prevents the use of a subobject name that doesn't exist in the scope of the default object being imported
		// from grabbing some other subobject with the same name and class in some other arbitrary default object
		if (Result != NULL && (PortFlags & PPF_ParsingDefaultProperties) && Result->IsTemplate(RF_ClassDefaultObject))
		{
			Result = NULL;
		}

		ScopedSearchRoot = ScopedSearchRoot->GetOuter();
	}

	if (Result == NULL)
	{
		// attempt to find a fully qualified object
		Result = StaticFindObject(ObjectClass, NULL, Text);

		if (Result == NULL)
		{
			// match any object of the correct class whose path contains the specified path
			Result = StaticFindObject(ObjectClass, ANY_PACKAGE, Text);
			// disallow class default subobjects here while importing defaults
			if (Result != NULL && (PortFlags & PPF_ParsingDefaultProperties) && Result->IsTemplate(RF_ClassDefaultObject))
			{
				Result = NULL;
			}
		}
	}

	// if we haven;t found it yet, then try to find it without a qualified name
	if (!Result)
	{
		const TCHAR* Dot = FCString::Strrchr(Text, '.');
		if (Dot && AttemptNonQualifiedSearch)
		{
			// search with just the object name
			Result = FindImportedObject(Property, OwnerObject, ObjectClass, RequiredMetaClass, Dot + 1);
		}
		FString NewText(Text);
		// if it didn't have a dot, then maybe they just gave a uasset package name
		if (!Dot && !Result)
		{
			int32 LastSlash = NewText.Find(TEXT("/"), ESearchCase::CaseSensitive, ESearchDir::FromEnd);
			if (LastSlash >= 0)
			{
				NewText += TEXT(".");
				NewText += (Text + LastSlash + 1);
				Dot = FCString::Strrchr(*NewText, '.');
			}
		}
		// If we still can't find it, try to load it. (Only try to load fully qualified names)
		if(!Result && Dot)
		{
#if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
			FLinkerLoad* Linker = (OwnerObject != nullptr) ? OwnerObject->GetClass()->GetLinker() : nullptr;
			const bool bDeferAssetImports = (Linker != nullptr) && (Linker->LoadFlags & LOAD_DeferDependencyLoads);

			if (bDeferAssetImports)
			{
				Result = Linker->RequestPlaceholderValue(ObjectClass, Text);
			}
			
			if (Result == nullptr)
#endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
			{
				uint32 LoadFlags = LOAD_NoWarn | LOAD_FindIfFail;

				UE_LOG(LogProperty, Verbose, TEXT("FindImportedObject is attempting to import [%s] (class = %s) with StaticLoadObject"), Text, *GetFullNameSafe(ObjectClass));
				Result = StaticLoadObject(ObjectClass, NULL, Text, NULL, LoadFlags, NULL);

#if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS
				check(!bDeferAssetImports || !Result || !FBlueprintSupport::IsInBlueprintPackage(Result));
#endif // USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS
			}
		}
	}

	// if we found an object, and we have a parent, make sure we are in the same package if the found object is private, unless it's a cross level property
	if (Result && !Result->HasAnyFlags(RF_Public) && OwnerObject && Result->GetOutermost() != OwnerObject->GetOutermost())
	{
		const UObjectPropertyBase* ObjectProperty = dynamic_cast<const UObjectPropertyBase*>(Property);
		if ( !ObjectProperty || !ObjectProperty->AllowCrossLevel())
		{
			UE_LOG(LogProperty, Warning, TEXT("Illegal TEXT reference to a private object in external package (%s) from referencer (%s).  Import failed..."), *Result->GetFullName(), *OwnerObject->GetFullName());
			Result = NULL;
		}
	}

	check(!Result || Result->IsA(RequiredMetaClass));
	return Result;
}
FString FEmitDefaultValueHelper::HandleSpecialTypes(FEmitterLocalContext& Context, const UProperty* Property, const uint8* ValuePtr)
{
	//TODO: Use Path maps for Objects
	if (auto ObjectProperty = Cast<UObjectProperty>(Property))
	{
		UObject* Object = ObjectProperty->GetPropertyValue(ValuePtr);
		if (Object)
		{
			{
				UClass* ObjectClassToUse = Context.GetFirstNativeOrConvertedClass(ObjectProperty->PropertyClass);
				const FString MappedObject = Context.FindGloballyMappedObject(Object, ObjectClassToUse);
				if (!MappedObject.IsEmpty())
				{
					return MappedObject;
				}
			}

			const bool bCreatingSubObjectsOfClass = (Context.CurrentCodeType == FEmitterLocalContext::EGeneratedCodeType::SubobjectsOfClass);
			{
				auto BPGC = Context.GetCurrentlyGeneratedClass();
				auto CDO = BPGC ? BPGC->GetDefaultObject(false) : nullptr;
				if (BPGC && Object && CDO && Object->IsIn(BPGC) && !Object->IsIn(CDO) && bCreatingSubObjectsOfClass)
				{
					return HandleClassSubobject(Context, Object, FEmitterLocalContext::EClassSubobjectList::MiscConvertedSubobjects, true, true);
				}
			}

			if (!bCreatingSubObjectsOfClass && Property->HasAnyPropertyFlags(CPF_InstancedReference))
			{
				const FString CreateAsInstancedSubobject = HandleInstancedSubobject(Context, Object, Object->HasAnyFlags(RF_ArchetypeObject));
				if (!CreateAsInstancedSubobject.IsEmpty())
				{
					return CreateAsInstancedSubobject;
				}
			}
		}
		else if (ObjectProperty->HasMetaData(FBlueprintMetadata::MD_LatentCallbackTarget))
		{
			return TEXT("this");
		}
	}

	if (auto StructProperty = Cast<UStructProperty>(Property))
	{
		FString StructConstructor;
		if (SpecialStructureConstructor(StructProperty->Struct, ValuePtr, &StructConstructor))
		{
			return StructConstructor;
		}
	}

	return FString();
}
	virtual void HandleObjectReference(UObject*& InObject, const UObject* InReferencingObject, const UProperty* InReferencingProperty) override
	{
		UObject* Object = InObject;
		if (!Object || Object->IsA<UBlueprint>())
		{
			return;
		}

		UClass* ActualClass = Cast<UClass>(Dependencies.GetActualStruct());
		UStruct* CurrentlyConvertedStruct = ActualClass ? Dependencies.FindOriginalClass(ActualClass) : Dependencies.GetActualStruct();
		ensure(CurrentlyConvertedStruct);
		if (Object == CurrentlyConvertedStruct)
		{
			return;
		}

		{
			auto ObjAsField = Cast<UField>(Object);
			if (!ObjAsField)
			{
				const bool bTransientObject = (Object->HasAnyFlags(RF_Transient) && !Object->IsIn(CurrentlyConvertedStruct)) || Object->IsIn(GetTransientPackage());
				if (bTransientObject)
				{
					return;
				}

				ObjAsField = Object->GetClass();
			}

			if (ObjAsField && !ObjAsField->HasAnyFlags(RF_ClassDefaultObject))
			{
				if (ObjAsField->IsA<UProperty>())
				{
					ObjAsField = ObjAsField->GetOwnerStruct();
				}
				if (ObjAsField->IsA<UFunction>())
				{
					ObjAsField = ObjAsField->GetOwnerClass();
				}
				IncludeTheHeaderInBody(ObjAsField);
			}
		}

		if ((Object->IsAsset() || Object->IsA<UBlueprintGeneratedClass>()) && !Object->IsIn(CurrentlyConvertedStruct))
		{
			return;
		}

		auto OwnedByAnythingInHierarchy = [&]()->bool
		{
			for (UStruct* IterStruct = CurrentlyConvertedStruct; IterStruct; IterStruct = IterStruct->GetSuperStruct())
			{
				if (Object->IsIn(IterStruct))
				{
					return true;
				}
				UClass* IterClass = Cast<UClass>(IterStruct);
				UObject* CDO = IterClass ? IterClass->GetDefaultObject(false) : nullptr;
				if (CDO && Object->IsIn(CDO))
				{
					return true;
				}
			}
			return false;
		};
		if (!Object->IsA<UField>() && !Object->HasAnyFlags(RF_ClassDefaultObject) && !OwnedByAnythingInHierarchy())
		{
			Object = Object->GetClass();
		}

		FindReferencesForNewObject(Object);
	}
void FFindStronglyConnected::FindAllCycles()
{
	UE_LOG(LogObj, Log, TEXT("Finding Edges"));
	for( FObjectIterator It; It; ++It )
	{
		UObject* Object = *It;
		{
			AllObjects.Add(Object);

			FArchiveFindAllRefs ArFind(Object);

			for (int32 Index = 0; Index < ArFind.References.Num(); Index++)
			{
				AllEdges.Add(Object, ArFind.References[Index]);
				if (AllEdges.Num() % 25000 == 0)
				{
					UE_LOG(LogObj, Log, TEXT("Finding Edges %d"), AllEdges.Num());
				}
			}
		}
	}
	UE_LOG(LogObj, Log, TEXT("Finding Edges Done %d"), AllEdges.Num());

	UE_LOG(LogObj, Log, TEXT("Finding permanent objects"));
	TArray<UObject*> Fringe;
	for (int32 Index = 0; Index < AllObjects.Num(); Index++)
	{
		UObject* Object = AllObjects[Index];
		if (Object->HasAnyFlags(GARBAGE_COLLECTION_KEEPFLAGS))
		{
			PermanentObjects.Add(Object);
			Fringe.Add(Object);
		}
	}
	while (Fringe.Num())
	{
		TArray<UObject*> LastFringe;
		Exchange(LastFringe,Fringe);
		for (int32 Index = 0; Index < LastFringe.Num(); Index++)
		{
			UObject* Object = LastFringe[Index];
			TArray<UObject*> Refs;
			AllEdges.MultiFind(Object, Refs);

			for (int32 IndexRef = 0; IndexRef < Refs.Num(); IndexRef++)
			{
				UObject* RefObject = Refs[IndexRef];
				if (!PermanentObjects.Contains(RefObject))
				{
					PermanentObjects.Add(RefObject);
					Fringe.Add(RefObject);
				}
			}
		}
	}
	for (int32 Index = 0; Index < AllObjects.Num(); Index++)
	{
		UObject* Object = AllObjects[Index];
		if (!PermanentObjects.Contains(Object))
		{
			TempObjects.Add(Object);
		}
	}
	for (TMultiMap<UObject*, UObject*>::TIterator It(AllEdges); It; ++It)
	{
		if (!PermanentObjects.Contains(It.Key()) && !PermanentObjects.Contains(It.Value()))
		{
			Edges.Add(It.Key(),It.Value());
		}
	}
	UE_LOG(LogObj, Log, TEXT("Finding cycles"));

	for (int32 Index = 0; Index < TempObjects.Num(); Index++)
	{
		StrongConnect(TempObjects[Index]);
	}
	UE_LOG(LogObj, Log, TEXT("Finding simple cycles"));
	Stack.Empty();
	NodeIndex.Empty();
	MasterIndex = 1;

	for (int32 Index = 0; Index < Components.Num(); Index++)
	{
		TArray<UObject*>& Dest = SimpleCycles[SimpleCycles.Add(TArray<UObject*>())];
		FindSimpleCycleForComponent(Dest, Components[Index]);
	}
}
	/**
	* Nulls out references to a given object
	*
	* @param InObject - Object to null references to
	*/
	void NullReferencesToObject(UObject* InObject)
	{
		TArray<UObject*> ReplaceableObjects;
		TMap<UObject*, UObject*> ReplacementMap;
		ReplacementMap.Add(InObject, NULL);
		ReplacementMap.GenerateKeyArray(ReplaceableObjects);

		// Find all the properties (and their corresponding objects) that refer to any of the objects to be replaced
		TMap< UObject*, TArray<UProperty*> > ReferencingPropertiesMap;
		for (FObjectIterator ObjIter; ObjIter; ++ObjIter)
		{
			UObject* CurObject = *ObjIter;

			// Find the referencers of the objects to be replaced
			FFindReferencersArchive FindRefsArchive(CurObject, ReplaceableObjects);

			// Inform the object referencing any of the objects to be replaced about the properties that are being forcefully
			// changed, and store both the object doing the referencing as well as the properties that were changed in a map (so that
			// we can correctly call PostEditChange later)
			TMap<UObject*, int32> CurNumReferencesMap;
			TMultiMap<UObject*, UProperty*> CurReferencingPropertiesMMap;
			if (FindRefsArchive.GetReferenceCounts(CurNumReferencesMap, CurReferencingPropertiesMMap) > 0)
			{
				TArray<UProperty*> CurReferencedProperties;
				CurReferencingPropertiesMMap.GenerateValueArray(CurReferencedProperties);
				ReferencingPropertiesMap.Add(CurObject, CurReferencedProperties);
				for (TArray<UProperty*>::TConstIterator RefPropIter(CurReferencedProperties); RefPropIter; ++RefPropIter)
				{
					CurObject->PreEditChange(*RefPropIter);
				}
			}

		}

		// Iterate over the map of referencing objects/changed properties, forcefully replacing the references and then
		// alerting the referencing objects the change has completed via PostEditChange
		int32 NumObjsReplaced = 0;
		for (TMap< UObject*, TArray<UProperty*> >::TConstIterator MapIter(ReferencingPropertiesMap); MapIter; ++MapIter)
		{
			++NumObjsReplaced;

			UObject* CurReplaceObj = MapIter.Key();
			const TArray<UProperty*>& RefPropArray = MapIter.Value();

			FArchiveReplaceObjectRef<UObject> ReplaceAr(CurReplaceObj, ReplacementMap, false, true, false);

			for (TArray<UProperty*>::TConstIterator RefPropIter(RefPropArray); RefPropIter; ++RefPropIter)
			{
				FPropertyChangedEvent PropertyEvent(*RefPropIter);
				CurReplaceObj->PostEditChangeProperty(PropertyEvent);
			}

			if (!CurReplaceObj->HasAnyFlags(RF_Transient) && CurReplaceObj->GetOutermost() != GetTransientPackage())
			{
				if (!CurReplaceObj->RootPackageHasAnyFlags(PKG_CompiledIn))
				{
					CurReplaceObj->MarkPackageDirty();
				}
			}
		}
	}
/**
 * Serializes an FTextureAllocations struct
 */
FArchive& operator<<( FArchive& Ar, FTextureAllocations& TextureAllocations )
{
	int32 NumSummaryTextures = 0;
	int32 NumExportTexturesTotal = 0;
	int32 NumExportTexturesAdded = 0;

	#if UE4_TODO
		// Are we cooking a package?
		if ( Ar.IsSaving() && !Ar.IsTransacting() )
		{
			FLinker* Linker = Ar.GetLinker();

			// Do we need to build the texture allocation data?
			if ( TextureAllocations.TextureTypes.Num() == 0 )
			{
				TArray<UObject*> TagExpObjects;
				GetObjectsWithAnyMarks(TagExpObjects, OBJECTMARK_TagExp);
				for(int32 Index = 0; Index < TagExpObjects.Num(); Index++)
				{
					UObject* Object = TagExpObjects(Index);
					check(Object->HasAnyMarks(OBJECTMARK_TagExp));
					if ( !Object->HasAnyFlags(RF_ClassDefaultObject) )
					{
						if (UTexture2D* Texture2D = dynamic_cast<UTexture2D*>(Object))
						{
							int32 PreAllocateSizeX = 0;
							int32 PreAllocateSizeY = 0;
							int32 PreAllocateNumMips = 0;
							uint32 TexCreateFlags = 0;
							if ( Texture2D->GetResourceMemSettings(Texture2D->FirstResourceMemMip, PreAllocateSizeX, PreAllocateSizeY, PreAllocateNumMips, TexCreateFlags ) )
							{
								TextureAllocations.AddResourceMemInfo(PreAllocateSizeX, PreAllocateSizeY, PreAllocateNumMips, Texture2D->Format, TexCreateFlags );
							}
						}
					}
				}
			}
			// Do we need to fixup the export indices?
			else if ( Ar.GetLinker() )
			{
				NumSummaryTextures = 0;
				FLinker* Linker = Ar.GetLinker();
				for ( int32 TypeIndex=0; TypeIndex < TextureAllocations.TextureTypes.Num(); ++TypeIndex )
				{
					FTextureAllocations::FTextureType& TextureType = TextureAllocations.TextureTypes( TypeIndex );
					NumSummaryTextures += TextureType.ExportIndices.Num();
					TextureType.ExportIndices.Empty();
				}

				NumExportTexturesTotal = 0;
				NumExportTexturesAdded = 0;
				for ( int32 ExportIndex=0; ExportIndex < Linker->ExportMap.Num(); ++ExportIndex )
				{
					UTexture2D* Texture2D = dynamic_cast<UTexture2D*>(Linker->ExportMap(ExportIndex).Object);
					if ( Texture2D && !Texture2D->HasAnyFlags(RF_ClassDefaultObject) )
					{
						NumExportTexturesTotal++;
						int32 PreAllocateSizeX = 0;
						int32 PreAllocateSizeY = 0;
						int32 PreAllocateNumMips = 0;
						uint32 TexCreateFlags = 0;
						if ( Texture2D->GetResourceMemSettings(Texture2D->FirstResourceMemMip, PreAllocateSizeX, PreAllocateSizeY, PreAllocateNumMips, TexCreateFlags ) )
						{
							FTextureAllocations::FTextureType* TextureType = TextureAllocations.FindTextureType(PreAllocateSizeX, PreAllocateSizeY, PreAllocateNumMips, Texture2D->Format, TexCreateFlags);
							check( TextureType );
							TextureType->ExportIndices.Add( ExportIndex );
							NumExportTexturesAdded++;
						}
					}
				}
				check( NumSummaryTextures == NumExportTexturesAdded );
			}
		}
	#endif

	Ar << TextureAllocations.TextureTypes;

	TextureAllocations.PendingAllocationSize = 0;
	TextureAllocations.PendingAllocationCount.Reset();

	return Ar;
}