Files
UnrealEngineUWP/Engine/Source/Developer/CookMetadata/Public/CookMetadata.h
dan thompson 54f13432d6 Misc CookMetadataFixes:
* Restaging a build no longer just constantly increases size
* Inclusive size actually looks at valid data
* Horde URL environment variable corrected.
* Add a new root pseudo plugin json event that holds the size of all plugins that don't belong to a root plugin.
#rb charles.bloom

[CL 26335038 by dan thompson in ue5-main branch]
2023-06-29 23:20:46 -04:00

261 lines
9.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Containers/Array.h"
#include "Containers/UnrealString.h"
#include "CoreTypes.h"
#include "Memory/MemoryFwd.h"
namespace UE::Cook
{
enum class ECookMetadataStateVersion : uint8
{
InvalidVersion = 0,
PluginHierarchy = 1,
PostWritebackHash = 2,
FixSerialization = 3,
// Add new versions above this.
VersionCount,
LatestVersion = VersionCount - 1
};
/**
* We classify various bits of the plugin data based on how it will be delivered to the end user in order to
* more appropriately track the user's experience.
*
* Each iostore chunk (note: NOT pak chunk!) gets compressed during staging and unreal pak will update the size
* for the plugin based on how the chunk gets deployed.
*/
enum class EPluginSizeTypes : uint8
{
// The iostore chunks will be deployed to servers for downloading on-demand by the game using the Individual Asset Streaming
// system.
Streaming,
// The iostore chunks are written to normal iostore containers that are expected to be distributed with the game. This
// includes the required global iostore container.
Installed,
// The iostore chunks are written to a separate container that isn't required to be distributed with the game. This is where e.g.
// OptionalMips go for textures. They appear as .uptnl files in the Cooked directory (if cooking to Loose Files),
// The CopyBuildToStagingDirectory script manually assigns the iostore chunk to a corresponding pak chunk with the name
// ending in "optional", e.g. pakChunk0optional.pak/ucas/utoc/sig. The only way to catch this in UnrealPak
// is to parse the filename.
Optional,
// These are sidecar files for distributing EditorOnly data for Cooked Editor builds. When cooking to loose files
// they will contain ".o" inside their filename, e.g. "myasset.o.ubulk". They are never intended to be shipped with
// a game.
OptionalSegment,
COUNT
};
constexpr uint8 EPluginSizeTypesCount = (uint8)EPluginSizeTypes::COUNT;
struct FPluginSizeInfo
{
uint64 Sizes[EPluginSizeTypesCount] = {};
void Zero() { FMemory::Memzero(this, sizeof(*this)); }
void AddSizes(uint64 SizesPerType[EPluginSizeTypesCount])
{
for (uint8 Type = 0; Type < EPluginSizeTypesCount; Type++)
{
Sizes[Type] += SizesPerType[Type];
}
}
void Add(const FPluginSizeInfo& Other)
{
for (uint8 Type = 0; Type < EPluginSizeTypesCount; Type++)
{
Sizes[Type] += Other.Sizes[Type];
}
}
uint64 TotalSize() const
{
uint64 Total = 0;
for (uint8 Type = 0; Type < EPluginSizeTypesCount; Type++)
{
Total += Sizes[Type];
}
return Total;
}
friend FArchive& operator<<(FArchive& Ar, FPluginSizeInfo& SizeInfo)
{
for (uint8 i = 0; i < EPluginSizeTypesCount; i++)
{
Ar << SizeInfo.Sizes[i];
}
return Ar;
}
uint64& operator[](EPluginSizeTypes InType) { return Sizes[(uint8)InType]; }
const uint64& operator[](EPluginSizeTypes InType) const { return Sizes[(uint8)InType]; }
};
/*
* Unrealpak doesn't compress the data for all platforms. In those cases, the data written back
* during staging isn't compressed and is not representative of the final sizes that occurs after
* the corresponding SDK tools process them for deployment.
*/
enum class ECookMetadataSizesPresent
{
// staging has not occured, or writeback wasn't enabled in project packaing settings.
NotPresent,
// unrealpak compressed the iostore chunks and the data we have is compressed sizes
Compressed,
// the selected platform isn't compressed by unrealpak, or package compression was disabled.
Uncompressed,
Count
};
/** The name and dependency information for a plugin that was enabled during cooking. */
struct COOKMETADATA_API FCookMetadataPluginEntry
{
FString Name;
// The dependencies are stored in the FCookMetadataPluginHierarchy::PluginDependencies array,
// and this is an index into it. From there you can get a further index into PluginsEnabledAtCook
// to get the plugin information.
// Example:
// for (uint16 DependencyIndex = Plugin->DependencyIndexStart; DependencyIndex < Plugin->DependencyIndexEnd; DependencyIndex++)
// {
// const UE::Cook::FCookMetadataPluginEntry& DependentPlugin = PluginHierarchy.PluginsEnabledAtCook[PluginHierarchy.PluginDependencies[DependencyIndex]];
// }
//
uint16 DependencyIndexStart = 0;
uint16 DependencyIndexEnd = 0;
//
// Theses sizes are set during staging by unrealpak if the option in project packaging is set.
// To determine if they are set, check FCookMetadataState::GetSizesPresent(). Inclusive contains
// the size of the plugin and all of its dependencies listed in its uplugin file.
//
FPluginSizeInfo InclusiveSizes;
FPluginSizeInfo ExclusiveSizes;
uint16 DependencyCount() const { return DependencyIndexEnd - DependencyIndexStart; }
friend FArchive& operator<<(FArchive& Ar, FCookMetadataPluginEntry& Entry)
{
Ar << Entry.Name << Entry.DependencyIndexStart << Entry.DependencyIndexEnd;
Ar << Entry.InclusiveSizes << Entry.ExclusiveSizes;
return Ar;
}
};
struct COOKMETADATA_API FCookMetadataPluginHierarchy
{
// The list of plugins that were enabled during the cook that generated the FCookMetadataState,
// pruned to remove plugins that aren't enabled on the cook platform. If the cook was DLC, this
// is further pruned to only the DLC plugin and its dependencies.
TArray<FCookMetadataPluginEntry> PluginsEnabledAtCook;
// The list of plugin dependencies. FCookMetadataPluginEntry::DependencyIndexStart indexes into this
// array.
TArray<uint16> PluginDependencies;
// The list of root plugins for the project as defined by the Editor.ini file.
TArray<uint16> RootPlugins;
friend FArchive& operator<<(FArchive& Ar, FCookMetadataPluginHierarchy& Hierarchy)
{
return Ar << Hierarchy.PluginsEnabledAtCook << Hierarchy.PluginDependencies << Hierarchy.RootPlugins;
}
};
/**
* Structure serialized to disk to contain non-asset related metadata about a cook. This should always
* exist alongside a Development Asset Registry, and to ensure that the pair is not out of sync, users
* should validate the development asset registry they are using with GetAssociatedDevelopmentAssetRegistryHash().
*/
class COOKMETADATA_API FCookMetadataState
{
public:
FCookMetadataState() = default;
FCookMetadataState(const FCookMetadataState&) = default;
FCookMetadataState(FCookMetadataState&& Rhs) = default;
~FCookMetadataState() = default;
FCookMetadataState& operator=(const FCookMetadataState&) = default;
FCookMetadataState& operator=(FCookMetadataState&& O) = default;
bool IsValid() const { return Version == ECookMetadataStateVersion::LatestVersion; }
void Reset() { *this = FCookMetadataState(); }
bool Serialize(FArchive& Ar);
// Plugin hierarchy information
void SetPluginHierarchyInfo(FCookMetadataPluginHierarchy&& InPluginHierarchy) { PluginHierarchy = MoveTemp(InPluginHierarchy); }
const FCookMetadataPluginHierarchy& GetPluginHierarchy() const { return PluginHierarchy; }
// So that unrealpak can update the sizes.
FCookMetadataPluginHierarchy& GetMutablePluginHierarchy() { return PluginHierarchy; }
/**
* Associated DevAR Hash.
*
* This is computed by reading the development asset registry file into a memory buffer and calling
* ComputeHashOfDevelopmentAssetRegistry on the data.
*
* Use this to ensure that the files you are working with were produced by the same cook and didn't
* get out of sync somehow.
*
* *IMPORTANT* If asset registry writeback is enabled during staging, then the hash of the development
* asset registry changes, and you'll need to check against GetAssociatedDevelopmentAssetRegistryHashPostWriteback.
* If you don't know which one you have, check both - they are both valid.
*
* e.g.
* uint64 CheckHash = GetAssociatedDevelopmentAssetRegistryHash();
* bValidDevAr = ComputeHashOfDevelopmentAssetRegistry(MakeMemoryView(SerializedAssetRegistry)) == CheckHash;
*/
void SetAssociatedDevelopmentAssetRegistryHash(uint64 InHash) { AssociatedDevelopmentAssetRegistryHash = InHash; }
void SetAssociatedDevelopmentAssetRegistryHashPostWriteback(uint64 InHash) { AssociatedDevelopmentAssetRegistryHashPostWriteback = InHash; }
uint64 GetAssociatedDevelopmentAssetRegistryHash() const { return AssociatedDevelopmentAssetRegistryHash; }
uint64 GetAssociatedDevelopmentAssetRegistryHashPostWriteback() const { return AssociatedDevelopmentAssetRegistryHashPostWriteback; }
void SetPlatformAndBuildVersion(const FString& InPlatform, const TCHAR* InBuildVersion) { Platform = InPlatform; BuildVersion = FString(InBuildVersion); }
const FString& GetPlatform() const { return Platform; }
const FString GetBuildVersion() const { return BuildVersion; }
void SetHordeJobId(FString&& InHordeJobId) { HordeJobId = MoveTemp(InHordeJobId); }
const FString& GetHordeJobId() const { return HordeJobId; }
static uint64 ComputeHashOfDevelopmentAssetRegistry(FMemoryView InSerializedDevelopmentAssetRegistry);
// Returns what size information is present in FCookMetadataPluginEntry. This varies based on the platform
// and settings.
FText GetSizesPresentAsText() const;
ECookMetadataSizesPresent GetSizesPresent() const { return SizesPresent; }
void SetSizesPresent(ECookMetadataSizesPresent InSizesPresent) { SizesPresent = InSizesPresent; }
private:
ECookMetadataStateVersion Version = ECookMetadataStateVersion::InvalidVersion;
FCookMetadataPluginHierarchy PluginHierarchy;
uint64 AssociatedDevelopmentAssetRegistryHash = 0;
// Asset registry size writeback changes the AR, so we have a separate hash for that DevAR that this
// also matches.
uint64 AssociatedDevelopmentAssetRegistryHashPostWriteback = 0;
FString Platform;
// BUILD_VERSION definition from definitions.h for the cook.
FString BuildVersion;
// If cooked on Horde, this is the job id that cooked it.
FString HordeJobId;
// Updated by unrealpak when plugin size information is added.
ECookMetadataSizesPresent SizesPresent = ECookMetadataSizesPresent::NotPresent;
};
COOKMETADATA_API const FString& GetCookMetadataFilename();
}; // namespace