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); } } } }
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; }
/** * Exports the property values for the specified object as text to the output device. * * @param Context Context from which the set of 'inner' objects is extracted. If NULL, an object iterator will be used. * @param Out the output device to send the exported text to * @param ObjectClass the class of the object to dump properties for * @param Object the address of the object to dump properties for * @param Indent number of spaces to prepend to each line of output * @param DiffClass the class to use for comparing property values when delta export is desired. * @param Diff the address of the object to use for determining whether a property value should be exported. If the value in Object matches the corresponding * value in Diff, it is not exported. Specify NULL to export all properties. * @param Parent the UObject corresponding to Object * @param PortFlags flags used for modifying the output and/or behavior of the export */ void ExportProperties ( const FExportObjectInnerContext* Context, FOutputDevice& Out, UClass* ObjectClass, uint8* Object, int32 Indent, UClass* DiffClass, uint8* Diff, UObject* Parent, uint32 PortFlags, UObject* ExportRootScope ) { FString ThisName = TEXT("(none)"); check(ObjectClass != NULL); for( UProperty* Property = ObjectClass->PropertyLink; Property; Property = Property->PropertyLinkNext ) { if (!Property->ShouldPort(PortFlags)) continue; ThisName = Property->GetName(); UArrayProperty* ArrayProperty = Cast<UArrayProperty>(Property); UObjectPropertyBase* ExportObjectProp = (Property->PropertyFlags & CPF_ExportObject) != 0 ? Cast<UObjectPropertyBase>(Property) : NULL; const uint32 ExportFlags = PortFlags | PPF_Delimited; if ( ArrayProperty != NULL ) { // Export dynamic array. UProperty* InnerProp = ArrayProperty->Inner; ExportObjectProp = (Property->PropertyFlags & CPF_ExportObject) != 0 ? Cast<UObjectPropertyBase>(InnerProp) : NULL; // This is used as the default value in the case of an array property that has // fewer elements than the exported object. uint8* StructDefaults = NULL; UStructProperty* StructProperty = Cast<UStructProperty>(InnerProp); if ( StructProperty != NULL ) { checkSlow(StructProperty->Struct); StructDefaults = (uint8*)FMemory::Malloc(StructProperty->Struct->GetStructureSize()); StructProperty->InitializeValue(StructDefaults); } for( int32 PropertyArrayIndex=0; PropertyArrayIndex<Property->ArrayDim; PropertyArrayIndex++ ) { void* Arr = Property->ContainerPtrToValuePtr<void>(Object, PropertyArrayIndex); FScriptArrayHelper ArrayHelper(ArrayProperty, Arr); void* DiffArr = NULL; if( DiffClass ) { DiffArr = Property->ContainerPtrToValuePtrForDefaults<void>(DiffClass, Diff, PropertyArrayIndex); } // we won't use this if DiffArr is NULL, but we have to set it up to something FScriptArrayHelper DiffArrayHelper(ArrayProperty, DiffArr); bool bAnyElementDiffered = false; for( int32 DynamicArrayIndex=0; DynamicArrayIndex<ArrayHelper.Num(); DynamicArrayIndex++ ) { FString Value; // compare each element's value manually so that elements which match the NULL value for the array's inner property type // but aren't in the diff array are still exported uint8* SourceData = ArrayHelper.GetRawPtr(DynamicArrayIndex); uint8* DiffData = DiffArr && DynamicArrayIndex < DiffArrayHelper.Num() ? DiffArrayHelper.GetRawPtr(DynamicArrayIndex) : StructDefaults; bool bExportItem = DiffData == NULL || (DiffData != SourceData && !InnerProp->Identical(SourceData, DiffData, ExportFlags)); if ( bExportItem ) { bAnyElementDiffered = true; InnerProp->ExportTextItem(Value, SourceData, DiffData, Parent, ExportFlags, ExportRootScope); if(ExportObjectProp) { UObject* Obj = ExportObjectProp->GetObjectPropertyValue(ArrayHelper.GetRawPtr(DynamicArrayIndex)); check(!Obj || Obj->IsValidLowLevel()); if( Obj && !Obj->HasAnyMarks(OBJECTMARK_TagImp) ) { // only export the BEGIN OBJECT block for a component if Parent is the component's Outer....when importing subobject definitions, // (i.e. BEGIN OBJECT), whichever BEGIN OBJECT block a component's BEGIN OBJECT block is located within is the object that will be // used as the Outer to create the component // Is this an array of components? if ( InnerProp->HasAnyPropertyFlags(CPF_InstancedReference) ) { if ( Obj->GetOuter() == Parent ) { // Don't export more than once. Obj->Mark(OBJECTMARK_TagImp); UExporter::ExportToOutputDevice( Context, Obj, NULL, Out, TEXT("T3D"), Indent, PortFlags ); } else { // set the OBJECTMARK_TagExp flag so that the calling code knows we wanted to export this object Obj->Mark(OBJECTMARK_TagExp); } } else { // Don't export more than once. Obj->Mark(OBJECTMARK_TagImp); UExporter::ExportToOutputDevice( Context, Obj, NULL, Out, TEXT("T3D"), Indent, PortFlags ); } } } Out.Logf( TEXT("%s%s(%i)=%s\r\n"), FCString::Spc(Indent), *Property->GetName(), DynamicArrayIndex, *Value ); } // if some other element has already been determined to differ from the defaults, then export this item with no data so that // the different array's size is maintained on import (this item will get the default values for that index, if any) // however, if no elements of the array have changed, we still don't want to export anything // so that the array size will also be taken from the defaults, which won't be the case if any element is exported else if (bAnyElementDiffered) { Out.Logf( TEXT("%s%s(%i)=()\r\n"), FCString::Spc(Indent), *Property->GetName(), DynamicArrayIndex ); } } } if (StructDefaults) { StructProperty->DestroyValue(StructDefaults); FMemory::Free(StructDefaults); } } else { for( int32 PropertyArrayIndex=0; PropertyArrayIndex<Property->ArrayDim; PropertyArrayIndex++ ) { FString Value; // Export single element. uint8* DiffData = (DiffClass && Property->IsInContainer(DiffClass->GetPropertiesSize())) ? Diff : NULL; if( Property->ExportText_InContainer( PropertyArrayIndex, Value, Object, DiffData, Parent, ExportFlags, ExportRootScope ) ) { if ( ExportObjectProp ) { UObject* Obj = ExportObjectProp->GetObjectPropertyValue(Property->ContainerPtrToValuePtr<void>(Object, PropertyArrayIndex)); if( Obj && !Obj->HasAnyMarks(OBJECTMARK_TagImp) ) { // only export the BEGIN OBJECT block for a component if Parent is the component's Outer....when importing subobject definitions, // (i.e. BEGIN OBJECT), whichever BEGIN OBJECT block a component's BEGIN OBJECT block is located within is the object that will be // used as the Outer to create the component if ( Property->HasAnyPropertyFlags(CPF_InstancedReference) ) { if ( Obj->GetOuter() == Parent ) { // Don't export more than once. Obj->Mark(OBJECTMARK_TagImp); UExporter::ExportToOutputDevice( Context, Obj, NULL, Out, TEXT("T3D"), Indent, PortFlags ); } else { // set the OBJECTMARK_TagExp flag so that the calling code knows we wanted to export this object Obj->Mark(OBJECTMARK_TagExp); } } else { // Don't export more than once. Obj->Mark(OBJECTMARK_TagImp); UExporter::ExportToOutputDevice( Context, Obj, NULL, Out, TEXT("T3D"), Indent, PortFlags ); } } } if( Property->ArrayDim == 1 ) { Out.Logf( TEXT("%s%s=%s\r\n"), FCString::Spc(Indent), *Property->GetName(), *Value ); } else { Out.Logf( TEXT("%s%s(%i)=%s\r\n"), FCString::Spc(Indent), *Property->GetName(), PropertyArrayIndex, *Value ); } } } } } // Allows to import/export C++ properties in case the automatic unreal script mesh wouldn't work. Parent->ExportCustomProperties(Out, Indent); }
/** * 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; } } } }
/** * 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; }