Files
UnrealEngineUWP/Engine/Source/Developer/Virtualization/Private/PackageRehydrationProcess.cpp
paul chipchase 30b731c6f1 Add an opt in entry to the asset context menu that allows the user to re-hydrate a virtualized package.
#rb Sebastian.Nordgren
#jira UE-159595
#rnx
#preflight 62d13965a66919b6700c8069

### SVirtualAssetsStatistics
- We do not currently have a virtualization specific editor module and have been piggybacking onto the DDC editor module, so although this new code has nothing to do with the VA statistics panel it seems easier to keep the code in a single file and then split it later when we move it to a virtualization editor module.
- At the moment if the files being hydrated are not checked out then the process will fail. Support for auto checkout will be added in a future submit.

### EditorExperimentalSettings
- By default no change will be made to the context menu. The user must edit the experimental editor settings and opt in to be able to see it.
- This is because the feature should not really be used in day to day workflows and is provided to either fix problems or to make it easier for people developing the virtualization system.

### PackageRehydrationProcess
- Fixed some typos in error messages
- Being unable to write to the package is considered an error rather than a warning. It was demoted to a warning when virtualizing to try and reduce the number of blocked submits but we do not have this problem with rehydration.
- Added code to reset the loader of a package if it happens to be already loaded in the editor now that we can invoke it from the editor.

[CL 21107763 by paul chipchase in ue5-main branch]
2022-07-15 06:38:07 -04:00

142 lines
3.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "PackageRehydrationProcess.h"
#include "HAL/FileManager.h"
#include "Internationalization/Internationalization.h"
#include "Misc/PackageName.h"
#include "Misc/PackagePath.h"
#include "Misc/ScopedSlowTask.h"
#include "PackageUtils.h"
#include "UObject/Linker.h"
#include "UObject/Package.h"
#include "UObject/PackageTrailer.h"
#include "UObject/UObjectGlobals.h"
#include "Virtualization/VirtualizationSystem.h"
#define LOCTEXT_NAMESPACE "Virtualization"
namespace UE::Virtualization
{
void RehydratePackages(const TArray<FString>& Packages, TArray<FText>& OutErrors)
{
TRACE_CPUPROFILER_EVENT_SCOPE(UE::Virtualization::RehydratePackages);
IVirtualizationSystem& System = IVirtualizationSystem::Get();
if (!System.IsEnabled())
{
return;
}
FScopedSlowTask Progress(1.0f, LOCTEXT("VAHydration_Task", "Re-hydrating Assets..."));
Progress.MakeDialog();
for (const FString& FilePath : Packages)
{
if (!FPackageName::IsPackageFilename(FilePath))
{
continue; // Only rehydrate valid packages
}
FPackageTrailer Trailer;
if (!FPackageTrailer::TryLoadFromFile(FilePath, Trailer))
{
continue; // Only rehydrate packages with package trailers
}
TArray<FIoHash> VirtualizedPayloads = Trailer.GetPayloads(EPayloadStorageType::Virtualized);
if (VirtualizedPayloads.IsEmpty())
{
continue; // If the package has no virtualized payloads then we can skip the rest
}
TUniquePtr<FArchive> PackageAr(IFileManager::Get().CreateFileReader(*FilePath));
if (!PackageAr.IsValid())
{
FText Message = FText::Format(LOCTEXT("VAHydration_ReadFailed", "Unable to open the package '{0}' for reading"),
FText::FromString(FilePath));
OutErrors.Add(Message);
return;
}
FPackageTrailerBuilder Builder = FPackageTrailerBuilder::CreateFromTrailer(Trailer, *PackageAr, FilePath);
PackageAr.Reset();
int32 PayloadsHydrated = 0;
for (const FIoHash& Id : VirtualizedPayloads)
{
FCompressedBuffer Payload = System.PullData(Id);
if (!Payload.IsNull())
{
if (Builder.UpdatePayloadAsLocal(Id, Payload))
{
PayloadsHydrated++;
}
else
{
FText Message = FText::Format(LOCTEXT("VAHydration_UpdateStatusFailed", "Unable to update the status for the payload '{0}' in the package '{1}'"),
FText::FromString(LexToString(Id)),
FText::FromString(FilePath));
OutErrors.Add(Message);
return;
}
}
else
{
FText Message = FText::Format(LOCTEXT("VAHydration_PullFailed", "Unable to pull the data for the payload '{0}' for the package '{1}'"),
FText::FromString(LexToString(Id)),
FText::FromString(FilePath));
OutErrors.Add(Message);
return;
}
}
if (PayloadsHydrated)
{
const FString NewPackagePath = DuplicatePackageWithNewTrailer(FilePath, Trailer, Builder, OutErrors);
FString PackageName;
if (FPackageName::TryConvertFilenameToLongPackageName(FilePath, PackageName))
{
UPackage* Package = FindObjectFast<UPackage>(nullptr, *PackageName);
if (Package != nullptr)
{
UE_LOG(LogVirtualization, Verbose, TEXT("Detaching '%s' from disk so that it can be rehydrated"), *FilePath);
ResetLoadersForSave(Package, *FilePath);
}
}
if (CanWriteToFile(FilePath))
{
if (!IFileManager::Get().Move(*FilePath, *NewPackagePath))
{
FText Message = FText::Format(LOCTEXT("VAHydration_MoveFailed", "Unable to replace the package '{0}' with the hydrated version"),
FText::FromString(FilePath));
OutErrors.Add(Message);
return;
}
}
else
{
FText Message = FText::Format(
LOCTEXT("VAHydration_PackageLocked", "The package file '{0}' has virtualized payloads but is locked for modification and cannot be hydrated"),
FText::FromString(FilePath));
OutErrors.Add(Message);
return;
}
}
}
}
} // namespace UE::Virtualization
#undef LOCTEXT_NAMESPACE