Files
UnrealEngineUWP/Engine/Source/Developer/IoStoreUtilities/Private/PackageStoreManifest.cpp
Marc Audy 0c3be2b6ad Merge Release-Engine-Staging to Test @ CL# 18240298
[CL 18241953 by Marc Audy in ue5-release-engine-test branch]
2021-11-18 14:37:34 -05:00

246 lines
7.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "PackageStoreManifest.h"
#include "Serialization/JsonWriter.h"
#include "Serialization/JsonReader.h"
#include "Serialization/JsonSerializer.h"
#include "Dom/JsonObject.h"
#include "Misc/FileHelper.h"
#include "Misc/ScopeLock.h"
#include "Misc/Paths.h"
FPackageStoreManifest::FPackageStoreManifest(const FString& InCookedOutputPath)
: CookedOutputPath(InCookedOutputPath)
{
FPaths::NormalizeFilename(CookedOutputPath);
}
void FPackageStoreManifest::BeginPackage(FName PackageName)
{
FScopeLock Lock(&CriticalSection);
FPackageInfo& PackageInfo = PackageInfoByNameMap.FindOrAdd(PackageName);
PackageInfo.PackageName = PackageName;
if (PackageInfo.PackageChunkId.IsValid())
{
FileNameByChunkIdMap.Remove(PackageInfo.PackageChunkId);
PackageInfo.PackageChunkId = FIoChunkId();
}
for (const FIoChunkId& BulkDataChunkId : PackageInfo.BulkDataChunkIds)
{
FileNameByChunkIdMap.Remove(BulkDataChunkId);
}
PackageInfo.BulkDataChunkIds.Empty();
}
void FPackageStoreManifest::AddPackageData(FName PackageName, const FString& FileName, const FIoChunkId& ChunkId)
{
FScopeLock Lock(&CriticalSection);
FPackageInfo* PackageInfo = PackageInfoByNameMap.Find(PackageName);
check(PackageInfo);
PackageInfo->PackageChunkId = ChunkId;
if (!FileName.IsEmpty())
{
FileNameByChunkIdMap.Add(ChunkId, FileName);
}
}
void FPackageStoreManifest::AddBulkData(FName PackageName, const FString& FileName, const FIoChunkId& ChunkId)
{
FScopeLock Lock(&CriticalSection);
FPackageInfo* PackageInfo = PackageInfoByNameMap.Find(PackageName);
check(PackageInfo);
PackageInfo->BulkDataChunkIds.Add(ChunkId);
if (!FileName.IsEmpty())
{
FileNameByChunkIdMap.Add(ChunkId, FileName);
}
}
FIoStatus FPackageStoreManifest::Save(const TCHAR* Filename) const
{
FScopeLock Lock(&CriticalSection);
TStringBuilder<64> ChunkIdStringBuilder;
auto ChunkIdToString = [&ChunkIdStringBuilder](const FIoChunkId& ChunkId)
{
ChunkIdStringBuilder.Reset();
ChunkIdStringBuilder << ChunkId;
return *ChunkIdStringBuilder;
};
FString JsonTcharText;
TSharedRef<TJsonWriter<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>> Writer = TJsonWriterFactory<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>::Create(&JsonTcharText);
Writer->WriteObjectStart();
if (ZenServerInfo)
{
Writer->WriteObjectStart(TEXT("ZenServer"));
Writer->WriteObjectStart(TEXT("Settings"));
ZenServerInfo->Settings.WriteToJson(*Writer);
Writer->WriteObjectEnd();
Writer->WriteValue(TEXT("ProjectId"), ZenServerInfo->ProjectId);
Writer->WriteValue(TEXT("OplogId"), ZenServerInfo->OplogId);
Writer->WriteObjectEnd();
}
Writer->WriteArrayStart(TEXT("Files"));
for (const auto& KV : FileNameByChunkIdMap)
{
Writer->WriteObjectStart();
FString RelativePath = KV.Value;
FPaths::MakePathRelativeTo(RelativePath, *CookedOutputPath);
Writer->WriteValue(TEXT("Path"), RelativePath);
Writer->WriteValue(TEXT("ChunkId"), ChunkIdToString(KV.Key));
Writer->WriteObjectEnd();
}
Writer->WriteArrayEnd();
Writer->WriteArrayStart(TEXT("Packages"));
for (const auto& KV : PackageInfoByNameMap)
{
const FPackageInfo& PackageInfo = KV.Value;
Writer->WriteObjectStart();
Writer->WriteValue(TEXT("Name"), PackageInfo.PackageName.ToString());
Writer->WriteValue(TEXT("PackageChunkId"), ChunkIdToString(PackageInfo.PackageChunkId));
if (!PackageInfo.BulkDataChunkIds.IsEmpty())
{
Writer->WriteArrayStart(TEXT("BulkDataChunkIds"));
for (const FIoChunkId& ChunkId : PackageInfo.BulkDataChunkIds)
{
Writer->WriteValue(ChunkIdToString(ChunkId));
}
Writer->WriteArrayEnd();
}
Writer->WriteObjectEnd();
}
Writer->WriteArrayEnd();
Writer->WriteObjectEnd();
Writer->Close();
if (!FFileHelper::SaveStringToFile(JsonTcharText, Filename))
{
return FIoStatus(EIoErrorCode::FileOpenFailed);
}
return FIoStatus::Ok;
}
FIoStatus FPackageStoreManifest::Load(const TCHAR* Filename)
{
FScopeLock Lock(&CriticalSection);
PackageInfoByNameMap.Empty();
FileNameByChunkIdMap.Empty();
auto ChunkIdFromString = [](const FString& ChunkIdString)
{
FStringView ChunkIdStringView(*ChunkIdString, 24);
uint8 Data[12];
UE::String::HexToBytes(ChunkIdStringView, Data);
FIoChunkId ChunkId;
ChunkId.Set(Data, 12);
return ChunkId;
};
FString JsonText;
if (!FFileHelper::LoadFileToString(JsonText, Filename))
{
return FIoStatus(EIoErrorCode::FileOpenFailed);
}
TSharedPtr<FJsonObject> JsonObject;
TSharedRef<TJsonReader<TCHAR>> Reader = TJsonReaderFactory<TCHAR>::Create(JsonText);
if (!FJsonSerializer::Deserialize(Reader, JsonObject) || !JsonObject.IsValid())
{
return FIoStatus(EIoErrorCode::Unknown);
}
TSharedPtr<FJsonValue> ZenServerValue = JsonObject->Values.FindRef(TEXT("ZenServer"));
if (ZenServerValue)
{
ZenServerInfo = MakeUnique<FZenServerInfo>();
TSharedPtr<FJsonObject> ZenServerObject = ZenServerValue->AsObject();
TSharedPtr<FJsonValue> SettingsValue = ZenServerObject->Values.FindRef(TEXT("Settings"));
if (SettingsValue)
{
TSharedPtr<FJsonObject> SettingsObject = SettingsValue->AsObject();
ZenServerInfo->Settings.ReadFromJson(*SettingsObject);
}
ZenServerInfo->ProjectId = ZenServerObject->Values.FindRef(TEXT("ProjectId"))->AsString();
ZenServerInfo->OplogId = ZenServerObject->Values.FindRef(TEXT("OplogId"))->AsString();
}
TSharedPtr<FJsonValue> FilesArrayValue = JsonObject->Values.FindRef(TEXT("Files"));
TArray<TSharedPtr<FJsonValue>> FilesArray = FilesArrayValue->AsArray();
FileNameByChunkIdMap.Reserve(FilesArray.Num());
for (const TSharedPtr<FJsonValue>& FileValue : FilesArray)
{
TSharedPtr<FJsonObject> FileObject = FileValue->AsObject();
FIoChunkId ChunkId = ChunkIdFromString(FileObject->Values.FindRef(TEXT("ChunkId"))->AsString());
FString RelativePath = FileObject->Values.FindRef(TEXT("Path"))->AsString();
FileNameByChunkIdMap.Add(ChunkId, FPaths::Combine(CookedOutputPath, RelativePath));
}
TArray<TSharedPtr<FJsonValue>> PackagesArray = JsonObject->Values.FindRef(TEXT("Packages"))->AsArray();
PackageInfoByNameMap.Reserve(PackagesArray.Num());
for (const TSharedPtr<FJsonValue>& PackageValue : PackagesArray)
{
TSharedPtr<FJsonObject> PackageObject = PackageValue->AsObject();
FName PackageName = FName(PackageObject->Values.FindRef(TEXT("Name"))->AsString());
FPackageInfo& PackageInfo = PackageInfoByNameMap.FindOrAdd(PackageName);
PackageInfo.PackageName = PackageName;
PackageInfo.PackageChunkId = ChunkIdFromString(PackageObject->Values.FindRef(TEXT("PackageChunkId"))->AsString());
TSharedPtr<FJsonValue> BulkDataChunkIdsValue = PackageObject->Values.FindRef(TEXT("BulkDataChunkIds"));
if (BulkDataChunkIdsValue.IsValid())
{
TArray<TSharedPtr<FJsonValue>> BulkDataChunkIdsArray = BulkDataChunkIdsValue->AsArray();
PackageInfo.BulkDataChunkIds.Reserve(BulkDataChunkIdsArray.Num());
for (const TSharedPtr<FJsonValue>& BulkDataChunkIdValue : BulkDataChunkIdsArray)
{
PackageInfo.BulkDataChunkIds.Add(ChunkIdFromString(BulkDataChunkIdValue->AsString()));
}
}
}
return FIoStatus::Ok;
}
TArray<FPackageStoreManifest::FFileInfo> FPackageStoreManifest::GetFiles() const
{
FScopeLock Lock(&CriticalSection);
TArray<FFileInfo> Files;
Files.Reserve(FileNameByChunkIdMap.Num());
for (const auto& KV : FileNameByChunkIdMap)
{
Files.Add({ KV.Value, KV.Key });
}
return Files;
}
TArray<FPackageStoreManifest::FPackageInfo> FPackageStoreManifest::GetPackages() const
{
FScopeLock Lock(&CriticalSection);
TArray<FPackageInfo> Packages;
PackageInfoByNameMap.GenerateValueArray(Packages);
return Packages;
}
FPackageStoreManifest::FZenServerInfo& FPackageStoreManifest::EditZenServerInfo()
{
FScopeLock Lock(&CriticalSection);
if (!ZenServerInfo)
{
ZenServerInfo = MakeUnique<FZenServerInfo>();
}
return *ZenServerInfo;
}
const FPackageStoreManifest::FZenServerInfo* FPackageStoreManifest::ReadZenServerInfo() const
{
FScopeLock Lock(&CriticalSection);
return ZenServerInfo.Get();
}