void UStructProperty::Serialize( FArchive& Ar ) { Super::Serialize( Ar ); static UScriptStruct* FallbackStruct = GetFallbackStruct(); if (Ar.IsPersistent() && Ar.GetLinker() && Ar.IsLoading() && !Struct) { // It's necessary to solve circular dependency problems, when serializing the Struct causes linking of the Property. Struct = FallbackStruct; } Ar << Struct; #if WITH_EDITOR if (Ar.IsPersistent() && Ar.GetLinker()) { if (!Struct && Ar.IsLoading()) { UE_LOG(LogProperty, Error, TEXT("UStructProperty::Serialize Loading: Property '%s'. Unknown structure."), *GetFullName()); Struct = FallbackStruct; } else if ((FallbackStruct == Struct) && Ar.IsSaving()) { UE_LOG(LogProperty, Error, TEXT("UStructProperty::Serialize Saving: Property '%s'. FallbackStruct structure."), *GetFullName()); } } #endif // WITH_EDITOR if (Struct) { PreloadInnerStructMembers(this); } else { ensure(true); } }
bool FStringAssetReference::Serialize(FArchive& Ar) { #if WITH_EDITOR if (Ar.IsSaving() && Ar.IsPersistent() && FCoreUObjectDelegates::StringAssetReferenceSaving.IsBound()) { AssetLongPathname = FCoreUObjectDelegates::StringAssetReferenceSaving.Execute(AssetLongPathname); } #endif // WITH_EDITOR Ar << *this; #if WITH_EDITOR if (Ar.IsLoading() && Ar.IsPersistent() && FCoreUObjectDelegates::StringAssetReferenceLoaded.IsBound()) { FCoreUObjectDelegates::StringAssetReferenceLoaded.Execute(AssetLongPathname); } #endif // WITH_EDITOR if (Ar.IsLoading() && (Ar.GetPortFlags()&PPF_DuplicateForPIE)) { // Remap unique ID if necessary FixupForPIE(); } return true; }
void UStructProperty::SerializeItem( FArchive& Ar, void* Value, int32 MaxReadBytes, void const* Defaults ) const { const bool bUseBinarySerialization = UseBinarySerialization(Ar); const bool bUseNativeSerialization = UseNativeSerialization(); // Preload struct before serialization tracking to not double count time. if ( bUseBinarySerialization || bUseNativeSerialization) { Ar.Preload( Struct ); } bool bItemSerialized = false; if (bUseNativeSerialization) { UScriptStruct::ICppStructOps* CppStructOps = Struct->GetCppStructOps(); check(CppStructOps); // else should not have STRUCT_SerializeNative check(!Struct->InheritedCppStructOps()); // else should not have STRUCT_SerializeNative bItemSerialized = CppStructOps->Serialize(Ar, Value); } if (!bItemSerialized) { if( bUseBinarySerialization ) { // Struct is already preloaded above. if ( !Ar.IsPersistent() && Ar.GetPortFlags() != 0 && !Struct->ShouldSerializeAtomically(Ar) ) { Struct->SerializeBinEx( Ar, Value, Defaults, Struct ); } else { Struct->SerializeBin( Ar, Value, MaxReadBytes ); } } else { Struct->SerializeTaggedProperties( Ar, (uint8*)Value, Struct, (uint8*)Defaults ); } } if (Struct->StructFlags & STRUCT_PostSerializeNative) { UScriptStruct::ICppStructOps* CppStructOps = Struct->GetCppStructOps(); check(CppStructOps); // else should not have STRUCT_PostSerializeNative check(!Struct->InheritedCppStructOps()); // else should not have STRUCT_PostSerializeNative CppStructOps->PostSerialize(Ar, Value); } }
// UObject interface. void UTransBuffer::Serialize( FArchive& Ar ) { check( !Ar.IsPersistent() ); CheckState(); Super::Serialize( Ar ); if ( IsObjectSerializationEnabled() || !Ar.IsObjectReferenceCollector() ) { Ar << UndoBuffer; } Ar << ResetReason << UndoCount << ActiveCount << ActiveRecordCounts; CheckState(); }
void USoundWave::SerializeCookedPlatformData(FArchive& Ar) { if (IsTemplate()) { return; } DECLARE_SCOPE_CYCLE_COUNTER( TEXT("USoundWave::SerializeCookedPlatformData"), STAT_SoundWave_SerializeCookedPlatformData, STATGROUP_LoadTime ); #if WITH_EDITORONLY_DATA if (Ar.IsCooking() && Ar.IsPersistent()) { check(!Ar.CookingTarget()->IsServerOnly()); FName PlatformFormat = Ar.CookingTarget()->GetWaveFormat(this); FString DerivedDataKey; GetStreamedAudioDerivedDataKey(*this, PlatformFormat, DerivedDataKey); FStreamedAudioPlatformData *PlatformDataToSave = CookedPlatformData.FindRef(DerivedDataKey); if (PlatformDataToSave == NULL) { PlatformDataToSave = new FStreamedAudioPlatformData(); PlatformDataToSave->Cache(*this, PlatformFormat, EStreamedAudioCacheFlags::InlineChunks | EStreamedAudioCacheFlags::Async); CookedPlatformData.Add(DerivedDataKey, PlatformDataToSave); } PlatformDataToSave->FinishCache(); PlatformDataToSave->Serialize(Ar, this); } else #endif // #if WITH_EDITORONLY_DATA { check(!FPlatformProperties::IsServerOnly()); CleanupCachedRunningPlatformData(); check(RunningPlatformData == NULL); // Don't serialize streaming data on servers, even if this platform supports streaming in theory RunningPlatformData = new FStreamedAudioPlatformData(); RunningPlatformData->Serialize(Ar, this); } }
void UAssetObjectProperty::SerializeItem( FArchive& Ar, void* Value, int32 MaxReadBytes, void const* Defaults ) const { // We never serialize our reference while the garbage collector is harvesting references // to objects, because we don't want asset pointers to keep objects from being garbage collected // Allow persistent archives so they can keep track of string references. (e.g. FArchiveSaveTagImports) if( !Ar.IsObjectReferenceCollector() || Ar.IsModifyingWeakAndStrongReferences() || Ar.IsPersistent() ) { FAssetPtr OldValue = *(FAssetPtr*)Value; Ar << *(FAssetPtr*)Value; if (Ar.IsLoading() || Ar.IsModifyingWeakAndStrongReferences()) { if (OldValue.GetUniqueID() != ((FAssetPtr*)Value)->GetUniqueID()) { CheckValidObject(Value); } } } }
// UObject interface. void UTransBuffer::Serialize( FArchive& Ar ) { check( !Ar.IsPersistent() ); CheckState(); // Handle garbage collection. Super::Serialize( Ar ); // We cannot support undoing across GC if we allow it to eliminate references so we need // to suppress it. if ( IsObjectSerializationEnabled() || !Ar.IsObjectReferenceCollector() ) { Ar.AllowEliminatingReferences( false ); Ar << UndoBuffer; Ar.AllowEliminatingReferences( true ); } Ar << ResetReason << UndoCount << ActiveCount; CheckState(); }
void UK2Node_VariableGet::Serialize(FArchive& Ar) { // The following code is to attempt to log info related to UE-19729 if (Ar.IsSaving() && Ar.IsPersistent()) { uint32 PortFlagsToSkip = PPF_Duplicate | PPF_DuplicateForPIE; if (!(Ar.GetPortFlags() & PortFlagsToSkip)) { if (UEdGraph* Graph = Cast<UEdGraph>(GetOuter())) { if (UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForGraph(Graph)) { if (!Blueprint->bBeingCompiled) { // The following line may spur the crash noted in UE-19729 and will confirm that the crash happens before the FiB gather. GetNodeTitle(ENodeTitleType::ListView); } } } } } Super::Serialize(Ar); }
/** * Serialize function used to serialize this bulk data structure. * * @param Ar Archive to serialize with * @param Owner Object owning the bulk data * @param Idx Index of bulk data item being serialized */ void FUntypedBulkData::Serialize( FArchive& Ar, UObject* Owner, int32 Idx ) { check( LockStatus == LOCKSTATUS_Unlocked ); if(Ar.IsTransacting()) { // Special case for transacting bulk data arrays. // constructing the object during load will save it to the transaction buffer. If it tries to load the bulk data now it will try to break it. bool bActuallySave = Ar.IsSaving() && (!Owner || !Owner->HasAnyFlags(RF_NeedLoad)); Ar << bActuallySave; if (bActuallySave) { if(Ar.IsLoading()) { // Flags for bulk data. Ar << BulkDataFlags; // Number of elements in array. Ar << ElementCount; // Allocate bulk data. check(bShouldFreeOnEmpty); BulkData = FMemory::Realloc( BulkData, GetBulkDataSize() ); // Deserialize bulk data. SerializeBulkData( Ar, BulkData ); } else if(Ar.IsSaving()) { // Flags for bulk data. Ar << BulkDataFlags; // Number of elements in array. Ar << ElementCount; // Don't attempt to load or serialize BulkData if the current size is 0. // This could be a newly constructed BulkData that has not yet been loaded, // and allocating 0 bytes now will cause a crash when we load. if (GetBulkDataSize() > 0) { // Make sure bulk data is loaded. MakeSureBulkDataIsLoaded(); // Serialize bulk data. SerializeBulkData(Ar, BulkData); } } } } else if( Ar.IsPersistent() && !Ar.IsObjectReferenceCollector() && !Ar.ShouldSkipBulkData() ) { #if TRACK_BULKDATA_USE FThreadSafeBulkDataToObjectMap::Get().Add( this, Owner ); #endif // Offset where the bulkdata flags are stored int64 SavedBulkDataFlagsPos = Ar.Tell(); Ar << BulkDataFlags; // Number of elements in array. Ar << ElementCount; // We're loading from the persistent archive. if( Ar.IsLoading() ) { Filename = TEXT(""); // @todo when Landscape (and others?) only Lock/Unlock once, we can enable this if (false) // FPlatformProperties::RequiresCookedData()) { // Bulk data that is being serialized via seekfree loading is single use only. This allows us // to free the memory as e.g. the bulk data won't be attached to an archive in the case of // seek free loading. BulkDataFlags |= BULKDATA_SingleUse; } // Size on disk, which in the case of compression is != GetBulkDataSize() Ar << BulkDataSizeOnDisk; Ar << BulkDataOffsetInFile; // fix up the file offset if (Owner != NULL && Owner->GetLinker()) { BulkDataOffsetInFile += Owner->GetLinker()->Summary.BulkDataStartOffset; } // determine whether the payload is stored inline or at the end of the file bool bPayloadInline = !(BulkDataFlags&BULKDATA_PayloadAtEndOfFile); // check( (bPayloadInline && BulkDataOffsetInFile == Ar.Tell()) || // (!bPayloadInline && BulkDataOffsetInFile > Ar.Tell())); // We're allowing defered serialization. if( Ar.IsAllowingLazyLoading() && Owner != NULL) { Linker = Owner->GetLinker(); #if WITH_EDITOR check(Linker); Ar.AttachBulkData( Owner, this ); AttachedAr = &Ar; #else check(Linker.IsValid()); Filename = Linker->Filename; #endif // WITH_EDITOR // only skip over payload, if it's stored inline if (bPayloadInline) { Ar.Seek( Ar.Tell() + BulkDataSizeOnDisk ); } } // Serialize the bulk data right away. else { // memory for bulk data can come from preallocated GPU-accessible resource memory or default to system memory BulkData = GetBulkDataResourceMemory(Owner,Idx); if( !BulkData ) { BulkData = FMemory::Realloc( BulkData, GetBulkDataSize() ); } if (bPayloadInline) { // if the payload is stored inline, just serialize it SerializeBulkData( Ar, BulkData ); } else { // if the payload is NOT stored inline ... // store the current file offset int64 CurOffset = Ar.Tell(); // seek to the location in the file where the payload is stored Ar.Seek(BulkDataOffsetInFile); // serialize the payload SerializeBulkData( Ar, BulkData ); // seek to the location we came from Ar.Seek(CurOffset); } } } // We're saving to the persistent archive. else if( Ar.IsSaving() ) { // check if we save the package compressed UPackage* Pkg = Owner ? dynamic_cast<UPackage*>(Owner->GetOutermost()) : nullptr; if (Pkg && !!(Pkg->PackageFlags & PKG_StoreCompressed) ) { ECompressionFlags BaseCompressionMethod = COMPRESS_Default; if (Ar.IsCooking()) { BaseCompressionMethod = Ar.CookingTarget()->GetBaseCompressionMethod(); } StoreCompressedOnDisk(BaseCompressionMethod); } // Remove single element serialization requirement before saving out bulk data flags. BulkDataFlags &= ~BULKDATA_ForceSingleElementSerialization; // Make sure bulk data is loaded. MakeSureBulkDataIsLoaded(); // Only serialize status information if wanted. int64 SavedBulkDataSizeOnDiskPos = INDEX_NONE; int64 SavedBulkDataOffsetInFilePos = INDEX_NONE; // Keep track of position we are going to serialize placeholder BulkDataSizeOnDisk. SavedBulkDataSizeOnDiskPos = Ar.Tell(); BulkDataSizeOnDisk = INDEX_NONE; // And serialize the placeholder which is going to be overwritten later. Ar << BulkDataSizeOnDisk; // Keep track of position we are going to serialize placeholder BulkDataOffsetInFile. SavedBulkDataOffsetInFilePos = Ar.Tell(); BulkDataOffsetInFile = INDEX_NONE; // And serialize the placeholder which is going to be overwritten later. Ar << BulkDataOffsetInFile; // try to get the linkersave object ULinkerSave* LinkerSave = dynamic_cast<ULinkerSave*>(Ar.GetLinker()); // determine whether we are going to store the payload inline or not. bool bStoreInline = !!(BulkDataFlags&BULKDATA_ForceInlinePayload) || LinkerSave == NULL; if (!bStoreInline) { // set the flag indicating where the payload is stored BulkDataFlags |= BULKDATA_PayloadAtEndOfFile; // with no LinkerSave we have to store the data inline check(LinkerSave != NULL); // add the bulkdata storage info object to the linkersave int32 Index = LinkerSave->BulkDataToAppend.AddZeroed(1); ULinkerSave::FBulkDataStorageInfo& BulkStore = LinkerSave->BulkDataToAppend[Index]; BulkStore.BulkDataOffsetInFilePos = SavedBulkDataOffsetInFilePos; BulkStore.BulkDataSizeOnDiskPos = SavedBulkDataSizeOnDiskPos; BulkStore.BulkData = this; // Serialize bulk data into the storage info BulkDataSizeOnDisk = -1; } else { // set the flag indicating where the payload is stored BulkDataFlags &= ~BULKDATA_PayloadAtEndOfFile; int64 SavedBulkDataStartPos = Ar.Tell(); // Serialize bulk data. SerializeBulkData( Ar, BulkData ); // store the payload endpos int64 SavedBulkDataEndPos = Ar.Tell(); checkf(SavedBulkDataStartPos >= 0 && SavedBulkDataEndPos >= 0, TEXT("Bad archive positions for bulkdata. StartPos=%d EndPos=%d"), SavedBulkDataStartPos, SavedBulkDataEndPos); BulkDataSizeOnDisk = SavedBulkDataEndPos - SavedBulkDataStartPos; BulkDataOffsetInFile = SavedBulkDataStartPos; } // store current file offset before seeking back int64 CurrentFileOffset = Ar.Tell(); // Seek back and overwrite the flags Ar.Seek(SavedBulkDataFlagsPos); Ar << BulkDataFlags; // Seek back and overwrite placeholder for BulkDataSizeOnDisk Ar.Seek( SavedBulkDataSizeOnDiskPos ); Ar << BulkDataSizeOnDisk; // Seek back and overwrite placeholder for BulkDataOffsetInFile Ar.Seek( SavedBulkDataOffsetInFilePos ); Ar << BulkDataOffsetInFile; // Seek to the end of written data so we don't clobber any data in subsequent write // operations Ar.Seek(CurrentFileOffset); } } }
void FTextHistory_Base::SerializeForDisplayString(FArchive& Ar, FTextDisplayStringRef& InOutDisplayString) { if(Ar.IsLoading()) { // We will definitely need to do a rebuild later Revision = INDEX_NONE; FString Namespace; FString Key; FString SourceStringRaw; Ar << Namespace; Ar << Key; Ar << SourceStringRaw; // If there was a SourceString, store it in the member variable if(!SourceStringRaw.IsEmpty()) { SourceString = MakeShareable(new FString(SourceStringRaw)); } // Using the deserialized namespace and key, find the DisplayString. InOutDisplayString = FTextLocalizationManager::Get().GetDisplayString(Namespace, Key, SourceString.Get()); } else if(Ar.IsSaving()) { FString Namespace; FString Key; const bool FoundNamespaceAndKey = FTextLocalizationManager::Get().FindNamespaceAndKeyFromDisplayString(InOutDisplayString, Namespace, Key); // If this has no namespace or key, attempt to give it a GUID for a key and register it. if (!FoundNamespaceAndKey && GIsEditor && (Ar.IsPersistent() && !Ar.HasAnyPortFlags(PPF_Duplicate))) { Key = FGuid::NewGuid().ToString(); if (!FTextLocalizationManager::Get().AddDisplayString(InOutDisplayString, Namespace, Key)) { // Could not add display string, reset namespace and key. Namespace.Empty(); Key.Empty(); } } // Serialize the Namespace Ar << Namespace; // Serialize the Key Ar << Key; // Serialize the SourceString, or an empty string if there is none if( SourceString.IsValid() ) { Ar << *(SourceString); } else { FString Empty; Ar << Empty; } } }
//------------------------------------------------------------------------------ bool FStructScriptLoader::LoadStructWithScript(UStruct* DestScriptContainer, FArchive& Ar, bool bAllowDeferredSerialization) { if (!Ar.IsLoading() || !IsPrimed() || GIsDuplicatingClassForReinstancing) { return false; } bool const bIsLinkerLoader = Ar.IsPersistent() && (Ar.GetLinker() != nullptr); int32 const ScriptEndOffset = ScriptSerializationOffset + SerializedScriptSize; // to help us move development forward (and not have to support ancient // script code), we define a minimum script version bool bSkipScriptSerialization = (Ar.UE4Ver() < VER_MIN_SCRIPTVM_UE4) || (Ar.LicenseeUE4Ver() < VER_MIN_SCRIPTVM_LICENSEEUE4); #if WITH_EDITOR static const FBoolConfigValueHelper SkipByteCodeHelper(TEXT("StructSerialization"), TEXT("SkipByteCodeSerialization")); // in editor builds, we're going to regenerate the bytecode anyways, so it // is a waste of cycles to try and serialize it in bSkipScriptSerialization |= (bool)SkipByteCodeHelper; #endif // WITH_EDITOR bSkipScriptSerialization &= bIsLinkerLoader; // to keep consistent with old UStruct::Serialize() functionality if (bSkipScriptSerialization) { int32 TrackedBufferSize = BytecodeBufferSize; BytecodeBufferSize = 0; // temporarily clear so that ClearScriptCode() doesn't leave Class->Script with anything allocated ClearScriptCode(DestScriptContainer); BytecodeBufferSize = TrackedBufferSize; // we have to at least move the archiver forward, so it is positioned // where it expects to be (as if we read in the script) Ar.Seek(ScriptEndOffset); return false; } bAllowDeferredSerialization &= bIsLinkerLoader; if (bAllowDeferredSerialization && ShouldDeferScriptSerialization(Ar)) { ULinkerLoad* Linker = CastChecked<ULinkerLoad>(Ar.GetLinker()); FDeferredScriptTracker::Get().AddDeferredScriptObject(Linker, DestScriptContainer, *this); // we have to at least move the archiver forward, so it is positioned // where it expects to be (as if we read in the script) Ar.Seek(ScriptEndOffset); return false; } Ar.Seek(ScriptSerializationOffset); if (bIsLinkerLoader) { ULinkerLoad* LinkerLoad = CastChecked<ULinkerLoad>(Ar.GetLinker()); TArray<uint8> ShaScriptBuffer; ShaScriptBuffer.AddUninitialized(SerializedScriptSize); Ar.Serialize(ShaScriptBuffer.GetData(), SerializedScriptSize); ensure(ScriptEndOffset == Ar.Tell()); LinkerLoad->UpdateScriptSHAKey(ShaScriptBuffer); Ar.Seek(ScriptSerializationOffset); } DestScriptContainer->Script.Empty(BytecodeBufferSize); DestScriptContainer->Script.AddUninitialized(BytecodeBufferSize); int32 BytecodeIndex = 0; while (BytecodeIndex < BytecodeBufferSize) { DestScriptContainer->SerializeExpr(BytecodeIndex, Ar); } ensure(ScriptEndOffset == Ar.Tell()); checkf(BytecodeIndex == BytecodeBufferSize, TEXT("'%s' script expression-count mismatch; Expected: %i, Got: %i"), *DestScriptContainer->GetName(), BytecodeBufferSize, BytecodeIndex); if (!GUObjectArray.IsDisregardForGC(DestScriptContainer)) { DestScriptContainer->ScriptObjectReferences.Empty(); FArchiveScriptReferenceCollector ObjRefCollector(DestScriptContainer->ScriptObjectReferences); BytecodeIndex = 0; while (BytecodeIndex < BytecodeBufferSize) { DestScriptContainer->SerializeExpr(BytecodeIndex, ObjRefCollector); } } // success! (we filled the target with serialized script code) return true; }