2023-06-19 13:59:07 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "CookMetadata.h"
2023-09-08 19:51:52 -04:00
# include "HAL/FileManager.h"
2023-06-19 13:59:07 -04:00
# include "Hash/xxhash.h"
2023-06-26 17:21:53 -04:00
# include "Internationalization/Internationalization.h"
2023-06-19 13:59:07 -04:00
# include "Memory/MemoryView.h"
2023-09-08 19:51:52 -04:00
# include "Misc/FileHelper.h"
# include "Serialization/ArrayWriter.h"
# include "Serialization/LargeMemoryReader.h"
2023-06-19 13:59:07 -04:00
namespace UE : : Cook
{
const FString & GetCookMetadataFilename ( )
{
static const FString CookMetadataFilename ( TEXT ( " CookMetadata.ucookmeta " ) ) ;
return CookMetadataFilename ;
}
constexpr uint32 COOK_METADATA_HEADER_MAGIC = ' UCMT ' ;
2023-09-08 19:51:52 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogCookedMetadata , Log , All )
2023-10-19 12:37:07 -04:00
// For backwards compatibility - remove this after 5.4 is released.
/** The name and dependency information for a plugin that was enabled during cooking. */
struct COOKMETADATA_API FCookMetadataPluginEntry_ActualAddShaderPseudoHierarchy
{
FString Name ;
ECookMetadataPluginType Type = ECookMetadataPluginType : : Unassigned ;
TMap < uint8 , bool > CustomBoolFields ;
TMap < uint8 , FString > CustomStringFields ;
uint32 DependencyIndexStart = 0 ;
uint32 DependencyIndexEnd = 0 ;
FPluginSizeInfo InclusiveSizes ;
FPluginSizeInfo ExclusiveSizes ;
friend FArchive & operator < < ( FArchive & Ar , FCookMetadataPluginEntry_ActualAddShaderPseudoHierarchy & Entry )
{
Ar < < Entry . Name < < Entry . DependencyIndexStart < < Entry . DependencyIndexEnd ;
Ar < < Entry . InclusiveSizes < < Entry . ExclusiveSizes ;
Ar < < Entry . CustomBoolFields < < Entry . CustomStringFields < < Entry . Type ;
return Ar ;
}
} ;
struct FCookMetadataPluginHierarchy_ActualAddShaderPseudoHierarchy
{
TArray < FCookMetadataPluginEntry_ActualAddShaderPseudoHierarchy > PluginsEnabledAtCook ;
TArray < uint16 > PluginDependencies ;
TArray < uint16 > RootPlugins ;
TArray < FString > CustomFieldNames ;
friend FArchive & operator < < ( FArchive & Ar , FCookMetadataPluginHierarchy_ActualAddShaderPseudoHierarchy & Hierarchy )
{
Ar < < Hierarchy . PluginsEnabledAtCook < < Hierarchy . PluginDependencies ;
Ar < < Hierarchy . RootPlugins < < Hierarchy . CustomFieldNames ;
return Ar ;
}
} ;
static void FCookMetadataPluginHierarchy_ActualAddShaderPseudoHierarchy_To_AdjustCustomFieldLayout (
FCookMetadataPluginHierarchy_ActualAddShaderPseudoHierarchy & From ,
FCookMetadataPluginHierarchy & To )
{
To . PluginDependencies = MoveTemp ( From . PluginDependencies ) ;
To . RootPlugins = MoveTemp ( From . RootPlugins ) ;
// Now bring over the plugins themselves.
TMap < uint8 , bool > TypeIsBool ;
for ( FCookMetadataPluginEntry_ActualAddShaderPseudoHierarchy & OldEntry : From . PluginsEnabledAtCook )
{
FCookMetadataPluginEntry & NewEntry = To . PluginsEnabledAtCook . AddDefaulted_GetRef ( ) ;
NewEntry . Name = MoveTemp ( OldEntry . Name ) ;
NewEntry . Type = OldEntry . Type ;
for ( TPair < uint8 , bool > & Bools : OldEntry . CustomBoolFields )
{
FCookMetadataPluginEntry : : CustomFieldVariantType V ;
V . Set < bool > ( Bools . Value ) ;
NewEntry . CustomFields . Add ( Bools . Key , MoveTemp ( V ) ) ;
TypeIsBool . Add ( Bools . Key , true ) ;
}
for ( TPair < uint8 , FString > & Strings : OldEntry . CustomStringFields )
{
FCookMetadataPluginEntry : : CustomFieldVariantType V ;
V . Emplace < FString > ( MoveTemp ( Strings . Value ) ) ;
NewEntry . CustomFields . Add ( Strings . Key , MoveTemp ( V ) ) ;
TypeIsBool . Add ( Strings . Key , false ) ;
}
NewEntry . DependencyIndexStart = OldEntry . DependencyIndexStart ;
NewEntry . DependencyIndexEnd = OldEntry . DependencyIndexEnd ;
NewEntry . InclusiveSizes = OldEntry . InclusiveSizes ;
NewEntry . ExclusiveSizes = OldEntry . ExclusiveSizes ;
}
uint8 EntryIndex = 0 ;
for ( FString & FieldName : From . CustomFieldNames )
{
FCookMetadataPluginHierarchy : : FCustomFieldEntry Field = To . CustomFieldEntries . AddDefaulted_GetRef ( ) ;
Field . Name = MoveTemp ( FieldName ) ;
Field . Type = ECookMetadataCustomFieldType : : Unknown ;
const bool * bIsBool = TypeIsBool . Find ( EntryIndex ) ;
if ( bIsBool )
{
if ( * bIsBool )
{
Field . Type = ECookMetadataCustomFieldType : : Bool ;
}
else
{
Field . Type = ECookMetadataCustomFieldType : : String ;
}
}
EntryIndex + + ;
}
}
2023-06-19 13:59:07 -04:00
bool FCookMetadataState : : Serialize ( FArchive & Ar )
{
uint32 MagicHeader = 0 ;
if ( Ar . IsLoading ( ) )
{
Ar < < MagicHeader ;
if ( MagicHeader ! = COOK_METADATA_HEADER_MAGIC )
{
return false ; // not a metadata file.
}
}
else
{
MagicHeader = COOK_METADATA_HEADER_MAGIC ;
Ar < < MagicHeader ;
2023-06-23 19:05:46 -04:00
Version = ECookMetadataStateVersion : : LatestVersion ;
2023-06-19 13:59:07 -04:00
}
2023-06-23 19:05:46 -04:00
2023-10-12 16:58:13 -04:00
bool bSerializeShaderHierarchy = true ;
2023-06-19 13:59:07 -04:00
Ar < < Version ;
2023-06-23 19:05:46 -04:00
if ( Ar . IsLoading ( ) )
{
2023-10-12 16:58:13 -04:00
if ( Version < ECookMetadataStateVersion : : AddedPluginEntryType )
2023-06-23 19:05:46 -04:00
{
2023-10-12 16:58:13 -04:00
UE_LOG ( LogCookedMetadata , Error , TEXT ( " Cook metadata version too old: found %d, we can load %d, latest is %d " ) , Version , ECookMetadataStateVersion : : AddedPluginEntryType , ECookMetadataStateVersion : : LatestVersion ) ;
2023-06-23 19:05:46 -04:00
return false ; // invalid version - current we don't support backcompat
}
2023-10-12 16:58:13 -04:00
if ( Version > ECookMetadataStateVersion : : LatestVersion )
{
UE_LOG ( LogCookedMetadata , Error , TEXT ( " Cook metadata version too new: found %d, latest is %d " ) , Version , ECookMetadataStateVersion : : LatestVersion ) ;
return false ;
}
bSerializeShaderHierarchy = Version > = ECookMetadataStateVersion : : ActualAddShaderPseudoHierarchy ;
2023-06-23 19:05:46 -04:00
}
2023-10-19 12:37:07 -04:00
if ( Ar . IsLoading ( ) & & Version < = ECookMetadataStateVersion : : ActualAddShaderPseudoHierarchy )
{
// Serialize the old hierarchy and convert to the new layout.
FCookMetadataPluginHierarchy_ActualAddShaderPseudoHierarchy OldHierarchy ;
Ar < < OldHierarchy ;
FCookMetadataPluginHierarchy_ActualAddShaderPseudoHierarchy_To_AdjustCustomFieldLayout (
OldHierarchy , PluginHierarchy ) ;
}
else
{
// saving, or on a version with the new setup.
Ar < < PluginHierarchy ;
}
2023-06-19 13:59:07 -04:00
Ar < < AssociatedDevelopmentAssetRegistryHash ;
2023-06-22 17:32:20 -04:00
Ar < < AssociatedDevelopmentAssetRegistryHashPostWriteback ;
Ar < < Platform ;
Ar < < BuildVersion ;
Ar < < HordeJobId ;
2023-06-23 19:05:46 -04:00
Ar < < SizesPresent ;
2023-10-12 16:58:13 -04:00
if ( bSerializeShaderHierarchy )
{
Ar < < ShaderPseudoHierarchy ;
}
2023-06-19 13:59:07 -04:00
return true ;
}
2023-09-08 19:51:52 -04:00
bool FCookMetadataState : : ReadFromFile ( const FString & FilePath )
{
TUniquePtr < FArchive > FileReader ( IFileManager : : Get ( ) . CreateFileReader ( * FilePath ) ) ;
if ( FileReader )
{
TArray64 < uint8 > Data ;
Data . SetNumUninitialized ( FileReader - > TotalSize ( ) ) ;
FileReader - > Serialize ( Data . GetData ( ) , Data . Num ( ) ) ;
check ( ! FileReader - > IsError ( ) ) ;
FLargeMemoryReader MemoryReader ( Data . GetData ( ) , Data . Num ( ) ) ;
if ( Serialize ( MemoryReader ) )
{
return true ;
}
else
{
UE_LOG ( LogCookedMetadata , Error , TEXT ( " Failed to serialize cook metadata from file (%s) " ) , * FilePath ) ;
}
}
else
{
UE_LOG ( LogCookedMetadata , Error , TEXT ( " Failed to make file reader from (%s) " ) , * FilePath ) ;
}
return false ;
}
bool FCookMetadataState : : SaveToFile ( const FString & FilePath )
{
FArrayWriter SerializedCookMetadata ;
Serialize ( SerializedCookMetadata ) ;
if ( FFileHelper : : SaveArrayToFile ( SerializedCookMetadata , * FilePath ) )
{
return true ;
}
else
{
UE_LOG ( LogCookedMetadata , Error , TEXT ( " Failed to write cook metadata file (%s) " ) , * FilePath ) ;
return false ;
}
}
2023-06-19 13:59:07 -04:00
/* static */
uint64 FCookMetadataState : : ComputeHashOfDevelopmentAssetRegistry ( FMemoryView InSerializedDevelopmentAssetRegistry )
{
return FXxHash64 : : HashBufferChunked ( InSerializedDevelopmentAssetRegistry . GetData ( ) , InSerializedDevelopmentAssetRegistry . GetSize ( ) , 1ULL < < 19 ) . Hash ;
}
2023-06-26 17:21:53 -04:00
FText FCookMetadataState : : GetSizesPresentAsText ( ) const
{
// Uncapitalized, presentation-ready
static FText CookMetadataSizesPresentStrings [ ] =
{
NSLOCTEXT ( " CookMetadata " , " CookMetadataNotPresent " , " not present " ) ,
NSLOCTEXT ( " CookMetadata " , " CookMetadataCompressed " , " compressed " ) ,
NSLOCTEXT ( " CookMetadata " , " CookMetadataUncompressed " , " uncompressed " )
} ;
static_assert ( sizeof ( CookMetadataSizesPresentStrings ) / sizeof ( CookMetadataSizesPresentStrings [ 0 ] ) = = static_cast < size_t > ( ECookMetadataSizesPresent : : Count ) ) ;
return CookMetadataSizesPresentStrings [ static_cast < size_t > ( SizesPresent ) ] ;
}
2023-06-19 13:59:07 -04:00
2023-11-07 19:53:50 -05:00
FText FCookMetadataPluginEntry : : GetPluginTypeAsText ( ) const
{
// Uncapitalized, presentation-ready
static FText CookMetadataPluginEntryTypeStrings [ ] =
{
NSLOCTEXT ( " CookMetadataPluginEntryType " , " PluginTypeUnassigned " , " unknown " ) ,
NSLOCTEXT ( " CookMetadataPluginEntryType " , " PluginTypeNormal " , " normal " ) ,
NSLOCTEXT ( " CookMetadataPluginEntryType " , " PluginTypeRoot " , " root " ) ,
NSLOCTEXT ( " CookMetadataPluginEntryType " , " PluginTypeEnginePseudo " , " engine pseudoplugin " ) ,
NSLOCTEXT ( " CookMetadataPluginEntryType " , " PluginTypeGamePseudo " , " game pseudoplugin " ) ,
NSLOCTEXT ( " CookMetadataPluginEntryType " , " PluginTypeShaderPseudo " , " shader pseudoplugin " )
} ;
static_assert ( sizeof ( CookMetadataPluginEntryTypeStrings ) / sizeof ( CookMetadataPluginEntryTypeStrings [ 0 ] ) = = static_cast < size_t > ( ECookMetadataPluginType : : Count ) ) ;
return CookMetadataPluginEntryTypeStrings [ static_cast < size_t > ( Type ) ] ;
}
2023-06-19 13:59:07 -04:00
} // end namespace