2021-02-08 10:48:17 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "PackageStoreOptimizer.h"
# include "ProfilingDebugging/CountersTrace.h"
# include "Serialization/BufferWriter.h"
# include "Serialization/LargeMemoryWriter.h"
2021-06-15 16:38:03 -04:00
# include "Serialization/MemoryReader.h"
2021-02-08 10:48:17 -04:00
# include "UObject/NameBatchSerialization.h"
# include "Containers/Map.h"
# include "UObject/UObjectHash.h"
# include "Interfaces/ITargetPlatform.h"
# include "UObject/Object.h"
# include "Serialization/MemoryReader.h"
# include "UObject/Package.h"
2021-06-10 09:36:47 -04:00
# include "Misc/SecureHash.h"
2021-09-15 10:39:23 -04:00
# include "Serialization/LargeMemoryReader.h"
2021-02-08 10:48:17 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogPackageStoreOptimizer , Log , All ) ;
// modified copy from SavePackage
EObjectMark GetExcludedObjectMarksForTargetPlatform ( const ITargetPlatform * TargetPlatform )
{
2021-06-22 00:27:54 -04:00
EObjectMark Marks = OBJECTMARK_NotForTargetPlatform ;
if ( ! TargetPlatform - > AllowsEditorObjects ( ) )
2021-02-08 10:48:17 -04:00
{
Marks = ( EObjectMark ) ( Marks | OBJECTMARK_EditorOnly ) ;
}
if ( TargetPlatform - > IsServerOnly ( ) )
{
Marks = ( EObjectMark ) ( Marks | OBJECTMARK_NotForServer ) ;
}
if ( TargetPlatform - > IsClientOnly ( ) )
{
Marks = ( EObjectMark ) ( Marks | OBJECTMARK_NotForClient ) ;
}
return Marks ;
}
// modified copy from SavePackage
EObjectMark GetExcludedObjectMarksForObject ( const UObject * Object , const ITargetPlatform * TargetPlatform )
{
EObjectMark Marks = OBJECTMARK_NOMARKS ;
if ( ! Object - > NeedsLoadForClient ( ) )
{
Marks = ( EObjectMark ) ( Marks | OBJECTMARK_NotForClient ) ;
}
if ( ! Object - > NeedsLoadForServer ( ) )
{
Marks = ( EObjectMark ) ( Marks | OBJECTMARK_NotForServer ) ;
}
2021-06-22 00:27:54 -04:00
# if WITH_ENGINE
// NotForServer && NotForClient implies EditorOnly
const bool bIsEditorOnlyObject = ( Marks & OBJECTMARK_NotForServer ) & & ( Marks & OBJECTMARK_NotForClient ) ;
const bool bTargetAllowsEditorObjects = TargetPlatform - > AllowsEditorObjects ( ) ;
// no need to query the target platform if the object is editoronly and the targetplatform doesn't allow editor objects
const bool bCheckTargetPlatform = ! bIsEditorOnlyObject | | bTargetAllowsEditorObjects ;
if ( bCheckTargetPlatform & & ( ! Object - > NeedsLoadForTargetPlatform ( TargetPlatform ) | | ! TargetPlatform - > AllowObject ( Object ) ) )
2021-02-08 10:48:17 -04:00
{
2021-06-22 00:27:54 -04:00
Marks = ( EObjectMark ) ( Marks | OBJECTMARK_NotForTargetPlatform ) ;
2021-02-08 10:48:17 -04:00
}
2021-06-22 00:27:54 -04:00
# endif
2021-02-08 10:48:17 -04:00
if ( Object - > IsEditorOnly ( ) )
{
Marks = ( EObjectMark ) ( Marks | OBJECTMARK_EditorOnly ) ;
}
if ( ( Marks & OBJECTMARK_NotForClient ) & & ( Marks & OBJECTMARK_NotForServer ) )
{
Marks = ( EObjectMark ) ( Marks | OBJECTMARK_EditorOnly ) ;
}
return Marks ;
}
// modified copy from PakFileUtilities
static FString RemapLocalizationPathIfNeeded ( const FString & Path , FString * OutRegion )
{
static constexpr TCHAR L10NString [ ] = TEXT ( " /L10N/ " ) ;
static constexpr int32 L10NPrefixLength = sizeof ( L10NString ) / sizeof ( TCHAR ) - 1 ;
int32 BeginL10NOffset = Path . Find ( L10NString , ESearchCase : : IgnoreCase ) ;
if ( BeginL10NOffset > = 0 )
{
int32 EndL10NOffset = BeginL10NOffset + L10NPrefixLength ;
int32 NextSlashIndex = Path . Find ( TEXT ( " / " ) , ESearchCase : : IgnoreCase , ESearchDir : : FromStart , EndL10NOffset ) ;
int32 RegionLength = NextSlashIndex - EndL10NOffset ;
if ( RegionLength > = 2 )
{
FString NonLocalizedPath = Path . Mid ( 0 , BeginL10NOffset ) + Path . Mid ( NextSlashIndex ) ;
if ( OutRegion )
{
* OutRegion = Path . Mid ( EndL10NOffset , RegionLength ) ;
OutRegion - > ToLowerInline ( ) ;
}
return NonLocalizedPath ;
}
}
return Path ;
}
2021-10-12 21:21:22 -04:00
void FPackageStoreOptimizer : : Initialize ( )
2021-02-08 10:48:17 -04:00
{
2021-10-12 21:21:22 -04:00
FindScriptObjects ( ) ;
2021-02-08 10:48:17 -04:00
}
2021-09-15 10:39:23 -04:00
void FPackageStoreOptimizer : : Initialize ( const FIoBuffer & ScriptObjectsBuffer )
{
LoadScriptObjectsBuffer ( ScriptObjectsBuffer ) ;
}
2021-05-06 08:02:55 -04:00
FPackageStorePackage * FPackageStoreOptimizer : : CreateMissingPackage ( const FName & Name ) const
{
FPackageStorePackage * Package = new FPackageStorePackage ( ) ;
Package - > Name = Name ;
Package - > Id = FPackageId : : FromName ( Name ) ;
Package - > SourceName = * RemapLocalizationPathIfNeeded ( Name . ToString ( ) , & Package - > Region ) ;
return Package ;
}
2021-02-08 10:48:17 -04:00
FPackageStorePackage * FPackageStoreOptimizer : : CreatePackageFromCookedHeader ( const FName & Name , const FIoBuffer & CookedHeaderBuffer ) const
{
FPackageStorePackage * Package = new FPackageStorePackage ( ) ;
Package - > Id = FPackageId : : FromName ( Name ) ;
2022-04-25 07:37:07 -04:00
Package - > Name = Name ;
2022-01-18 13:01:31 -05:00
FString NameStr = Name . ToString ( ) ;
Package - > SourceName = * RemapLocalizationPathIfNeeded ( NameStr , & Package - > Region ) ;
2021-02-08 10:48:17 -04:00
2021-06-15 16:38:03 -04:00
FCookedHeaderData CookedHeaderData = LoadCookedHeader ( CookedHeaderBuffer ) ;
2021-10-12 21:21:22 -04:00
if ( ! CookedHeaderData . Summary . bUnversioned )
{
FZenPackageVersioningInfo & VersioningInfo = Package - > VersioningInfo . Emplace ( ) ;
VersioningInfo . ZenVersion = EZenPackageVersion : : Latest ;
VersioningInfo . PackageVersion = CookedHeaderData . Summary . GetFileVersionUE ( ) ;
VersioningInfo . LicenseeVersion = CookedHeaderData . Summary . GetFileVersionLicenseeUE ( ) ;
VersioningInfo . CustomVersions = CookedHeaderData . Summary . GetCustomVersionContainer ( ) ;
}
2021-06-15 16:38:03 -04:00
Package - > PackageFlags = CookedHeaderData . Summary . GetPackageFlags ( ) ;
Package - > CookedHeaderSize = CookedHeaderData . Summary . TotalHeaderSize ;
2021-09-30 02:05:41 -04:00
for ( int32 I = 0 ; I < CookedHeaderData . Summary . NamesReferencedFromExportDataCount ; + + I )
2021-06-15 16:38:03 -04:00
{
2021-09-30 02:05:41 -04:00
Package - > NameMapBuilder . AddName ( CookedHeaderData . SummaryNames [ I ] ) ;
2021-06-15 16:38:03 -04:00
}
2022-01-18 13:01:31 -05:00
TArray < FPackageStorePackage : : FUnresolvedImport > Imports ;
ProcessImports ( CookedHeaderData , Package , Imports ) ;
ProcessExports ( CookedHeaderData , Package , Imports . GetData ( ) ) ;
2021-06-15 16:38:03 -04:00
ProcessPreloadDependencies ( CookedHeaderData , Package ) ;
CreateExportBundles ( Package ) ;
2021-02-08 10:48:17 -04:00
return Package ;
}
2021-06-15 16:38:03 -04:00
FPackageStorePackage * FPackageStoreOptimizer : : CreatePackageFromPackageStoreHeader ( const FName & Name , const FIoBuffer & Buffer , const FPackageStoreEntryResource & PackageStoreEntry ) const
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
FPackageStorePackage * Package = new FPackageStorePackage ( ) ;
Package - > Id = FPackageId : : FromName ( Name ) ;
2022-01-18 13:01:31 -05:00
// The package id should be generated from the original name
// Support for optional package is not implemented when loading from the package store yet however
FString NameStr = Name . ToString ( ) ;
int32 Index = NameStr . Find ( FPackagePath : : GetOptionalSegmentExtensionModifier ( ) ) ;
if ( Index ! = INDEX_NONE )
{
unimplemented ( ) ;
}
Package - > Name = Name ;
Package - > SourceName = * RemapLocalizationPathIfNeeded ( NameStr , & Package - > Region ) ;
2021-06-15 16:38:03 -04:00
FPackageStoreHeaderData PackageStoreHeaderData = LoadPackageStoreHeader ( Buffer , PackageStoreEntry ) ;
2021-10-12 21:21:22 -04:00
if ( PackageStoreHeaderData . VersioningInfo . IsSet ( ) )
{
Package - > VersioningInfo . Emplace ( PackageStoreHeaderData . VersioningInfo . GetValue ( ) ) ;
}
2021-06-15 16:38:03 -04:00
Package - > PackageFlags = PackageStoreHeaderData . Summary . PackageFlags ;
Package - > CookedHeaderSize = PackageStoreHeaderData . Summary . CookedHeaderSize ;
2022-04-25 03:48:33 -04:00
for ( FDisplayNameEntryId DisplayId : PackageStoreHeaderData . NameMap )
2021-06-15 16:38:03 -04:00
{
2022-04-25 03:48:33 -04:00
Package - > NameMapBuilder . AddName ( DisplayId ) ;
2021-06-15 16:38:03 -04:00
}
ProcessImports ( PackageStoreHeaderData , Package ) ;
ProcessExports ( PackageStoreHeaderData , Package ) ;
ProcessPreloadDependencies ( PackageStoreHeaderData , Package ) ;
CreateExportBundles ( Package ) ;
return Package ;
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
FPackageStoreOptimizer : : FCookedHeaderData FPackageStoreOptimizer : : LoadCookedHeader ( const FIoBuffer & CookedHeaderBuffer ) const
{
FCookedHeaderData CookedHeaderData ;
2021-02-08 10:48:17 -04:00
TArrayView < const uint8 > MemView ( CookedHeaderBuffer . Data ( ) , CookedHeaderBuffer . DataSize ( ) ) ;
FMemoryReaderView Ar ( MemView ) ;
2021-06-15 16:38:03 -04:00
FPackageFileSummary & Summary = CookedHeaderData . Summary ;
2021-02-08 10:48:17 -04:00
{
TGuardValue < int32 > GuardAllowUnversionedContentInEditor ( GAllowUnversionedContentInEditor , 1 ) ;
2021-06-15 16:38:03 -04:00
Ar < < Summary ;
2021-02-08 10:48:17 -04:00
}
2021-06-15 16:38:03 -04:00
Ar . SetFilterEditorOnly ( ( CookedHeaderData . Summary . GetPackageFlags ( ) & EPackageFlags : : PKG_FilterEditorOnly ) ! = 0 ) ;
2021-02-08 10:48:17 -04:00
2021-06-15 16:38:03 -04:00
if ( Summary . NameCount > 0 )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
Ar . Seek ( Summary . NameOffset ) ;
2021-02-08 10:48:17 -04:00
FNameEntrySerialized NameEntry ( ENAME_LinkerConstructor ) ;
2021-12-16 18:22:15 -05:00
CookedHeaderData . SummaryNames . Reserve ( Summary . NameCount ) ;
2021-06-15 16:38:03 -04:00
for ( int32 I = 0 ; I < Summary . NameCount ; + + I )
2021-02-08 10:48:17 -04:00
{
Ar < < NameEntry ;
2021-06-15 16:38:03 -04:00
CookedHeaderData . SummaryNames . Add ( NameEntry ) ;
2021-02-08 10:48:17 -04:00
}
}
class FNameReaderProxyArchive
: public FArchiveProxy
{
public :
using FArchiveProxy : : FArchiveProxy ;
2021-06-15 16:38:03 -04:00
FNameReaderProxyArchive ( FArchive & InAr , const TArray < FName > & InNameMap )
2021-02-08 10:48:17 -04:00
: FArchiveProxy ( InAr )
, NameMap ( InNameMap )
{
// Replicate the filter editor only state of the InnerArchive as FArchiveProxy will
// not intercept it.
FArchive : : SetFilterEditorOnly ( InAr . IsFilterEditorOnly ( ) ) ;
}
FArchive & operator < < ( FName & Name )
{
2021-02-09 15:11:26 -04:00
int32 NameIndex = 0 ;
int32 Number = 0 ;
2021-02-08 10:48:17 -04:00
InnerArchive < < NameIndex < < Number ;
if ( ! NameMap . IsValidIndex ( NameIndex ) )
{
UE_LOG ( LogPackageStoreOptimizer , Fatal , TEXT ( " Bad name index %i/%i " ) , NameIndex , NameMap . Num ( ) ) ;
}
2021-06-15 16:38:03 -04:00
const FName & MappedName = NameMap [ NameIndex ] ;
Name = FName : : CreateFromDisplayId ( MappedName . GetDisplayIndex ( ) , Number ) ;
2021-02-08 10:48:17 -04:00
return * this ;
}
private :
2021-06-15 16:38:03 -04:00
const TArray < FName > & NameMap ;
2021-02-08 10:48:17 -04:00
} ;
2021-06-15 16:38:03 -04:00
FNameReaderProxyArchive ProxyAr ( Ar , CookedHeaderData . SummaryNames ) ;
2021-02-08 10:48:17 -04:00
2021-06-15 16:38:03 -04:00
if ( Summary . ImportCount > 0 )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
CookedHeaderData . ObjectImports . Reserve ( Summary . ImportCount ) ;
ProxyAr . Seek ( Summary . ImportOffset ) ;
for ( int32 I = 0 ; I < Summary . ImportCount ; + + I )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
ProxyAr < < CookedHeaderData . ObjectImports . AddDefaulted_GetRef ( ) ;
2021-02-08 10:48:17 -04:00
}
}
2021-06-15 16:38:03 -04:00
if ( Summary . PreloadDependencyCount > 0 )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
CookedHeaderData . PreloadDependencies . Reserve ( Summary . PreloadDependencyCount ) ;
ProxyAr . Seek ( Summary . PreloadDependencyOffset ) ;
for ( int32 I = 0 ; I < Summary . PreloadDependencyCount ; + + I )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
ProxyAr < < CookedHeaderData . PreloadDependencies . AddDefaulted_GetRef ( ) ;
2021-02-08 10:48:17 -04:00
}
}
2021-06-15 16:38:03 -04:00
if ( Summary . ExportCount > 0 )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
CookedHeaderData . ObjectExports . Reserve ( Summary . ExportCount ) ;
ProxyAr . Seek ( Summary . ExportOffset ) ;
for ( int32 I = 0 ; I < Summary . ExportCount ; + + I )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
FObjectExport & ObjectExport = CookedHeaderData . ObjectExports . AddDefaulted_GetRef ( ) ;
2021-02-08 10:48:17 -04:00
ProxyAr < < ObjectExport ;
}
}
2021-06-15 16:38:03 -04:00
return CookedHeaderData ;
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
FPackageStoreOptimizer : : FPackageStoreHeaderData FPackageStoreOptimizer : : LoadPackageStoreHeader ( const FIoBuffer & PackageStoreHeaderBuffer , const FPackageStoreEntryResource & PackageStoreEntry ) const
{
FPackageStoreHeaderData PackageStoreHeaderData ;
const uint8 * HeaderData = PackageStoreHeaderBuffer . Data ( ) ;
2021-10-12 21:21:22 -04:00
FZenPackageSummary & Summary = PackageStoreHeaderData . Summary ;
Summary = * reinterpret_cast < const FZenPackageSummary * > ( HeaderData ) ;
2021-06-15 16:38:03 -04:00
check ( PackageStoreHeaderBuffer . DataSize ( ) = = Summary . HeaderSize ) ;
2021-10-12 21:21:22 -04:00
TArrayView < const uint8 > HeaderDataView ( HeaderData + sizeof ( FZenPackageSummary ) , Summary . HeaderSize - sizeof ( FZenPackageSummary ) ) ;
FMemoryReaderView HeaderDataReader ( HeaderDataView ) ;
if ( Summary . bHasVersioningInfo )
{
FZenPackageVersioningInfo & VersioningInfo = PackageStoreHeaderData . VersioningInfo . Emplace ( ) ;
HeaderDataReader < < VersioningInfo ;
}
2022-04-25 03:48:33 -04:00
TArray < FDisplayNameEntryId > & NameMap = PackageStoreHeaderData . NameMap ;
2021-10-12 21:21:22 -04:00
NameMap = LoadNameBatch ( HeaderDataReader ) ;
2021-06-15 16:38:03 -04:00
for ( FPackageId PackageId : PackageStoreEntry . ImportedPackageIds )
{
PackageStoreHeaderData . ImportedPackageIds . Add ( PackageId ) ;
}
2021-11-18 14:37:34 -05:00
PackageStoreHeaderData . ImportedPublicExportHashes =
MakeArrayView < const uint64 > (
reinterpret_cast < const uint64 * > ( HeaderData + Summary . ImportedPublicExportHashesOffset ) ,
( Summary . ImportMapOffset - Summary . ImportedPublicExportHashesOffset ) / sizeof ( uint64 ) ) ;
2021-06-15 16:38:03 -04:00
PackageStoreHeaderData . Imports =
MakeArrayView < const FPackageObjectIndex > (
reinterpret_cast < const FPackageObjectIndex * > ( HeaderData + Summary . ImportMapOffset ) ,
( Summary . ExportMapOffset - Summary . ImportMapOffset ) / sizeof ( FPackageObjectIndex ) ) ;
PackageStoreHeaderData . Exports =
MakeArrayView < const FExportMapEntry > (
reinterpret_cast < const FExportMapEntry * > ( HeaderData + Summary . ExportMapOffset ) ,
( Summary . ExportBundleEntriesOffset - Summary . ExportMapOffset ) / sizeof ( FExportMapEntry ) ) ;
PackageStoreHeaderData . ExportBundleHeaders =
MakeArrayView < const FExportBundleHeader > (
reinterpret_cast < const FExportBundleHeader * > ( HeaderData + Summary . GraphDataOffset ) ,
PackageStoreEntry . ExportInfo . ExportBundleCount ) ;
PackageStoreHeaderData . ExportBundleEntries =
MakeArrayView < const FExportBundleEntry > (
reinterpret_cast < const FExportBundleEntry * > ( HeaderData + Summary . ExportBundleEntriesOffset ) ,
PackageStoreEntry . ExportInfo . ExportCount * FExportBundleEntry : : ExportCommandType_Count ) ;
const uint64 ExportBundleHeadersSize = sizeof ( FExportBundleHeader ) * PackageStoreEntry . ExportInfo . ExportBundleCount ;
const uint64 ArcsDataOffset = Summary . GraphDataOffset + ExportBundleHeadersSize ;
const uint64 ArcsDataSize = Summary . HeaderSize - ArcsDataOffset ;
FMemoryReaderView ArcsAr ( MakeArrayView < const uint8 > ( HeaderData + ArcsDataOffset , ArcsDataSize ) ) ;
int32 InternalArcsCount = 0 ;
ArcsAr < < InternalArcsCount ;
for ( int32 Idx = 0 ; Idx < InternalArcsCount ; + + Idx )
{
FPackageStorePackage : : FInternalArc & InternalArc = PackageStoreHeaderData . InternalArcs . AddDefaulted_GetRef ( ) ;
ArcsAr < < InternalArc . FromExportBundleIndex ;
ArcsAr < < InternalArc . ToExportBundleIndex ;
}
for ( FPackageId ImportedPackageId : PackageStoreHeaderData . ImportedPackageIds )
{
int32 ExternalArcsCount = 0 ;
ArcsAr < < ExternalArcsCount ;
for ( int32 Idx = 0 ; Idx < ExternalArcsCount ; + + Idx )
{
FPackageStorePackage : : FExternalArc ExternalArc ;
ArcsAr < < ExternalArc . FromImportIndex ;
uint8 FromCommandType = 0 ;
ArcsAr < < FromCommandType ;
ExternalArc . FromCommandType = static_cast < FExportBundleEntry : : EExportCommandType > ( FromCommandType ) ;
ArcsAr < < ExternalArc . ToExportBundleIndex ;
PackageStoreHeaderData . ExternalArcs . Add ( ExternalArc ) ;
}
}
return PackageStoreHeaderData ;
2021-02-08 10:48:17 -04:00
}
2021-08-02 07:21:44 -04:00
void FPackageStoreOptimizer : : ResolveImport ( FPackageStorePackage : : FUnresolvedImport * Imports , const FObjectImport * ObjectImports , int32 LocalImportIndex ) const
2021-02-08 10:48:17 -04:00
{
2021-08-02 07:21:44 -04:00
FPackageStorePackage : : FUnresolvedImport * Import = Imports + LocalImportIndex ;
2021-02-08 10:48:17 -04:00
if ( Import - > FullName . Len ( ) = = 0 )
{
Import - > FullName . Reserve ( 256 ) ;
const FObjectImport * ObjectImport = ObjectImports + LocalImportIndex ;
if ( ObjectImport - > OuterIndex . IsNull ( ) )
{
FName PackageName = ObjectImport - > ObjectName ;
PackageName . AppendString ( Import - > FullName ) ;
Import - > FullName . ToLowerInline ( ) ;
2021-08-02 07:21:44 -04:00
Import - > FromPackageId = FPackageId : : FromName ( PackageName ) ;
Import - > FromPackageName = PackageName ;
Import - > FromPackageNameLen = Import - > FullName . Len ( ) ;
2021-02-08 10:48:17 -04:00
Import - > bIsScriptImport = Import - > FullName . StartsWith ( TEXT ( " /Script/ " ) ) ;
2021-08-02 07:21:44 -04:00
Import - > bIsImportOfPackage = true ;
2021-02-08 10:48:17 -04:00
}
else
{
const int32 OuterIndex = ObjectImport - > OuterIndex . ToImport ( ) ;
ResolveImport ( Imports , ObjectImports , OuterIndex ) ;
2021-08-02 07:21:44 -04:00
FPackageStorePackage : : FUnresolvedImport * OuterImport = Imports + OuterIndex ;
2021-02-08 10:48:17 -04:00
check ( OuterImport - > FullName . Len ( ) > 0 ) ;
Import - > bIsScriptImport = OuterImport - > bIsScriptImport ;
Import - > FullName . Append ( OuterImport - > FullName ) ;
Import - > FullName . AppendChar ( TEXT ( ' / ' ) ) ;
ObjectImport - > ObjectName . AppendString ( Import - > FullName ) ;
Import - > FullName . ToLowerInline ( ) ;
2021-08-02 07:21:44 -04:00
Import - > FromPackageId = OuterImport - > FromPackageId ;
2022-01-18 13:01:31 -05:00
Import - > bIsImportOptional = ObjectImport - > bImportOptional ;
2021-08-02 07:21:44 -04:00
Import - > FromPackageName = OuterImport - > FromPackageName ;
Import - > FromPackageNameLen = OuterImport - > FromPackageNameLen ;
2021-02-08 10:48:17 -04:00
}
}
}
2021-11-18 14:37:34 -05:00
uint64 FPackageStoreOptimizer : : GetPublicExportHash ( FStringView PackageRelativeExportPath )
{
check ( PackageRelativeExportPath . Len ( ) > 1 ) ;
check ( PackageRelativeExportPath [ 0 ] = = ' / ' ) ;
return CityHash64 ( reinterpret_cast < const char * > ( PackageRelativeExportPath . GetData ( ) + 1 ) , ( PackageRelativeExportPath . Len ( ) - 1 ) * sizeof ( TCHAR ) ) ;
}
2022-01-18 13:01:31 -05:00
void FPackageStoreOptimizer : : ProcessImports ( const FCookedHeaderData & CookedHeaderData , FPackageStorePackage * Package , TArray < FPackageStorePackage : : FUnresolvedImport > & UnresolvedImports ) const
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
int32 ImportCount = CookedHeaderData . ObjectImports . Num ( ) ;
2021-08-02 07:21:44 -04:00
UnresolvedImports . SetNum ( ImportCount ) ;
2021-02-08 10:48:17 -04:00
Package - > Imports . SetNum ( ImportCount ) ;
2021-06-15 16:38:03 -04:00
TSet < FPackageId > ImportedPackageIds ;
2021-02-08 10:48:17 -04:00
for ( int32 ImportIndex = 0 ; ImportIndex < ImportCount ; + + ImportIndex )
{
2021-08-02 07:21:44 -04:00
ResolveImport ( UnresolvedImports . GetData ( ) , CookedHeaderData . ObjectImports . GetData ( ) , ImportIndex ) ;
FPackageStorePackage : : FUnresolvedImport & UnresolvedImport = UnresolvedImports [ ImportIndex ] ;
2022-01-18 13:01:31 -05:00
if ( ! UnresolvedImport . bIsScriptImport )
2021-02-08 10:48:17 -04:00
{
2022-01-18 13:01:31 -05:00
if ( UnresolvedImport . bIsImportOfPackage )
{
ImportedPackageIds . Add ( UnresolvedImport . FromPackageId ) ;
}
2021-02-08 10:48:17 -04:00
}
}
2021-06-15 16:38:03 -04:00
Package - > ImportedPackageIds = ImportedPackageIds . Array ( ) ;
Algo : : Sort ( Package - > ImportedPackageIds ) ;
2021-08-02 07:21:44 -04:00
for ( int32 ImportIndex = 0 ; ImportIndex < ImportCount ; + + ImportIndex )
{
FPackageStorePackage : : FUnresolvedImport & UnresolvedImport = UnresolvedImports [ ImportIndex ] ;
if ( UnresolvedImport . bIsScriptImport )
{
2021-09-15 10:39:23 -04:00
FPackageObjectIndex ScriptObjectIndex = FPackageObjectIndex : : FromScriptPath ( UnresolvedImport . FullName ) ;
if ( ! ScriptObjectsMap . Contains ( ScriptObjectIndex ) )
{
UE_LOG ( LogPackageStoreOptimizer , Warning , TEXT ( " Package '%s' is referencing missing script import '%s' " ) , * Package - > Name . ToString ( ) , * UnresolvedImport . FullName ) ;
}
2021-12-16 18:22:15 -05:00
Package - > Imports [ ImportIndex ] = ScriptObjectIndex ;
2021-08-02 07:21:44 -04:00
}
else if ( ! UnresolvedImport . bIsImportOfPackage )
{
bool bFoundPackageIndex = false ;
for ( uint32 PackageIndex = 0 , PackageCount = static_cast < uint32 > ( Package - > ImportedPackageIds . Num ( ) ) ; PackageIndex < PackageCount ; + + PackageIndex )
{
2022-04-25 07:37:07 -04:00
FPackageId FromPackageId = UnresolvedImport . FromPackageId ;
2022-01-18 13:01:31 -05:00
if ( FromPackageId = = Package - > ImportedPackageIds [ PackageIndex ] )
2021-08-02 07:21:44 -04:00
{
FStringView PackageRelativeName = FStringView ( UnresolvedImport . FullName ) . RightChop ( UnresolvedImport . FromPackageNameLen ) ;
check ( PackageRelativeName . Len ( ) ) ;
2021-11-18 14:37:34 -05:00
FPackageImportReference PackageImportRef ( PackageIndex , Package - > ImportedPublicExportHashes . Num ( ) ) ;
2021-08-02 07:21:44 -04:00
Package - > Imports [ ImportIndex ] = FPackageObjectIndex : : FromPackageImportRef ( PackageImportRef ) ;
2021-11-18 14:37:34 -05:00
uint64 ExportHash = GetPublicExportHash ( PackageRelativeName ) ;
Package - > ImportedPublicExportHashes . Add ( ExportHash ) ;
2021-08-02 07:21:44 -04:00
bFoundPackageIndex = true ;
break ;
}
}
check ( bFoundPackageIndex ) ;
}
}
2021-06-15 16:38:03 -04:00
}
void FPackageStoreOptimizer : : ProcessImports ( const FPackageStoreHeaderData & PackageStoreHeaderData , FPackageStorePackage * Package ) const
{
Package - > ImportedPackageIds = PackageStoreHeaderData . ImportedPackageIds ;
2021-11-18 14:37:34 -05:00
Package - > ImportedPublicExportHashes = PackageStoreHeaderData . ImportedPublicExportHashes ;
2021-08-02 07:21:44 -04:00
Package - > Imports = PackageStoreHeaderData . Imports ;
2021-02-08 10:48:17 -04:00
}
void FPackageStoreOptimizer : : ResolveExport (
FPackageStorePackage : : FExport * Exports ,
const FObjectExport * ObjectExports ,
const int32 LocalExportIndex ,
2022-01-18 13:01:31 -05:00
const FName & PackageName ,
FPackageStorePackage : : FUnresolvedImport * Imports ,
const FObjectImport * ObjectImports ) const
2021-02-08 10:48:17 -04:00
{
FPackageStorePackage : : FExport * Export = Exports + LocalExportIndex ;
if ( Export - > FullName . Len ( ) = = 0 )
{
Export - > FullName . Reserve ( 256 ) ;
const FObjectExport * ObjectExport = ObjectExports + LocalExportIndex ;
if ( ObjectExport - > OuterIndex . IsNull ( ) )
{
PackageName . AppendString ( Export - > FullName ) ;
Export - > FullName . AppendChar ( TEXT ( ' / ' ) ) ;
ObjectExport - > ObjectName . AppendString ( Export - > FullName ) ;
Export - > FullName . ToLowerInline ( ) ;
check ( Export - > FullName . Len ( ) > 0 ) ;
}
else
{
2022-01-18 13:01:31 -05:00
FString * OuterName = nullptr ;
if ( ObjectExport - > OuterIndex . IsExport ( ) )
{
int32 OuterExportIndex = ObjectExport - > OuterIndex . ToExport ( ) ;
2022-05-18 12:56:12 -04:00
ResolveExport ( Exports , ObjectExports , OuterExportIndex , PackageName , Imports , ObjectImports ) ;
2022-01-18 13:01:31 -05:00
OuterName = & Exports [ OuterExportIndex ] . FullName ;
}
else
{
check ( Imports & & ObjectImports ) ;
int32 OuterImportIndex = ObjectExport - > OuterIndex . ToImport ( ) ;
ResolveImport ( Imports , ObjectImports , OuterImportIndex ) ;
OuterName = & Imports [ OuterImportIndex ] . FullName ;
2021-02-08 10:48:17 -04:00
2022-01-18 13:01:31 -05:00
}
check ( OuterName & & OuterName - > Len ( ) > 0 ) ;
Export - > FullName . Append ( * OuterName ) ;
2021-02-08 10:48:17 -04:00
Export - > FullName . AppendChar ( TEXT ( ' / ' ) ) ;
ObjectExport - > ObjectName . AppendString ( Export - > FullName ) ;
Export - > FullName . ToLowerInline ( ) ;
}
}
}
2021-06-15 16:38:03 -04:00
void FPackageStoreOptimizer : : ResolveExport ( FPackageStorePackage : : FExport * Exports , const int32 LocalExportIndex , const FName & PackageName ) const
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
FPackageStorePackage : : FExport * Export = Exports + LocalExportIndex ;
if ( Export - > FullName . Len ( ) = = 0 )
{
Export - > FullName . Reserve ( 256 ) ;
if ( Export - > OuterIndex . IsNull ( ) )
{
PackageName . AppendString ( Export - > FullName ) ;
Export - > FullName . AppendChar ( TEXT ( ' / ' ) ) ;
Export - > ObjectName . AppendString ( Export - > FullName ) ;
Export - > FullName . ToLowerInline ( ) ;
check ( Export - > FullName . Len ( ) > 0 ) ;
}
else
{
check ( Export - > OuterIndex . IsExport ( ) ) ;
int32 OuterExportIndex = Export - > OuterIndex . ToExport ( ) ;
ResolveExport ( Exports , OuterExportIndex , PackageName ) ;
FString & OuterName = Exports [ OuterExportIndex ] . FullName ;
check ( OuterName . Len ( ) > 0 ) ;
Export - > FullName . Append ( OuterName ) ;
Export - > FullName . AppendChar ( TEXT ( ' / ' ) ) ;
Export - > ObjectName . AppendString ( Export - > FullName ) ;
Export - > FullName . ToLowerInline ( ) ;
}
}
}
2022-01-18 13:01:31 -05:00
void FPackageStoreOptimizer : : ProcessExports ( const FCookedHeaderData & CookedHeaderData , FPackageStorePackage * Package , FPackageStorePackage : : FUnresolvedImport * Imports ) const
2021-06-15 16:38:03 -04:00
{
int32 ExportCount = CookedHeaderData . ObjectExports . Num ( ) ;
2021-02-08 10:48:17 -04:00
Package - > Exports . SetNum ( ExportCount ) ;
Package - > ExportGraphNodes . Reserve ( ExportCount * 2 ) ;
auto PackageObjectIdFromPackageIndex =
2021-08-02 07:21:44 -04:00
[ ] ( const TArray < FPackageObjectIndex > & Imports , const FPackageIndex & PackageIndex ) - > FPackageObjectIndex
2021-02-08 10:48:17 -04:00
{
if ( PackageIndex . IsImport ( ) )
{
2021-08-02 07:21:44 -04:00
return Imports [ PackageIndex . ToImport ( ) ] ;
2021-02-08 10:48:17 -04:00
}
if ( PackageIndex . IsExport ( ) )
{
return FPackageObjectIndex : : FromExportIndex ( PackageIndex . ToExport ( ) ) ;
}
return FPackageObjectIndex ( ) ;
} ;
2021-08-02 07:21:44 -04:00
FString PackageNameStr = Package - > Name . ToString ( ) ;
2021-11-18 14:37:34 -05:00
TMap < uint64 , const FPackageStorePackage : : FExport * > SeenPublicExportHashes ;
2021-02-08 10:48:17 -04:00
for ( int32 ExportIndex = 0 ; ExportIndex < ExportCount ; + + ExportIndex )
{
2021-06-15 16:38:03 -04:00
const FObjectExport & ObjectExport = CookedHeaderData . ObjectExports [ ExportIndex ] ;
Package - > ExportsSerialSize + = ObjectExport . SerialSize ;
2021-02-08 10:48:17 -04:00
FPackageStorePackage : : FExport & Export = Package - > Exports [ ExportIndex ] ;
Export . ObjectName = ObjectExport . ObjectName ;
Export . ObjectFlags = ObjectExport . ObjectFlags ;
Export . CookedSerialOffset = ObjectExport . SerialOffset ;
2021-06-15 16:38:03 -04:00
Export . SerialOffset = ObjectExport . SerialOffset - CookedHeaderData . Summary . TotalHeaderSize ;
Export . SerialSize = ObjectExport . SerialSize ;
2021-02-08 10:48:17 -04:00
Export . bNotForClient = ObjectExport . bNotForClient ;
Export . bNotForServer = ObjectExport . bNotForServer ;
2022-01-18 13:01:31 -05:00
Export . bIsPublic = ( Export . ObjectFlags & RF_Public ) > 0 | | ObjectExport . bGeneratePublicHash ;
ResolveExport ( Package - > Exports . GetData ( ) , CookedHeaderData . ObjectExports . GetData ( ) , ExportIndex , Package - > Name , Imports , CookedHeaderData . ObjectImports . GetData ( ) ) ;
2021-02-08 10:48:17 -04:00
if ( Export . bIsPublic )
{
check ( Export . FullName . Len ( ) > 0 ) ;
2021-08-02 07:21:44 -04:00
FStringView PackageRelativeName = FStringView ( Export . FullName ) . RightChop ( PackageNameStr . Len ( ) ) ;
check ( PackageRelativeName . Len ( ) ) ;
2021-11-18 14:37:34 -05:00
Export . PublicExportHash = GetPublicExportHash ( PackageRelativeName ) ;
const FPackageStorePackage : : FExport * FindCollidingExport = SeenPublicExportHashes . FindRef ( Export . PublicExportHash ) ;
if ( FindCollidingExport )
{
UE_LOG ( LogPackageStoreOptimizer , Fatal , TEXT ( " Export hash collision in package \" %s \" : \" %s \" and \" %s " ) , * PackageNameStr , PackageRelativeName . GetData ( ) , * FindCollidingExport - > FullName . RightChop ( PackageNameStr . Len ( ) ) ) ;
}
SeenPublicExportHashes . Add ( Export . PublicExportHash , & Export ) ;
2021-02-08 10:48:17 -04:00
}
Export . OuterIndex = PackageObjectIdFromPackageIndex ( Package - > Imports , ObjectExport . OuterIndex ) ;
Export . ClassIndex = PackageObjectIdFromPackageIndex ( Package - > Imports , ObjectExport . ClassIndex ) ;
Export . SuperIndex = PackageObjectIdFromPackageIndex ( Package - > Imports , ObjectExport . SuperIndex ) ;
Export . TemplateIndex = PackageObjectIdFromPackageIndex ( Package - > Imports , ObjectExport . TemplateIndex ) ;
2021-06-15 16:38:03 -04:00
for ( uint8 CommandType = 0 ; CommandType < FExportBundleEntry : : ExportCommandType_Count ; + + CommandType )
{
FPackageStorePackage : : FExportGraphNode & Node = Package - > ExportGraphNodes . AddDefaulted_GetRef ( ) ;
Node . BundleEntry . CommandType = FExportBundleEntry : : EExportCommandType ( CommandType ) ;
Node . BundleEntry . LocalExportIndex = ExportIndex ;
Node . bIsPublic = Export . bIsPublic ;
Export . Nodes [ CommandType ] = & Node ;
}
2021-02-08 10:48:17 -04:00
}
}
2021-06-15 16:38:03 -04:00
void FPackageStoreOptimizer : : ProcessExports ( const FPackageStoreHeaderData & PackageStoreHeaderData , FPackageStorePackage * Package ) const
{
const int32 ExportCount = PackageStoreHeaderData . Exports . Num ( ) ;
Package - > Exports . SetNum ( ExportCount ) ;
Package - > ExportGraphNodes . Reserve ( ExportCount * 2 ) ;
2022-04-25 03:48:33 -04:00
const TArray < FDisplayNameEntryId > & NameMap = PackageStoreHeaderData . NameMap ;
2021-06-15 16:38:03 -04:00
2021-11-18 14:37:34 -05:00
Package - > ImportedPublicExportHashes = PackageStoreHeaderData . ImportedPublicExportHashes ;
2021-06-15 16:38:03 -04:00
for ( int32 ExportIndex = 0 ; ExportIndex < ExportCount ; + + ExportIndex )
{
const FExportMapEntry & ExportEntry = PackageStoreHeaderData . Exports [ ExportIndex ] ;
Package - > ExportsSerialSize + = ExportEntry . CookedSerialSize ;
FPackageStorePackage : : FExport & Export = Package - > Exports [ ExportIndex ] ;
2022-04-25 03:48:33 -04:00
Export . ObjectName = ExportEntry . ObjectName . ResolveName ( NameMap ) ;
2021-11-18 14:37:34 -05:00
Export . PublicExportHash = ExportEntry . PublicExportHash ;
2021-06-15 16:38:03 -04:00
Export . OuterIndex = ExportEntry . OuterIndex ;
Export . ClassIndex = ExportEntry . ClassIndex ;
Export . SuperIndex = ExportEntry . SuperIndex ;
Export . TemplateIndex = ExportEntry . TemplateIndex ;
Export . ObjectFlags = ExportEntry . ObjectFlags ;
Export . CookedSerialOffset = ExportEntry . CookedSerialOffset ;
Export . SerialSize = ExportEntry . CookedSerialSize ;
Export . bNotForClient = ExportEntry . FilterFlags = = EExportFilterFlags : : NotForClient ;
Export . bNotForServer = ExportEntry . FilterFlags = = EExportFilterFlags : : NotForServer ;
Export . bIsPublic = ( ExportEntry . ObjectFlags & RF_Public ) > 0 ;
for ( uint8 CommandType = 0 ; CommandType < FExportBundleEntry : : ExportCommandType_Count ; + + CommandType )
{
FPackageStorePackage : : FExportGraphNode & Node = Package - > ExportGraphNodes . AddDefaulted_GetRef ( ) ;
Node . BundleEntry . CommandType = FExportBundleEntry : : EExportCommandType ( CommandType ) ;
Node . BundleEntry . LocalExportIndex = ExportIndex ;
Node . bIsPublic = Export . bIsPublic ;
Export . Nodes [ CommandType ] = & Node ;
}
Package - > NameMapBuilder . MarkNameAsReferenced ( Export . ObjectName ) ;
}
for ( int32 ExportIndex = 0 ; ExportIndex < ExportCount ; + + ExportIndex )
{
ResolveExport ( Package - > Exports . GetData ( ) , ExportIndex , Package - > Name ) ;
}
uint64 ExportSerialOffset = 0 ;
for ( const FExportBundleHeader & ExportBundleHeader : PackageStoreHeaderData . ExportBundleHeaders )
{
int32 ExportEntryIndex = ExportBundleHeader . FirstEntryIndex ;
for ( uint32 Idx = 0 ; Idx < ExportBundleHeader . EntryCount ; + + Idx )
{
const FExportBundleEntry & BundleEntry = PackageStoreHeaderData . ExportBundleEntries [ ExportEntryIndex + + ] ;
if ( BundleEntry . CommandType = = FExportBundleEntry : : ExportCommandType_Serialize )
{
FPackageStorePackage : : FExport & Export = Package - > Exports [ BundleEntry . LocalExportIndex ] ;
Export . SerialOffset = ExportSerialOffset ;
ExportSerialOffset + = Export . SerialSize ;
}
}
}
check ( ExportSerialOffset = = Package - > ExportsSerialSize ) ;
}
TArray < FPackageStorePackage * > FPackageStoreOptimizer : : SortPackagesInLoadOrder ( const TMap < FPackageId , FPackageStorePackage * > & PackagesMap ) const
2021-02-08 10:48:17 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( SortPackagesInLoadOrder ) ;
2021-06-15 16:38:03 -04:00
TArray < FPackageStorePackage * > Packages ;
PackagesMap . GenerateValueArray ( Packages ) ;
2021-02-08 10:48:17 -04:00
Algo : : Sort ( Packages , [ ] ( const FPackageStorePackage * A , const FPackageStorePackage * B )
{
return A - > Id < B - > Id ;
} ) ;
TMap < FPackageStorePackage * , TArray < FPackageStorePackage * > > SortedEdges ;
for ( FPackageStorePackage * Package : Packages )
{
2021-06-15 16:38:03 -04:00
for ( FPackageId ImportedPackageId : Package - > ImportedPackageIds )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
FPackageStorePackage * FindImportedPackage = PackagesMap . FindRef ( ImportedPackageId ) ;
if ( FindImportedPackage )
{
TArray < FPackageStorePackage * > & SourceArray = SortedEdges . FindOrAdd ( FindImportedPackage ) ;
SourceArray . Add ( Package ) ;
}
2021-02-08 10:48:17 -04:00
}
}
for ( auto & KV : SortedEdges )
{
TArray < FPackageStorePackage * > & SourceArray = KV . Value ;
Algo : : Sort ( SourceArray , [ ] ( const FPackageStorePackage * A , const FPackageStorePackage * B )
{
return A - > Id < B - > Id ;
} ) ;
}
TArray < FPackageStorePackage * > Result ;
Result . Reserve ( Packages . Num ( ) ) ;
struct
{
void Visit ( FPackageStorePackage * Package )
{
if ( Package - > bPermanentMark | | Package - > bTemporaryMark )
{
return ;
}
Package - > bTemporaryMark = true ;
TArray < FPackageStorePackage * > * TargetNodes = Edges . Find ( Package ) ;
if ( TargetNodes )
{
for ( FPackageStorePackage * ToNode : * TargetNodes )
{
Visit ( ToNode ) ;
}
}
Package - > bTemporaryMark = false ;
Package - > bPermanentMark = true ;
Result . Add ( Package ) ;
}
TMap < FPackageStorePackage * , TArray < FPackageStorePackage * > > & Edges ;
TArray < FPackageStorePackage * > & Result ;
} Visitor { SortedEdges , Result } ;
for ( FPackageStorePackage * Package : Packages )
{
Visitor . Visit ( Package ) ;
}
check ( Result . Num ( ) = = Packages . Num ( ) ) ;
Algo : : Reverse ( Result ) ;
Swap ( Result , Packages ) ;
2021-06-15 16:38:03 -04:00
return Packages ;
2021-02-08 10:48:17 -04:00
}
2021-06-15 16:38:03 -04:00
TArray < FPackageStorePackage : : FExportBundleGraphNode * > FPackageStoreOptimizer : : SortExportBundleGraphNodesInLoadOrder ( const TArray < FPackageStorePackage * > & Packages , FExportBundleGraphEdges & Edges ) const
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( SortExportBundleGraphNodesInLoadOrder ) ;
2021-02-08 10:48:17 -04:00
int32 NodeCount = 0 ;
for ( FPackageStorePackage * Package : Packages )
{
NodeCount + = Package - > ExportGraphNodes . Num ( ) ;
}
for ( auto & KV : Edges )
{
2021-06-15 16:38:03 -04:00
FPackageStorePackage : : FExportBundleGraphNode * ToNode = KV . Value ;
2021-02-08 10:48:17 -04:00
+ + ToNode - > IncomingEdgeCount ;
}
2021-06-15 16:38:03 -04:00
auto NodeSorter = [ ] ( const FPackageStorePackage : : FExportBundleGraphNode & A , const FPackageStorePackage : : FExportBundleGraphNode & B )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
return A . Index < B . Index ;
2021-02-08 10:48:17 -04:00
} ;
for ( FPackageStorePackage * Package : Packages )
{
2021-06-15 16:38:03 -04:00
for ( FPackageStorePackage : : FExportBundleGraphNode & Node : Package - > ExportBundleGraphNodes )
2021-02-08 10:48:17 -04:00
{
if ( Node . IncomingEdgeCount = = 0 )
{
Package - > NodesWithNoIncomingEdges . HeapPush ( & Node , NodeSorter ) ;
}
}
}
2021-06-15 16:38:03 -04:00
TArray < FPackageStorePackage : : FExportBundleGraphNode * > LoadOrder ;
2021-02-08 10:48:17 -04:00
LoadOrder . Reserve ( NodeCount ) ;
while ( LoadOrder . Num ( ) < NodeCount )
{
bool bMadeProgress = false ;
for ( FPackageStorePackage * Package : Packages )
{
while ( Package - > NodesWithNoIncomingEdges . Num ( ) )
{
2021-06-15 16:38:03 -04:00
FPackageStorePackage : : FExportBundleGraphNode * RemovedNode ;
2021-02-08 10:48:17 -04:00
Package - > NodesWithNoIncomingEdges . HeapPop ( RemovedNode , NodeSorter , false ) ;
LoadOrder . Add ( RemovedNode ) ;
bMadeProgress = true ;
for ( auto EdgeIt = Edges . CreateKeyIterator ( RemovedNode ) ; EdgeIt ; + + EdgeIt )
{
2021-06-15 16:38:03 -04:00
FPackageStorePackage : : FExportBundleGraphNode * ToNode = EdgeIt . Value ( ) ;
2021-02-08 10:48:17 -04:00
check ( ToNode - > IncomingEdgeCount > 0 ) ;
if ( - - ToNode - > IncomingEdgeCount = = 0 )
{
ToNode - > Package - > NodesWithNoIncomingEdges . HeapPush ( ToNode , NodeSorter ) ;
}
EdgeIt . RemoveCurrent ( ) ;
}
}
}
check ( bMadeProgress ) ;
}
return LoadOrder ;
}
2021-06-15 16:38:03 -04:00
void FPackageStoreOptimizer : : OptimizeExportBundles ( const TMap < FPackageId , FPackageStorePackage * > & PackagesMap )
{
TArray < FPackageStorePackage * > Packages = SortPackagesInLoadOrder ( PackagesMap ) ;
for ( FPackageStorePackage * Package : Packages )
{
Package - > ExportBundleGraphNodes . Reserve ( Package - > GraphData . ExportBundles . Num ( ) ) ;
for ( FPackageStorePackage : : FExportBundle & ExportBundle : Package - > GraphData . ExportBundles )
{
FPackageStorePackage : : FExportBundleGraphNode & Node = Package - > ExportBundleGraphNodes . AddDefaulted_GetRef ( ) ;
Node . Package = Package ;
Node . Index = Package - > ExportBundleGraphNodes . Num ( ) - 1 ;
Node . ExportGraphNodes . Reserve ( ExportBundle . Entries . Num ( ) ) ;
for ( FExportBundleEntry & ExportBundleEntry : ExportBundle . Entries )
{
FPackageStorePackage : : FExport & Export = Package - > Exports [ ExportBundleEntry . LocalExportIndex ] ;
Node . ExportGraphNodes . Add ( Export . Nodes [ ExportBundleEntry . CommandType ] ) ;
}
}
Package - > GraphData . ExportBundles . Empty ( ) ;
}
FExportBundleGraphEdges Edges ;
TSet < FPackageStorePackage : : FExportBundleGraphNode * > Dependencies ;
for ( FPackageStorePackage * Package : Packages )
{
for ( FPackageStorePackage : : FExportBundleGraphNode & ExportBundleGraphNode : Package - > ExportBundleGraphNodes )
{
for ( FPackageStorePackage : : FExportGraphNode * ExportGraphNode : ExportBundleGraphNode . ExportGraphNodes )
{
check ( ExportGraphNode - > ExportBundleIndex > = 0 ) ;
for ( FPackageStorePackage : : FExportGraphNode * InternalDependency : ExportGraphNode - > InternalDependencies )
{
check ( InternalDependency - > ExportBundleIndex > = 0 ) ;
FPackageStorePackage : : FExportBundleGraphNode * FromNode = & Package - > ExportBundleGraphNodes [ InternalDependency - > ExportBundleIndex ] ;
Dependencies . Add ( FromNode ) ;
}
for ( FPackageStorePackage : : FExternalDependency & ExternalDependency : ExportGraphNode - > ExternalDependencies )
{
2021-08-02 07:21:44 -04:00
FPackageObjectIndex FromImport = Package - > Imports [ ExternalDependency . ImportIndex ] ;
check ( FromImport . IsPackageImport ( ) ) ;
FPackageImportReference FromPackageImportRef = FromImport . ToPackageImportRef ( ) ;
FPackageId FromPackageId = Package - > ImportedPackageIds [ FromPackageImportRef . GetImportedPackageIndex ( ) ] ;
2021-11-18 14:37:34 -05:00
uint64 FromPublicExportHash = Package - > ImportedPublicExportHashes [ FromPackageImportRef . GetImportedPublicExportHashIndex ( ) ] ;
2021-08-02 07:21:44 -04:00
FPackageStorePackage * FindFromPackage = PackagesMap . FindRef ( FromPackageId ) ;
2021-06-15 16:38:03 -04:00
if ( FindFromPackage )
{
bool bFoundExport = false ;
for ( int32 ExportIndex = 0 ; ExportIndex < FindFromPackage - > Exports . Num ( ) ; + + ExportIndex )
{
FPackageStorePackage : : FExport & FromExport = FindFromPackage - > Exports [ ExportIndex ] ;
2021-11-18 14:37:34 -05:00
if ( FromExport . PublicExportHash = = FromPublicExportHash )
2021-06-15 16:38:03 -04:00
{
FPackageStorePackage : : FExportGraphNode * FromExportGraphNode = FromExport . Nodes [ ExternalDependency . ExportBundleCommandType ] ;
check ( FromExportGraphNode - > ExportBundleIndex > = 0 ) ;
FPackageStorePackage : : FExportBundleGraphNode * FromNode = & FindFromPackage - > ExportBundleGraphNodes [ FromExportGraphNode - > ExportBundleIndex ] ;
Dependencies . Add ( FromNode ) ;
bFoundExport = true ;
break ;
}
}
}
}
}
for ( FPackageStorePackage : : FExportBundleGraphNode * FromNode : Dependencies )
{
Edges . Add ( FromNode , & ExportBundleGraphNode ) ;
}
Dependencies . Reset ( ) ;
}
}
TArray < FPackageStorePackage : : FExportBundleGraphNode * > LoadOrder = SortExportBundleGraphNodesInLoadOrder ( Packages , Edges ) ;
FPackageStorePackage * PreviousPackage = nullptr ;
2021-08-18 07:59:06 -04:00
for ( const FPackageStorePackage : : FExportBundleGraphNode * Node : LoadOrder )
2021-06-15 16:38:03 -04:00
{
2021-08-18 07:59:06 -04:00
check ( Node ) ;
2021-06-15 16:38:03 -04:00
FPackageStorePackage * Package = Node - > Package ;
2021-08-05 13:15:23 -04:00
check ( Package ) ;
2021-08-18 07:59:06 -04:00
if ( Package - > CurrentBundle = = nullptr | | Package ! = PreviousPackage )
2021-06-15 16:38:03 -04:00
{
if ( Package - > GraphData . ExportBundles . IsEmpty ( ) )
{
Package - > LoadOrder = NextLoadOrder + + ;
}
Package - > CurrentBundle = & Package - > GraphData . ExportBundles . AddDefaulted_GetRef ( ) ;
}
for ( FPackageStorePackage : : FExportGraphNode * ExportGraphNode : Node - > ExportGraphNodes )
{
Package - > CurrentBundle - > Entries . Add ( ExportGraphNode - > BundleEntry ) ;
ExportGraphNode - > ExportBundleIndex = Package - > GraphData . ExportBundles . Num ( ) - 1 ;
}
PreviousPackage = Package ;
}
}
void FPackageStoreOptimizer : : ProcessPreloadDependencies ( const FCookedHeaderData & CookedHeaderData , FPackageStorePackage * Package ) const
{
TRACE_CPUPROFILER_EVENT_SCOPE ( ProcessPreloadDependencies ) ;
auto AddInternalDependency = [ ] ( FPackageStorePackage * Package , int32 FromExportIndex , FExportBundleEntry : : EExportCommandType FromExportBundleCommandType , FPackageStorePackage : : FExportGraphNode * ToNode )
{
FPackageStorePackage : : FExport & FromExport = Package - > Exports [ FromExportIndex ] ;
FPackageStorePackage : : FExportGraphNode * FromNode = FromExport . Nodes [ FromExportBundleCommandType ] ;
ToNode - > InternalDependencies . Add ( FromNode ) ;
} ;
auto AddExternalDependency = [ ] ( FPackageStorePackage * Package , int32 FromImportIndex , FExportBundleEntry : : EExportCommandType FromExportBundleCommandType , FPackageStorePackage : : FExportGraphNode * ToNode )
{
2021-08-02 07:21:44 -04:00
FPackageObjectIndex FromImport = Package - > Imports [ FromImportIndex ] ;
if ( FromImport . IsScriptImport ( ) )
2021-06-15 16:38:03 -04:00
{
return ;
}
FPackageStorePackage : : FExternalDependency & ExternalDependency = ToNode - > ExternalDependencies . AddDefaulted_GetRef ( ) ;
ExternalDependency . ImportIndex = FromImportIndex ;
ExternalDependency . ExportBundleCommandType = FromExportBundleCommandType ;
} ;
for ( int32 ExportIndex = 0 ; ExportIndex < Package - > Exports . Num ( ) ; + + ExportIndex )
{
FPackageStorePackage : : FExport & Export = Package - > Exports [ ExportIndex ] ;
const FObjectExport & ObjectExport = CookedHeaderData . ObjectExports [ ExportIndex ] ;
AddInternalDependency ( Package , ExportIndex , FExportBundleEntry : : ExportCommandType_Create , Export . Nodes [ FExportBundleEntry : : ExportCommandType_Serialize ] ) ;
if ( ObjectExport . FirstExportDependency > = 0 )
{
int32 RunningIndex = ObjectExport . FirstExportDependency ;
for ( int32 Index = ObjectExport . SerializationBeforeSerializationDependencies ; Index > 0 ; Index - - )
{
FPackageIndex Dep = CookedHeaderData . PreloadDependencies [ RunningIndex + + ] ;
if ( Dep . IsExport ( ) )
{
AddInternalDependency ( Package , Dep . ToExport ( ) , FExportBundleEntry : : ExportCommandType_Serialize , Export . Nodes [ FExportBundleEntry : : ExportCommandType_Serialize ] ) ;
}
else
{
AddExternalDependency ( Package , Dep . ToImport ( ) , FExportBundleEntry : : ExportCommandType_Serialize , Export . Nodes [ FExportBundleEntry : : ExportCommandType_Serialize ] ) ;
}
}
for ( int32 Index = ObjectExport . CreateBeforeSerializationDependencies ; Index > 0 ; Index - - )
{
FPackageIndex Dep = CookedHeaderData . PreloadDependencies [ RunningIndex + + ] ;
if ( Dep . IsExport ( ) )
{
AddInternalDependency ( Package , Dep . ToExport ( ) , FExportBundleEntry : : ExportCommandType_Create , Export . Nodes [ FExportBundleEntry : : ExportCommandType_Serialize ] ) ;
}
else
{
AddExternalDependency ( Package , Dep . ToImport ( ) , FExportBundleEntry : : ExportCommandType_Create , Export . Nodes [ FExportBundleEntry : : ExportCommandType_Serialize ] ) ;
}
}
for ( int32 Index = ObjectExport . SerializationBeforeCreateDependencies ; Index > 0 ; Index - - )
{
FPackageIndex Dep = CookedHeaderData . PreloadDependencies [ RunningIndex + + ] ;
if ( Dep . IsExport ( ) )
{
AddInternalDependency ( Package , Dep . ToExport ( ) , FExportBundleEntry : : ExportCommandType_Serialize , Export . Nodes [ FExportBundleEntry : : ExportCommandType_Create ] ) ;
}
else
{
AddExternalDependency ( Package , Dep . ToImport ( ) , FExportBundleEntry : : ExportCommandType_Serialize , Export . Nodes [ FExportBundleEntry : : ExportCommandType_Create ] ) ;
}
}
for ( int32 Index = ObjectExport . CreateBeforeCreateDependencies ; Index > 0 ; Index - - )
{
FPackageIndex Dep = CookedHeaderData . PreloadDependencies [ RunningIndex + + ] ;
if ( Dep . IsExport ( ) )
{
AddInternalDependency ( Package , Dep . ToExport ( ) , FExportBundleEntry : : ExportCommandType_Create , Export . Nodes [ FExportBundleEntry : : ExportCommandType_Create ] ) ;
}
else
{
AddExternalDependency ( Package , Dep . ToImport ( ) , FExportBundleEntry : : ExportCommandType_Create , Export . Nodes [ FExportBundleEntry : : ExportCommandType_Create ] ) ;
}
}
}
}
}
void FPackageStoreOptimizer : : ProcessPreloadDependencies ( const FPackageStoreHeaderData & PackageStoreHeaderData , FPackageStorePackage * Package ) const
{
TRACE_CPUPROFILER_EVENT_SCOPE ( ProcessPreloadDependencies ) ;
for ( const FPackageStorePackage : : FInternalArc & InternalArc : PackageStoreHeaderData . InternalArcs )
{
const FExportBundleHeader & FromExportBundle = PackageStoreHeaderData . ExportBundleHeaders [ InternalArc . FromExportBundleIndex ] ;
const FExportBundleHeader & ToExportBundle = PackageStoreHeaderData . ExportBundleHeaders [ InternalArc . ToExportBundleIndex ] ;
uint32 FromBundleEntryIndex = FromExportBundle . FirstEntryIndex ;
const uint32 LastFromBundleEntryIndex = FromBundleEntryIndex + FromExportBundle . EntryCount ;
while ( FromBundleEntryIndex < LastFromBundleEntryIndex )
{
const FExportBundleEntry & FromBundleEntry = PackageStoreHeaderData . ExportBundleEntries [ FromBundleEntryIndex + + ] ;
FPackageStorePackage : : FExport & FromExport = Package - > Exports [ FromBundleEntry . LocalExportIndex ] ;
FPackageStorePackage : : FExportGraphNode * FromNode = FromExport . Nodes [ FromBundleEntry . CommandType ] ;
uint32 ToBundleEntryIndex = ToExportBundle . FirstEntryIndex ;
const uint32 LastToBundleEntryIndex = ToBundleEntryIndex + ToExportBundle . EntryCount ;
while ( ToBundleEntryIndex < LastToBundleEntryIndex )
{
const FExportBundleEntry & ToBundleEntry = PackageStoreHeaderData . ExportBundleEntries [ ToBundleEntryIndex + + ] ;
FPackageStorePackage : : FExport & ToExport = Package - > Exports [ ToBundleEntry . LocalExportIndex ] ;
FPackageStorePackage : : FExportGraphNode * ToNode = ToExport . Nodes [ ToBundleEntry . CommandType ] ;
ToNode - > InternalDependencies . Add ( FromNode ) ;
}
}
}
for ( const FPackageStorePackage : : FExternalArc & ExternalArc : PackageStoreHeaderData . ExternalArcs )
{
const FExportBundleHeader & ToExportBundle = PackageStoreHeaderData . ExportBundleHeaders [ ExternalArc . ToExportBundleIndex ] ;
uint32 ToBundleEntryIndex = ToExportBundle . FirstEntryIndex ;
const uint32 LastToBundleEntryIndex = ToBundleEntryIndex + ToExportBundle . EntryCount ;
while ( ToBundleEntryIndex < LastToBundleEntryIndex )
{
const FExportBundleEntry & ToBundleEntry = PackageStoreHeaderData . ExportBundleEntries [ ToBundleEntryIndex + + ] ;
FPackageStorePackage : : FExport & ToExport = Package - > Exports [ ToBundleEntry . LocalExportIndex ] ;
FPackageStorePackage : : FExportGraphNode * ToNode = ToExport . Nodes [ ToBundleEntry . CommandType ] ;
FPackageStorePackage : : FExternalDependency & ExternalDependency = ToNode - > ExternalDependencies . AddDefaulted_GetRef ( ) ;
ExternalDependency . ImportIndex = ExternalArc . FromImportIndex ;
ExternalDependency . ExportBundleCommandType = ExternalArc . FromCommandType ;
}
}
}
TArray < FPackageStorePackage : : FExportGraphNode * > FPackageStoreOptimizer : : SortExportGraphNodesInLoadOrder ( FPackageStorePackage * Package , FExportGraphEdges & Edges ) const
{
TRACE_CPUPROFILER_EVENT_SCOPE ( SortExportGraphNodesInLoadOrder ) ;
int32 NodeCount = Package - > ExportGraphNodes . Num ( ) ;
for ( auto & KV : Edges )
{
FPackageStorePackage : : FExportGraphNode * ToNode = KV . Value ;
+ + ToNode - > IncomingEdgeCount ;
}
auto NodeSorter = [ ] ( const FPackageStorePackage : : FExportGraphNode & A , const FPackageStorePackage : : FExportGraphNode & B )
{
if ( A . bIsPublic ! = B . bIsPublic )
{
return A . bIsPublic ;
}
if ( A . BundleEntry . CommandType ! = B . BundleEntry . CommandType )
{
return A . BundleEntry . CommandType < B . BundleEntry . CommandType ;
}
return A . BundleEntry . LocalExportIndex < B . BundleEntry . LocalExportIndex ;
} ;
TArray < FPackageStorePackage : : FExportGraphNode * > NodesWithNoIncomingEdges ;
NodesWithNoIncomingEdges . Reserve ( NodeCount ) ;
for ( FPackageStorePackage : : FExportGraphNode & Node : Package - > ExportGraphNodes )
{
if ( Node . IncomingEdgeCount = = 0 )
{
NodesWithNoIncomingEdges . HeapPush ( & Node , NodeSorter ) ;
}
}
TArray < FPackageStorePackage : : FExportGraphNode * > LoadOrder ;
LoadOrder . Reserve ( NodeCount ) ;
while ( NodesWithNoIncomingEdges . Num ( ) )
{
FPackageStorePackage : : FExportGraphNode * RemovedNode ;
NodesWithNoIncomingEdges . HeapPop ( RemovedNode , NodeSorter , false ) ;
LoadOrder . Add ( RemovedNode ) ;
for ( auto EdgeIt = Edges . CreateKeyIterator ( RemovedNode ) ; EdgeIt ; + + EdgeIt )
{
FPackageStorePackage : : FExportGraphNode * ToNode = EdgeIt . Value ( ) ;
check ( ToNode - > IncomingEdgeCount > 0 ) ;
if ( - - ToNode - > IncomingEdgeCount = = 0 )
{
NodesWithNoIncomingEdges . HeapPush ( ToNode , NodeSorter ) ;
}
EdgeIt . RemoveCurrent ( ) ;
}
}
check ( LoadOrder . Num ( ) = = NodeCount ) ;
return LoadOrder ;
}
void FPackageStoreOptimizer : : CreateExportBundles ( FPackageStorePackage * Package ) const
2021-02-08 10:48:17 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( CreateExportBundles ) ;
2021-06-15 16:38:03 -04:00
FExportGraphEdges Edges ;
for ( FPackageStorePackage : : FExportGraphNode & ExportGraphNode : Package - > ExportGraphNodes )
{
for ( FPackageStorePackage : : FExportGraphNode * InternalDependency : ExportGraphNode . InternalDependencies )
{
Edges . Add ( InternalDependency , & ExportGraphNode ) ;
}
}
TArray < FPackageStorePackage : : FExportGraphNode * > LoadOrder = SortExportGraphNodesInLoadOrder ( Package , Edges ) ;
FPackageStorePackage : : FExportBundle * CurrentBundle = nullptr ;
2021-02-08 10:48:17 -04:00
for ( FPackageStorePackage : : FExportGraphNode * Node : LoadOrder )
{
2021-06-15 16:38:03 -04:00
if ( ! CurrentBundle )
2021-02-09 15:11:26 -04:00
{
2021-06-15 16:38:03 -04:00
Package - > CurrentBundle = & Package - > GraphData . ExportBundles . AddDefaulted_GetRef ( ) ;
2021-02-09 15:11:26 -04:00
}
2021-06-15 16:38:03 -04:00
Package - > CurrentBundle - > Entries . Add ( Node - > BundleEntry ) ;
Node - > ExportBundleIndex = Package - > GraphData . ExportBundles . Num ( ) - 1 ;
if ( Node - > bIsPublic )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
CurrentBundle = nullptr ;
2021-02-08 10:48:17 -04:00
}
}
}
static const TCHAR * GetExportNameSafe ( const FString & ExportFullName , const FName & PackageName , int32 PackageNameLen )
{
const bool bValidNameLen = ExportFullName . Len ( ) > PackageNameLen + 1 ;
if ( bValidNameLen )
{
const TCHAR * ExportNameStr = * ExportFullName + PackageNameLen ;
const bool bValidNameFormat = * ExportNameStr = = ' / ' ;
if ( bValidNameFormat )
{
return ExportNameStr + 1 ; // skip verified '/'
}
else
{
UE_CLOG ( ! bValidNameFormat , LogPackageStoreOptimizer , Warning ,
TEXT ( " Export name '%s' should start with '/' at position %d, i.e. right after package prefix '%s' " ) ,
* ExportFullName ,
PackageNameLen ,
* PackageName . ToString ( ) ) ;
}
}
else
{
UE_CLOG ( ! bValidNameLen , LogPackageStoreOptimizer , Warning ,
TEXT ( " Export name '%s' with length %d should be longer than package name '%s' with length %d " ) ,
* ExportFullName ,
PackageNameLen ,
* PackageName . ToString ( ) ) ;
}
return nullptr ;
} ;
2021-08-02 07:21:44 -04:00
bool FPackageStoreOptimizer : : VerifyRedirect (
const FPackageStorePackage * SourcePackage ,
2021-02-08 10:48:17 -04:00
FPackageStorePackage & TargetPackage ,
2021-08-02 07:21:44 -04:00
bool bIsBuildingDLC ) const
2021-02-08 10:48:17 -04:00
{
2021-08-02 07:21:44 -04:00
if ( ! SourcePackage )
{
if ( bIsBuildingDLC )
{
// We can't verify against the source package but check for presence of UStructs
for ( const FPackageStorePackage : : FExport & Export : TargetPackage . Exports )
{
if ( ! Export . SuperIndex . IsNull ( ) & & Export . OuterIndex . IsNull ( ) )
{
UE_LOG ( LogPackageStoreOptimizer , Warning , TEXT ( " Skipping redirect to package '%s' due to presence of UStruct '%s' " ) , * TargetPackage . Name . ToString ( ) , * Export . ObjectName . ToString ( ) ) ;
return false ;
}
}
return true ;
}
return false ;
}
2021-02-08 10:48:17 -04:00
const int32 ExportCount =
2021-08-02 07:21:44 -04:00
SourcePackage - > Exports . Num ( ) < TargetPackage . Exports . Num ( ) ?
SourcePackage - > Exports . Num ( ) :
2021-02-08 10:48:17 -04:00
TargetPackage . Exports . Num ( ) ;
2021-08-02 07:21:44 -04:00
UE_CLOG ( SourcePackage - > Exports . Num ( ) ! = TargetPackage . Exports . Num ( ) , LogPackageStoreOptimizer , Verbose ,
2021-02-08 10:48:17 -04:00
TEXT ( " Redirection target package '%s' (0x%llX) for source package '%s' (0x%llX) - Has ExportCount %d vs. %d " ) ,
* TargetPackage . Name . ToString ( ) ,
TargetPackage . Id . ValueForDebugging ( ) ,
2021-08-02 07:21:44 -04:00
* SourcePackage - > Name . ToString ( ) ,
SourcePackage - > Id . ValueForDebugging ( ) ,
2021-02-08 10:48:17 -04:00
TargetPackage . Exports . Num ( ) ,
2021-08-02 07:21:44 -04:00
SourcePackage - > Exports . Num ( ) ) ;
2021-02-08 10:48:17 -04:00
2021-08-02 07:21:44 -04:00
auto AppendMismatchMessage = [ & TargetPackage , SourcePackage ] (
2021-02-08 10:48:17 -04:00
const TCHAR * Text , FName ExportName , FPackageObjectIndex TargetIndex , FPackageObjectIndex SourceIndex , FString & FailReason )
{
FailReason . Appendf ( TEXT ( " Public export '%s' has %s %s vs. %s " ) ,
* ExportName . ToString ( ) ,
Text ,
* TargetPackage . Exports [ TargetIndex . ToExport ( ) ] . FullName ,
2021-08-02 07:21:44 -04:00
* SourcePackage - > Exports [ SourceIndex . ToExport ( ) ] . FullName ) ;
2021-02-08 10:48:17 -04:00
} ;
const int32 TargetPackageNameLen = TargetPackage . Name . GetStringLength ( ) ;
2021-08-02 07:21:44 -04:00
const int32 SourcePackageNameLen = SourcePackage - > Name . GetStringLength ( ) ;
2021-02-08 10:48:17 -04:00
bool bSuccess = true ;
int32 TargetIndex = 0 ;
int32 SourceIndex = 0 ;
while ( TargetIndex < ExportCount & & SourceIndex < ExportCount )
{
FString FailReason ;
const FPackageStorePackage : : FExport & TargetExport = TargetPackage . Exports [ TargetIndex ] ;
2021-08-02 07:21:44 -04:00
const FPackageStorePackage : : FExport & SourceExport = SourcePackage - > Exports [ SourceIndex ] ;
2021-02-08 10:48:17 -04:00
const TCHAR * TargetExportStr = GetExportNameSafe (
TargetExport . FullName , TargetPackage . Name , TargetPackageNameLen ) ;
const TCHAR * SourceExportStr = GetExportNameSafe (
2021-08-02 07:21:44 -04:00
SourceExport . FullName , SourcePackage - > Name , SourcePackageNameLen ) ;
2021-02-08 10:48:17 -04:00
if ( ! TargetExportStr | | ! SourceExportStr )
{
UE_LOG ( LogPackageStoreOptimizer , Error ,
TEXT ( " Redirection target package '%s' (0x%llX) for source package '%s' (0x%llX) - Has some bad data from an earlier phase. " ) ,
* TargetPackage . Name . ToString ( ) ,
TargetPackage . Id . ValueForDebugging ( ) ,
2021-08-02 07:21:44 -04:00
* SourcePackage - > Name . ToString ( ) ,
SourcePackage - > Id . ValueForDebugging ( ) )
2021-02-08 10:48:17 -04:00
return false ;
}
int32 CompareResult = FCString : : Stricmp ( TargetExportStr , SourceExportStr ) ;
if ( CompareResult < 0 )
{
+ + TargetIndex ;
}
else if ( CompareResult > 0 )
{
+ + SourceIndex ;
if ( SourceExport . bIsPublic )
{
FailReason . Appendf ( TEXT ( " Public source export '%s' is missing in the localized package " ) ,
* SourceExport . ObjectName . ToString ( ) ) ;
}
}
else
{
+ + TargetIndex ;
+ + SourceIndex ;
if ( SourceExport . bIsPublic )
{
if ( ! TargetExport . bIsPublic )
{
FailReason . Appendf ( TEXT ( " Public source export '%s' exists in the localized package " )
TEXT ( " , but is not a public localized export. " ) ,
* SourceExport . ObjectName . ToString ( ) ) ;
}
else if ( TargetExport . ClassIndex ! = SourceExport . ClassIndex )
{
AppendMismatchMessage ( TEXT ( " class " ) , TargetExport . ObjectName ,
TargetExport . ClassIndex , SourceExport . ClassIndex , FailReason ) ;
}
else if ( TargetExport . TemplateIndex ! = SourceExport . TemplateIndex )
{
AppendMismatchMessage ( TEXT ( " template " ) , TargetExport . ObjectName ,
TargetExport . TemplateIndex , SourceExport . TemplateIndex , FailReason ) ;
}
else if ( TargetExport . SuperIndex ! = SourceExport . SuperIndex )
{
AppendMismatchMessage ( TEXT ( " super " ) , TargetExport . ObjectName ,
TargetExport . SuperIndex , SourceExport . SuperIndex , FailReason ) ;
}
}
else if ( TargetExport . bIsPublic )
{
FailReason . Appendf ( TEXT ( " Export '%s' exists in the source package " )
TEXT ( " , but is not a public source export. " ) ,
* TargetExport . ObjectName . ToString ( ) ) ;
}
}
if ( FailReason . Len ( ) > 0 )
{
UE_LOG ( LogPackageStoreOptimizer , Warning ,
TEXT ( " Redirection target package '%s' (0x%llX) for '%s' (0x%llX) - %s " ) ,
* TargetPackage . Name . ToString ( ) ,
TargetPackage . Id . ValueForDebugging ( ) ,
2021-08-02 07:21:44 -04:00
* SourcePackage - > Name . ToString ( ) ,
SourcePackage - > Id . ValueForDebugging ( ) ,
2021-02-08 10:48:17 -04:00
* FailReason ) ;
bSuccess = false ;
}
}
return bSuccess ;
}
2021-08-02 07:21:44 -04:00
void FPackageStoreOptimizer : : ProcessRedirects ( const TMap < FPackageId , FPackageStorePackage * > & PackagesMap , bool bIsBuildingDLC ) const
2021-02-08 10:48:17 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( ProcessRedirects ) ;
2021-06-15 16:38:03 -04:00
for ( const auto & KV : PackagesMap )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
FPackageStorePackage * Package = KV . Value ;
2021-02-08 10:48:17 -04:00
if ( Package - > SourceName . IsNone ( ) | | Package - > Name = = Package - > SourceName )
{
continue ;
}
FPackageId SourcePackageId = FPackageId : : FromName ( Package - > SourceName ) ;
2021-06-15 16:38:03 -04:00
FPackageStorePackage * SourcePackage = PackagesMap . FindRef ( SourcePackageId ) ;
2021-08-02 07:21:44 -04:00
Package - > bIsRedirected = VerifyRedirect ( SourcePackage , * Package , bIsBuildingDLC ) ;
2021-02-08 10:48:17 -04:00
if ( Package - > bIsRedirected )
{
UE_LOG ( LogPackageStoreOptimizer , Verbose , TEXT ( " Adding package redirect from '%s' (0x%llX) to '%s' (0x%llX). " ) ,
* Package - > SourceName . ToString ( ) ,
SourcePackageId . ValueForDebugging ( ) ,
* Package - > Name . ToString ( ) ,
Package - > Id . ValueForDebugging ( ) ) ;
}
else
{
2021-09-07 01:31:40 -04:00
if ( Package - > Region . Len ( ) > 0 & & ! SourcePackage )
{
// no update or verification required
UE_LOG ( LogPackageStoreOptimizer , Verbose ,
TEXT ( " For culture '%s': Localized package '%s' (0x%llX) is unique and does not override a source package. " ) ,
* Package - > Region ,
* Package - > Name . ToString ( ) ,
Package - > Id . ValueForDebugging ( ) ) ;
}
else
{
UE_LOG ( LogPackageStoreOptimizer , Display ,
TEXT ( " Skipping package redirect from '%s' (0x%llX) to '%s' (0x%llX) due to mismatching public exports. " ) ,
* Package - > SourceName . ToString ( ) ,
SourcePackageId . ValueForDebugging ( ) ,
* Package - > Name . ToString ( ) ,
Package - > Id . ValueForDebugging ( ) ) ;
}
2021-02-08 10:48:17 -04:00
}
}
}
2021-06-15 16:38:03 -04:00
void FPackageStoreOptimizer : : SerializeGraphData ( const TArray < FPackageId > & ImportedPackageIds , FPackageStorePackage : : FGraphData & GraphData , FBufferWriter & GraphArchive ) const
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
uint32 ExportBundleEntryIndex = 0 ;
for ( const FPackageStorePackage : : FExportBundle & ExportBundle : GraphData . ExportBundles )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
const uint32 EntryCount = ExportBundle . Entries . Num ( ) ;
FExportBundleHeader ExportBundleHeader { ExportBundle . SerialOffset , ExportBundleEntryIndex , EntryCount } ;
GraphArchive < < ExportBundleHeader ;
ExportBundleEntryIndex + = EntryCount ;
}
Algo : : Sort ( GraphData . InternalArcs , [ ] ( const FPackageStorePackage : : FInternalArc & A , const FPackageStorePackage : : FInternalArc & B )
{
if ( A . ToExportBundleIndex = = B . ToExportBundleIndex )
{
return A . FromExportBundleIndex < B . FromExportBundleIndex ;
}
return A . ToExportBundleIndex < B . ToExportBundleIndex ;
} ) ;
int32 InternalArcsCount = GraphData . InternalArcs . Num ( ) ;
GraphArchive < < InternalArcsCount ;
for ( FPackageStorePackage : : FInternalArc & InternalArc : GraphData . InternalArcs )
{
GraphArchive < < InternalArc . FromExportBundleIndex ;
GraphArchive < < InternalArc . ToExportBundleIndex ;
}
for ( FPackageId ImportedPackageId : ImportedPackageIds )
{
TArray < FPackageStorePackage : : FExternalArc > * FindArcsFromImportedPackage = GraphData . ExternalArcs . Find ( ImportedPackageId ) ;
if ( ! FindArcsFromImportedPackage )
{
int32 ExternalArcCount = 0 ;
GraphArchive < < ExternalArcCount ;
}
else
{
Algo : : Sort ( * FindArcsFromImportedPackage , [ ] ( const FPackageStorePackage : : FExternalArc & A , const FPackageStorePackage : : FExternalArc & B )
{
if ( A . ToExportBundleIndex = = B . ToExportBundleIndex )
{
if ( A . FromImportIndex = = B . FromImportIndex )
{
return A . FromCommandType < B . FromCommandType ;
}
return A . FromImportIndex < B . FromImportIndex ;
}
return A . ToExportBundleIndex < B . ToExportBundleIndex ;
} ) ;
int32 ExternalArcCount = FindArcsFromImportedPackage - > Num ( ) ;
GraphArchive < < ExternalArcCount ;
for ( FPackageStorePackage : : FExternalArc & Arc : * FindArcsFromImportedPackage )
{
GraphArchive < < Arc . FromImportIndex ;
uint8 FromCommandType = uint8 ( Arc . FromCommandType ) ;
GraphArchive < < FromCommandType ;
GraphArchive < < Arc . ToExportBundleIndex ;
}
}
2021-02-08 10:48:17 -04:00
}
}
void FPackageStoreOptimizer : : FinalizePackageHeader ( FPackageStorePackage * Package ) const
{
2021-11-18 14:37:34 -05:00
FBufferWriter ImportedPublicExportHashesArchive ( nullptr , 0 , EBufferWriterFlags : : AllowResize | EBufferWriterFlags : : TakeOwnership ) ;
for ( uint64 ImportedPublicExportHash : Package - > ImportedPublicExportHashes )
{
ImportedPublicExportHashesArchive < < ImportedPublicExportHash ;
}
Package - > ImportedPublicExportHashesSize = ImportedPublicExportHashesArchive . Tell ( ) ;
2021-02-08 10:48:17 -04:00
FBufferWriter ImportMapArchive ( nullptr , 0 , EBufferWriterFlags : : AllowResize | EBufferWriterFlags : : TakeOwnership ) ;
2021-08-02 07:21:44 -04:00
for ( FPackageObjectIndex Import : Package - > Imports )
2021-02-08 10:48:17 -04:00
{
2021-08-02 07:21:44 -04:00
ImportMapArchive < < Import ;
2021-02-08 10:48:17 -04:00
}
Package - > ImportMapSize = ImportMapArchive . Tell ( ) ;
FBufferWriter ExportMapArchive ( nullptr , 0 , EBufferWriterFlags : : AllowResize | EBufferWriterFlags : : TakeOwnership ) ;
for ( const FPackageStorePackage : : FExport & Export : Package - > Exports )
{
FExportMapEntry ExportMapEntry ;
ExportMapEntry . CookedSerialOffset = Export . CookedSerialOffset ;
2021-06-15 16:38:03 -04:00
ExportMapEntry . CookedSerialSize = Export . SerialSize ;
2021-09-30 02:05:41 -04:00
Package - > NameMapBuilder . MarkNameAsReferenced ( Export . ObjectName ) ;
2021-02-08 10:48:17 -04:00
ExportMapEntry . ObjectName = Package - > NameMapBuilder . MapName ( Export . ObjectName ) ;
2021-11-18 14:37:34 -05:00
ExportMapEntry . PublicExportHash = Export . PublicExportHash ;
2021-02-08 10:48:17 -04:00
ExportMapEntry . OuterIndex = Export . OuterIndex ;
ExportMapEntry . ClassIndex = Export . ClassIndex ;
ExportMapEntry . SuperIndex = Export . SuperIndex ;
ExportMapEntry . TemplateIndex = Export . TemplateIndex ;
ExportMapEntry . ObjectFlags = Export . ObjectFlags ;
ExportMapEntry . FilterFlags = EExportFilterFlags : : None ;
if ( Export . bNotForClient )
{
ExportMapEntry . FilterFlags = EExportFilterFlags : : NotForClient ;
}
else if ( Export . bNotForServer )
{
ExportMapEntry . FilterFlags = EExportFilterFlags : : NotForServer ;
}
ExportMapArchive < < ExportMapEntry ;
}
Package - > ExportMapSize = ExportMapArchive . Tell ( ) ;
2021-06-15 16:38:03 -04:00
FBufferWriter ExportBundleEntriesArchive ( nullptr , 0 , EBufferWriterFlags : : AllowResize | EBufferWriterFlags : : TakeOwnership ) ;
for ( const FPackageStorePackage : : FExportBundle & ExportBundle : Package - > GraphData . ExportBundles )
2021-02-08 10:48:17 -04:00
{
for ( FExportBundleEntry BundleEntry : ExportBundle . Entries )
{
2021-06-15 16:38:03 -04:00
ExportBundleEntriesArchive < < BundleEntry ;
2021-02-08 10:48:17 -04:00
}
}
2021-06-15 16:38:03 -04:00
Package - > ExportBundleEntriesSize = ExportBundleEntriesArchive . Tell ( ) ;
FBufferWriter GraphArchive ( nullptr , 0 , EBufferWriterFlags : : AllowResize | EBufferWriterFlags : : TakeOwnership ) ;
SerializeGraphData ( Package - > ImportedPackageIds , Package - > GraphData , GraphArchive ) ;
Package - > GraphDataSize = GraphArchive . Tell ( ) ;
2021-02-08 10:48:17 -04:00
Package - > NameMapBuilder . MarkNameAsReferenced ( Package - > Name ) ;
FMappedName MappedPackageName = Package - > NameMapBuilder . MapName ( Package - > Name ) ;
2021-06-15 16:38:03 -04:00
FBufferWriter NameMapArchive ( nullptr , 0 , EBufferWriterFlags : : AllowResize | EBufferWriterFlags : : TakeOwnership ) ;
SaveNameBatch ( Package - > NameMapBuilder . GetNameMap ( ) , NameMapArchive ) ;
Package - > NameMapSize = NameMapArchive . Tell ( ) ;
2021-02-08 10:48:17 -04:00
2021-10-12 21:21:22 -04:00
FBufferWriter VersioningInfoArchive ( nullptr , 0 , EBufferWriterFlags : : AllowResize | EBufferWriterFlags : : TakeOwnership ) ;
if ( Package - > VersioningInfo . IsSet ( ) )
{
VersioningInfoArchive < < Package - > VersioningInfo . GetValue ( ) ;
Package - > VersioningInfoSize = VersioningInfoArchive . Tell ( ) ;
}
2021-06-15 16:38:03 -04:00
Package - > HeaderSize =
2021-10-12 21:21:22 -04:00
sizeof ( FZenPackageSummary )
+ Package - > VersioningInfoSize
2021-02-08 10:48:17 -04:00
+ Package - > NameMapSize
2021-11-18 14:37:34 -05:00
+ Package - > ImportedPublicExportHashesSize
2021-02-08 10:48:17 -04:00
+ Package - > ImportMapSize
+ Package - > ExportMapSize
2021-06-15 16:38:03 -04:00
+ Package - > ExportBundleEntriesSize
+ Package - > GraphDataSize ;
2021-02-08 10:48:17 -04:00
2021-06-15 16:38:03 -04:00
Package - > HeaderBuffer = FIoBuffer ( Package - > HeaderSize ) ;
uint8 * HeaderData = Package - > HeaderBuffer . Data ( ) ;
FMemory : : Memzero ( HeaderData , Package - > HeaderSize ) ;
2021-10-12 21:21:22 -04:00
FZenPackageSummary * PackageSummary = reinterpret_cast < FZenPackageSummary * > ( HeaderData ) ;
2021-06-15 16:38:03 -04:00
PackageSummary - > HeaderSize = Package - > HeaderSize ;
2021-02-08 10:48:17 -04:00
PackageSummary - > Name = MappedPackageName ;
PackageSummary - > PackageFlags = Package - > PackageFlags ;
PackageSummary - > CookedHeaderSize = Package - > CookedHeaderSize ;
2021-06-15 16:38:03 -04:00
FBufferWriter HeaderArchive ( HeaderData , Package - > HeaderSize ) ;
2021-10-12 21:21:22 -04:00
HeaderArchive . Seek ( sizeof ( FZenPackageSummary ) ) ;
2021-02-08 10:48:17 -04:00
2021-10-12 21:21:22 -04:00
if ( Package - > VersioningInfo . IsSet ( ) )
2021-02-08 10:48:17 -04:00
{
2021-10-12 21:21:22 -04:00
PackageSummary - > bHasVersioningInfo = 1 ;
HeaderArchive . Serialize ( VersioningInfoArchive . GetWriterData ( ) , VersioningInfoArchive . Tell ( ) ) ;
}
else
{
PackageSummary - > bHasVersioningInfo = 0 ;
2021-02-08 10:48:17 -04:00
}
2021-06-15 16:38:03 -04:00
HeaderArchive . Serialize ( NameMapArchive . GetWriterData ( ) , NameMapArchive . Tell ( ) ) ;
2021-11-18 14:37:34 -05:00
PackageSummary - > ImportedPublicExportHashesOffset = HeaderArchive . Tell ( ) ;
HeaderArchive . Serialize ( ImportedPublicExportHashesArchive . GetWriterData ( ) , ImportedPublicExportHashesArchive . Tell ( ) ) ;
2021-06-15 16:38:03 -04:00
PackageSummary - > ImportMapOffset = HeaderArchive . Tell ( ) ;
HeaderArchive . Serialize ( ImportMapArchive . GetWriterData ( ) , ImportMapArchive . Tell ( ) ) ;
PackageSummary - > ExportMapOffset = HeaderArchive . Tell ( ) ;
HeaderArchive . Serialize ( ExportMapArchive . GetWriterData ( ) , ExportMapArchive . Tell ( ) ) ;
PackageSummary - > ExportBundleEntriesOffset = HeaderArchive . Tell ( ) ;
HeaderArchive . Serialize ( ExportBundleEntriesArchive . GetWriterData ( ) , ExportBundleEntriesArchive . Tell ( ) ) ;
PackageSummary - > GraphDataOffset = HeaderArchive . Tell ( ) ;
HeaderArchive . Serialize ( GraphArchive . GetWriterData ( ) , GraphArchive . Tell ( ) ) ;
check ( HeaderArchive . Tell ( ) = = PackageSummary - > HeaderSize )
2021-02-08 10:48:17 -04:00
}
2021-06-15 16:38:03 -04:00
void FPackageStoreOptimizer : : FinalizePackage ( FPackageStorePackage * Package )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
+ + TotalPackageCount ;
TotalExportBundleCount + = Package - > GraphData . ExportBundles . Num ( ) ;
uint64 PackageExportBundleEntryCount = 0 ;
for ( const FPackageStorePackage : : FExportBundle & ExportBundle : Package - > GraphData . ExportBundles )
{
PackageExportBundleEntryCount + = ExportBundle . Entries . Num ( ) ;
}
check ( PackageExportBundleEntryCount = = FExportBundleEntry : : ExportCommandType_Count * Package - > Exports . Num ( ) ) ;
TotalExportBundleEntryCount + = PackageExportBundleEntryCount ;
2021-02-08 10:48:17 -04:00
for ( FPackageStorePackage : : FExportGraphNode & Node : Package - > ExportGraphNodes )
{
check ( Node . ExportBundleIndex > = 0 ) ;
2021-12-16 18:22:15 -05:00
TSet < FPackageStorePackage : : FInternalArc > InternalArcsSet ;
2021-06-15 16:38:03 -04:00
for ( FPackageStorePackage : : FExportGraphNode * InternalDependency : Node . InternalDependencies )
{
FPackageStorePackage : : FInternalArc Arc ;
check ( InternalDependency - > ExportBundleIndex > = 0 ) ;
Arc . FromExportBundleIndex = InternalDependency - > ExportBundleIndex ;
Arc . ToExportBundleIndex = Node . ExportBundleIndex ;
2021-12-16 18:22:15 -05:00
if ( Arc . FromExportBundleIndex ! = Arc . ToExportBundleIndex )
2021-06-15 16:38:03 -04:00
{
2021-12-16 18:22:15 -05:00
bool bIsAlreadyInSet = false ;
InternalArcsSet . Add ( Arc , & bIsAlreadyInSet ) ;
if ( ! bIsAlreadyInSet )
{
Package - > GraphData . InternalArcs . Add ( Arc ) ;
+ + TotalInternalBundleArcsCount ;
}
2021-06-15 16:38:03 -04:00
}
}
2021-02-08 10:48:17 -04:00
for ( FPackageStorePackage : : FExternalDependency & ExternalDependency : Node . ExternalDependencies )
{
2021-06-15 16:38:03 -04:00
check ( ExternalDependency . ImportIndex > = 0 ) ;
2021-08-02 07:21:44 -04:00
const FPackageObjectIndex & Import = Package - > Imports [ ExternalDependency . ImportIndex ] ;
check ( Import . IsPackageImport ( ) ) ;
FPackageImportReference PackageImportRef = Import . ToPackageImportRef ( ) ;
TArray < FPackageStorePackage : : FExternalArc > & ArcsFromImportedPackage = Package - > GraphData . ExternalArcs . FindOrAdd ( Package - > ImportedPackageIds [ PackageImportRef . GetImportedPackageIndex ( ) ] ) ;
2021-06-15 16:38:03 -04:00
FPackageStorePackage : : FExternalArc Arc ;
Arc . FromImportIndex = ExternalDependency . ImportIndex ;
Arc . FromCommandType = ExternalDependency . ExportBundleCommandType ;
Arc . ToExportBundleIndex = Node . ExportBundleIndex ;
2021-02-08 10:48:17 -04:00
if ( ! ArcsFromImportedPackage . Contains ( Arc ) )
{
ArcsFromImportedPackage . Add ( Arc ) ;
2021-06-15 16:38:03 -04:00
+ + TotalExternalBundleArcsCount ;
}
}
}
uint64 SerialOffset = 0 ;
for ( FPackageStorePackage : : FExportBundle & ExportBundle : Package - > GraphData . ExportBundles )
{
ExportBundle . SerialOffset = SerialOffset ;
for ( const FExportBundleEntry & BundleEntry : ExportBundle . Entries )
{
if ( BundleEntry . CommandType = = FExportBundleEntry : : ExportCommandType_Serialize )
{
const FPackageStorePackage : : FExport & Export = Package - > Exports [ BundleEntry . LocalExportIndex ] ;
SerialOffset + = Export . SerialSize ;
2021-02-08 10:48:17 -04:00
}
}
}
FinalizePackageHeader ( Package ) ;
}
FIoBuffer FPackageStoreOptimizer : : CreatePackageBuffer ( const FPackageStorePackage * Package , const FIoBuffer & CookedExportsDataBuffer , TArray < FFileRegion > * InOutFileRegions ) const
{
2021-06-15 16:38:03 -04:00
check ( Package - > HeaderBuffer . DataSize ( ) > 0 ) ;
check ( Package - > HeaderBuffer . DataSize ( ) = = Package - > HeaderSize ) ;
const uint64 BundleBufferSize = Package - > HeaderSize + Package - > ExportsSerialSize ;
2021-02-08 10:48:17 -04:00
FIoBuffer BundleBuffer ( BundleBufferSize ) ;
2021-06-15 16:38:03 -04:00
FMemory : : Memcpy ( BundleBuffer . Data ( ) , Package - > HeaderBuffer . Data ( ) , Package - > HeaderSize ) ;
uint64 BundleBufferOffset = Package - > HeaderSize ;
2021-02-08 10:48:17 -04:00
TArray < FFileRegion > OutputRegions ;
2021-06-15 16:38:03 -04:00
for ( const FPackageStorePackage : : FExportBundle & ExportBundle : Package - > GraphData . ExportBundles )
2021-02-08 10:48:17 -04:00
{
for ( const FExportBundleEntry & BundleEntry : ExportBundle . Entries )
{
if ( BundleEntry . CommandType = = FExportBundleEntry : : ExportCommandType_Serialize )
{
const FPackageStorePackage : : FExport & Export = Package - > Exports [ BundleEntry . LocalExportIndex ] ;
2021-06-15 16:38:03 -04:00
check ( Export . SerialOffset + Export . SerialSize < = CookedExportsDataBuffer . DataSize ( ) ) ;
FMemory : : Memcpy ( BundleBuffer . Data ( ) + BundleBufferOffset , CookedExportsDataBuffer . Data ( ) + Export . SerialOffset , Export . SerialSize ) ;
2021-02-08 10:48:17 -04:00
if ( InOutFileRegions )
{
// Find overlapping regions and adjust them to match the new offset of the export data
for ( const FFileRegion & Region : * InOutFileRegions )
{
2021-06-15 16:38:03 -04:00
if ( Export . SerialOffset < = Region . Offset & & Region . Offset + Region . Length < = Export . SerialOffset + Export . SerialSize )
2021-02-08 10:48:17 -04:00
{
FFileRegion NewRegion = Region ;
2021-06-15 16:38:03 -04:00
NewRegion . Offset - = Export . SerialOffset ;
2021-02-08 10:48:17 -04:00
NewRegion . Offset + = BundleBufferOffset ;
OutputRegions . Add ( NewRegion ) ;
}
}
}
2021-06-15 16:38:03 -04:00
BundleBufferOffset + = Export . SerialSize ;
2021-02-08 10:48:17 -04:00
}
}
}
check ( BundleBufferOffset = = BundleBuffer . DataSize ( ) ) ;
if ( InOutFileRegions )
{
* InOutFileRegions = OutputRegions ;
}
return BundleBuffer ;
}
2021-10-12 21:21:22 -04:00
void FPackageStoreOptimizer : : FindScriptObjectsRecursive ( FPackageObjectIndex OuterIndex , UObject * Object )
2021-02-08 10:48:17 -04:00
{
if ( ! Object - > HasAllFlags ( RF_Public ) )
{
UE_LOG ( LogPackageStoreOptimizer , Verbose , TEXT ( " Skipping script object: %s (!RF_Public) " ) , * Object - > GetFullName ( ) ) ;
return ;
}
2021-03-18 15:20:03 -04:00
FString OuterFullName ;
FPackageObjectIndex OuterCDOClassIndex ;
{
const FScriptObjectData * Outer = ScriptObjectsMap . Find ( OuterIndex ) ;
check ( Outer ) ;
OuterFullName = Outer - > FullName ;
OuterCDOClassIndex = Outer - > CDOClassIndex ;
}
2021-02-08 10:48:17 -04:00
FName ObjectName = Object - > GetFName ( ) ;
2021-03-18 15:20:03 -04:00
FString TempFullName = OuterFullName ;
2021-02-08 10:48:17 -04:00
TempFullName . AppendChar ( TEXT ( ' / ' ) ) ;
ObjectName . AppendString ( TempFullName ) ;
TempFullName . ToLowerInline ( ) ;
FPackageObjectIndex GlobalImportIndex = FPackageObjectIndex : : FromScriptPath ( TempFullName ) ;
FScriptObjectData * ScriptImport = ScriptObjectsMap . Find ( GlobalImportIndex ) ;
if ( ScriptImport )
{
UE_LOG ( LogPackageStoreOptimizer , Fatal , TEXT ( " Import name hash collision \" %s \" and \" %s " ) , * TempFullName , * ScriptImport - > FullName ) ;
}
2021-03-18 15:20:03 -04:00
FPackageObjectIndex CDOClassIndex = OuterCDOClassIndex ;
2021-02-08 10:48:17 -04:00
if ( CDOClassIndex . IsNull ( ) )
{
TCHAR NameBuffer [ FName : : StringBufferSize ] ;
uint32 Len = ObjectName . ToString ( NameBuffer ) ;
if ( FCString : : Strncmp ( NameBuffer , TEXT ( " Default__ " ) , 9 ) = = 0 )
{
2021-03-18 15:20:03 -04:00
FString CDOClassFullName = OuterFullName ;
2021-02-08 10:48:17 -04:00
CDOClassFullName . AppendChar ( TEXT ( ' / ' ) ) ;
CDOClassFullName . AppendChars ( NameBuffer + 9 , Len - 9 ) ;
CDOClassFullName . ToLowerInline ( ) ;
CDOClassIndex = FPackageObjectIndex : : FromScriptPath ( CDOClassFullName ) ;
}
}
ScriptImport = & ScriptObjectsMap . Add ( GlobalImportIndex ) ;
ScriptImport - > GlobalIndex = GlobalImportIndex ;
ScriptImport - > FullName = MoveTemp ( TempFullName ) ;
2021-03-18 15:20:03 -04:00
ScriptImport - > OuterIndex = OuterIndex ;
2021-02-08 10:48:17 -04:00
ScriptImport - > ObjectName = ObjectName ;
ScriptImport - > CDOClassIndex = CDOClassIndex ;
TArray < UObject * > InnerObjects ;
GetObjectsWithOuter ( Object , InnerObjects , /*bIncludeNestedObjects*/ false ) ;
for ( UObject * InnerObject : InnerObjects )
{
2021-10-12 21:21:22 -04:00
FindScriptObjectsRecursive ( GlobalImportIndex , InnerObject ) ;
2021-02-08 10:48:17 -04:00
}
} ;
2021-10-12 21:21:22 -04:00
void FPackageStoreOptimizer : : FindScriptObjects ( )
2021-02-08 10:48:17 -04:00
{
TArray < UPackage * > ScriptPackages ;
FindAllRuntimeScriptPackages ( ScriptPackages ) ;
TArray < UObject * > InnerObjects ;
for ( UPackage * Package : ScriptPackages )
{
FName ObjectName = Package - > GetFName ( ) ;
FString FullName = Package - > GetName ( ) ;
FullName . ToLowerInline ( ) ;
FPackageObjectIndex GlobalImportIndex = FPackageObjectIndex : : FromScriptPath ( FullName ) ;
FScriptObjectData * ScriptImport = ScriptObjectsMap . Find ( GlobalImportIndex ) ;
checkf ( ! ScriptImport , TEXT ( " Import name hash collision \" %s \" and \" %s " ) , * FullName , * ScriptImport - > FullName ) ;
ScriptImport = & ScriptObjectsMap . Add ( GlobalImportIndex ) ;
ScriptImport - > GlobalIndex = GlobalImportIndex ;
ScriptImport - > FullName = FullName ;
ScriptImport - > OuterIndex = FPackageObjectIndex ( ) ;
ScriptImport - > ObjectName = ObjectName ;
InnerObjects . Reset ( ) ;
GetObjectsWithOuter ( Package , InnerObjects , /*bIncludeNestedObjects*/ false ) ;
for ( UObject * InnerObject : InnerObjects )
{
2021-10-12 21:21:22 -04:00
FindScriptObjectsRecursive ( GlobalImportIndex , InnerObject ) ;
2021-02-08 10:48:17 -04:00
}
}
TotalScriptObjectCount = ScriptObjectsMap . Num ( ) ;
}
2021-06-15 16:38:03 -04:00
FIoBuffer FPackageStoreOptimizer : : CreateScriptObjectsBuffer ( ) const
2021-02-08 10:48:17 -04:00
{
TArray < FScriptObjectData > ScriptObjectsAsArray ;
ScriptObjectsMap . GenerateValueArray ( ScriptObjectsAsArray ) ;
Algo : : Sort ( ScriptObjectsAsArray , [ ] ( const FScriptObjectData & A , const FScriptObjectData & B )
{
return A . FullName < B . FullName ;
} ) ;
2021-06-15 16:38:03 -04:00
TArray < FScriptObjectEntry > ScriptObjectEntries ;
ScriptObjectEntries . Reserve ( ScriptObjectsAsArray . Num ( ) ) ;
2021-02-08 10:48:17 -04:00
FPackageStoreNameMapBuilder NameMapBuilder ;
NameMapBuilder . SetNameMapType ( FMappedName : : EType : : Global ) ;
for ( const FScriptObjectData & ImportData : ScriptObjectsAsArray )
{
NameMapBuilder . MarkNameAsReferenced ( ImportData . ObjectName ) ;
2021-06-15 16:38:03 -04:00
FScriptObjectEntry & Entry = ScriptObjectEntries . AddDefaulted_GetRef ( ) ;
2022-02-21 02:35:48 -05:00
Entry . Mapped = NameMapBuilder . MapName ( ImportData . ObjectName ) ;
2021-02-08 10:48:17 -04:00
Entry . GlobalIndex = ImportData . GlobalIndex ;
Entry . OuterIndex = ImportData . OuterIndex ;
Entry . CDOClassIndex = ImportData . CDOClassIndex ;
2021-06-15 16:38:03 -04:00
}
2021-02-08 10:48:17 -04:00
2021-06-15 16:38:03 -04:00
FLargeMemoryWriter ScriptObjectsArchive ( 0 , true ) ;
SaveNameBatch ( NameMapBuilder . GetNameMap ( ) , ScriptObjectsArchive ) ;
int32 NumScriptObjects = ScriptObjectEntries . Num ( ) ;
ScriptObjectsArchive < < NumScriptObjects ;
for ( FScriptObjectEntry & Entry : ScriptObjectEntries )
{
2021-02-08 10:48:17 -04:00
ScriptObjectsArchive < < Entry ;
}
2021-06-15 16:38:03 -04:00
int64 DataSize = ScriptObjectsArchive . TotalSize ( ) ;
return FIoBuffer ( FIoBuffer : : AssumeOwnership , ScriptObjectsArchive . ReleaseOwnership ( ) , DataSize ) ;
2021-02-08 10:48:17 -04:00
}
2021-09-15 10:39:23 -04:00
void FPackageStoreOptimizer : : LoadScriptObjectsBuffer ( const FIoBuffer & ScriptObjectsBuffer )
{
FLargeMemoryReader ScriptObjectsArchive ( ScriptObjectsBuffer . Data ( ) , ScriptObjectsBuffer . DataSize ( ) ) ;
2022-04-25 03:48:33 -04:00
TArray < FDisplayNameEntryId > NameMap = LoadNameBatch ( ScriptObjectsArchive ) ;
2021-09-15 10:39:23 -04:00
int32 NumScriptObjects ;
ScriptObjectsArchive < < NumScriptObjects ;
for ( int32 Index = 0 ; Index < NumScriptObjects ; + + Index )
{
2022-02-21 02:35:48 -05:00
FScriptObjectEntry Entry { } ;
2021-09-15 10:39:23 -04:00
ScriptObjectsArchive < < Entry ;
FScriptObjectData & ImportData = ScriptObjectsMap . Add ( Entry . GlobalIndex ) ;
2022-02-21 02:35:48 -05:00
FMappedName MappedName = Entry . Mapped ;
2022-04-25 03:48:33 -04:00
ImportData . ObjectName = NameMap [ MappedName . GetIndex ( ) ] . ToName ( MappedName . GetNumber ( ) ) ;
2021-09-15 10:39:23 -04:00
ImportData . GlobalIndex = Entry . GlobalIndex ;
ImportData . OuterIndex = Entry . OuterIndex ;
ImportData . CDOClassIndex = Entry . CDOClassIndex ;
}
}
2022-04-25 07:37:07 -04:00
FPackageStoreEntryResource FPackageStoreOptimizer : : CreatePackageStoreEntry ( const FPackageStorePackage * Package , const FPackageStorePackage * OptionalSegmentPackage ) const
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
FPackageStoreEntryResource Result ;
Result . Flags = Package - > bIsRedirected ? EPackageStoreEntryFlags : : Redirected : EPackageStoreEntryFlags : : None ;
Result . PackageName = Package - > Name ;
Result . SourcePackageName = Package - > SourceName ;
Result . Region = FName ( * Package - > Region ) ;
Result . ExportInfo . ExportCount = Package - > Exports . Num ( ) ;
Result . ExportInfo . ExportBundleCount = Package - > GraphData . ExportBundles . Num ( ) ;
2021-02-08 10:48:17 -04:00
Result . ImportedPackageIds = Package - > ImportedPackageIds ;
2021-06-10 09:36:47 -04:00
Result . ShaderMapHashes = Package - > ShaderMapHashes . Array ( ) ;
2022-05-05 17:43:49 -04:00
// Package->ShaderMapHashes is a TSet and is unsorted - we want this sorted as it's serialized
// in to the ContainerHeader, and if not sorted leads to staging non-determinism.
Algo : : Sort ( Result . ShaderMapHashes ) ;
2022-04-25 07:37:07 -04:00
if ( OptionalSegmentPackage )
{
Result . OptionalSegmentExportInfo . ExportCount = OptionalSegmentPackage - > Exports . Num ( ) ;
Result . OptionalSegmentExportInfo . ExportBundleCount = OptionalSegmentPackage - > GraphData . ExportBundles . Num ( ) ;
Result . OptionalSegmentImportedPackageIds = OptionalSegmentPackage - > ImportedPackageIds ;
}
2021-02-08 10:48:17 -04:00
return Result ;
}
2022-04-25 07:37:07 -04:00
FIoContainerHeader FPackageStoreOptimizer : : CreateContainerHeader ( const FIoContainerId & ContainerId , TArrayView < const FPackageStoreEntryResource > PackageStoreEntries , EContainerHeaderInclusionFilter InclusionFilter ) const
2021-02-08 10:48:17 -04:00
{
2022-04-25 07:37:07 -04:00
const bool bIncludeNonOptionalSegments = ( InclusionFilter & IncludeNonOptionalSegments ) > 0 ;
const bool bIncludeOptionalSegments = ( InclusionFilter & IncludeOptionalSegments ) > 0 ;
2021-09-28 04:00:33 -04:00
FIoContainerHeader Header ;
2021-02-08 10:48:17 -04:00
Header . ContainerId = ContainerId ;
2022-04-25 07:37:07 -04:00
const int32 NonOptionalSegmentStoreEntriesCount = bIncludeNonOptionalSegments ? PackageStoreEntries . Num ( ) : 0 ;
2021-02-08 10:48:17 -04:00
2022-04-25 07:37:07 -04:00
int32 OptionalSegmentStoreEntriesCount = 0 ;
if ( bIncludeOptionalSegments )
2021-02-08 10:48:17 -04:00
{
2022-04-25 07:37:07 -04:00
for ( const FPackageStoreEntryResource & Entry : PackageStoreEntries )
{
if ( Entry . OptionalSegmentExportInfo . ExportCount )
{
+ + OptionalSegmentStoreEntriesCount ;
}
}
}
struct FStoreEntriesWriter
{
const int32 StoreTocSize ;
FLargeMemoryWriter StoreTocArchive = FLargeMemoryWriter ( 0 , true ) ;
FLargeMemoryWriter StoreDataArchive = FLargeMemoryWriter ( 0 , true ) ;
void Flush ( TArray < uint8 > & OutputBuffer )
{
check ( StoreTocArchive . TotalSize ( ) = = StoreTocSize ) ;
if ( StoreTocSize )
{
const int32 StoreByteCount = StoreTocArchive . TotalSize ( ) + StoreDataArchive . TotalSize ( ) ;
OutputBuffer . AddUninitialized ( StoreByteCount ) ;
FBufferWriter PackageStoreArchive ( OutputBuffer . GetData ( ) , StoreByteCount ) ;
PackageStoreArchive . Serialize ( StoreTocArchive . GetData ( ) , StoreTocArchive . TotalSize ( ) ) ;
PackageStoreArchive . Serialize ( StoreDataArchive . GetData ( ) , StoreDataArchive . TotalSize ( ) ) ;
}
}
} ;
FStoreEntriesWriter StoreEntriesWriter
{
static_cast < int32 > ( NonOptionalSegmentStoreEntriesCount * sizeof ( FFilePackageStoreEntry ) )
} ;
FStoreEntriesWriter OptionalSegmentStoreEntriesWriter
{
static_cast < int32 > ( OptionalSegmentStoreEntriesCount * sizeof ( FFilePackageStoreEntry ) )
} ;
auto SerializePackageEntryCArrayHeader = [ ] ( FStoreEntriesWriter & Writer , int32 Count )
{
const int32 RemainingTocSize = Writer . StoreTocSize - Writer . StoreTocArchive . Tell ( ) ;
const int32 OffsetFromThis = RemainingTocSize + Writer . StoreDataArchive . Tell ( ) ;
2021-02-08 10:48:17 -04:00
uint32 ArrayNum = Count > 0 ? Count : 0 ;
uint32 OffsetToDataFromThis = ArrayNum > 0 ? OffsetFromThis : 0 ;
2022-04-25 07:37:07 -04:00
Writer . StoreTocArchive < < ArrayNum ;
Writer . StoreTocArchive < < OffsetToDataFromThis ;
2021-02-08 10:48:17 -04:00
} ;
2021-06-15 16:38:03 -04:00
TArray < const FPackageStoreEntryResource * > SortedPackageStoreEntries ;
SortedPackageStoreEntries . Reserve ( PackageStoreEntries . Num ( ) ) ;
for ( const FPackageStoreEntryResource & Entry : PackageStoreEntries )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
SortedPackageStoreEntries . Add ( & Entry ) ;
2021-02-08 10:48:17 -04:00
}
2021-06-15 16:38:03 -04:00
Algo : : Sort ( SortedPackageStoreEntries , [ ] ( const FPackageStoreEntryResource * A , const FPackageStoreEntryResource * B )
2021-02-08 10:48:17 -04:00
{
2021-06-15 16:38:03 -04:00
return A - > GetPackageId ( ) < B - > GetPackageId ( ) ;
2021-02-08 10:48:17 -04:00
} ) ;
2022-04-25 07:37:07 -04:00
Header . PackageIds . Reserve ( NonOptionalSegmentStoreEntriesCount ) ;
Header . OptionalSegmentPackageIds . Reserve ( OptionalSegmentStoreEntriesCount ) ;
2021-08-02 07:21:44 -04:00
FPackageStoreNameMapBuilder RedirectsNameMapBuilder ;
RedirectsNameMapBuilder . SetNameMapType ( FMappedName : : EType : : Container ) ;
2021-10-12 21:21:22 -04:00
TSet < FPackageId > AllLocalizedPackages ;
2021-06-15 16:38:03 -04:00
for ( const FPackageStoreEntryResource * Entry : SortedPackageStoreEntries )
2021-02-08 10:48:17 -04:00
{
2022-04-25 07:37:07 -04:00
if ( bIncludeOptionalSegments & & Entry - > OptionalSegmentExportInfo . ExportCount )
{
Header . OptionalSegmentPackageIds . Add ( Entry - > GetPackageId ( ) ) ;
FPackageStoreExportInfo OptionalSegmentExportInfo = Entry - > OptionalSegmentExportInfo ;
OptionalSegmentStoreEntriesWriter . StoreTocArchive < < OptionalSegmentExportInfo ;
const TArray < FPackageId > & OptionalSegmentImportedPackageIds = Entry - > OptionalSegmentImportedPackageIds ;
SerializePackageEntryCArrayHeader ( OptionalSegmentStoreEntriesWriter , OptionalSegmentImportedPackageIds . Num ( ) ) ;
for ( FPackageId OptionalSegmentImportedPackageId : OptionalSegmentImportedPackageIds )
{
check ( OptionalSegmentImportedPackageId . IsValid ( ) ) ;
OptionalSegmentStoreEntriesWriter . StoreDataArchive < < OptionalSegmentImportedPackageId ;
}
// ShaderMapHashes is N/A for optional segments
SerializePackageEntryCArrayHeader ( OptionalSegmentStoreEntriesWriter , 0 ) ;
}
if ( ! bIncludeNonOptionalSegments )
{
continue ;
}
2021-06-15 16:38:03 -04:00
Header . PackageIds . Add ( Entry - > GetPackageId ( ) ) ;
if ( Entry - > IsRedirected ( ) )
2021-02-08 10:48:17 -04:00
{
2021-08-02 07:21:44 -04:00
RedirectsNameMapBuilder . MarkNameAsReferenced ( Entry - > GetSourcePackageName ( ) ) ;
FMappedName MappedSourcePackageName = RedirectsNameMapBuilder . MapName ( Entry - > GetSourcePackageName ( ) ) ;
2021-09-14 06:08:53 -04:00
if ( ! Entry - > Region . IsNone ( ) )
2021-02-08 10:48:17 -04:00
{
2021-10-12 21:21:22 -04:00
if ( ! AllLocalizedPackages . Contains ( Entry - > GetSourcePackageId ( ) ) )
{
Header . LocalizedPackages . Add ( { Entry - > GetSourcePackageId ( ) , MappedSourcePackageName } ) ;
AllLocalizedPackages . Add ( Entry - > GetSourcePackageId ( ) ) ;
}
2021-02-08 10:48:17 -04:00
}
else
{
2021-08-02 07:21:44 -04:00
Header . PackageRedirects . Add ( { Entry - > GetSourcePackageId ( ) , Entry - > GetPackageId ( ) , MappedSourcePackageName } ) ;
2021-02-08 10:48:17 -04:00
}
}
// StoreEntries
2021-06-15 16:38:03 -04:00
FPackageStoreExportInfo ExportInfo = Entry - > ExportInfo ;
2022-04-25 07:37:07 -04:00
StoreEntriesWriter . StoreTocArchive < < ExportInfo ;
2021-08-23 10:50:32 -04:00
2021-02-08 10:48:17 -04:00
// ImportedPackages
2021-06-15 16:38:03 -04:00
const TArray < FPackageId > & ImportedPackageIds = Entry - > ImportedPackageIds ;
2022-04-25 07:37:07 -04:00
SerializePackageEntryCArrayHeader ( StoreEntriesWriter , ImportedPackageIds . Num ( ) ) ;
2021-02-08 10:48:17 -04:00
for ( FPackageId ImportedPackageId : ImportedPackageIds )
{
check ( ImportedPackageId . IsValid ( ) ) ;
2022-04-25 07:37:07 -04:00
StoreEntriesWriter . StoreDataArchive < < ImportedPackageId ;
2021-02-08 10:48:17 -04:00
}
2021-06-10 09:36:47 -04:00
// ShaderMapHashes
2021-06-15 16:38:03 -04:00
const TArray < FSHAHash > & ShaderMapHashes = Entry - > ShaderMapHashes ;
2022-04-25 07:37:07 -04:00
SerializePackageEntryCArrayHeader ( StoreEntriesWriter , ShaderMapHashes . Num ( ) ) ;
2021-06-10 09:36:47 -04:00
for ( const FSHAHash & ShaderMapHash : ShaderMapHashes )
{
2022-04-25 07:37:07 -04:00
StoreEntriesWriter . StoreDataArchive < < const_cast < FSHAHash & > ( ShaderMapHash ) ;
2021-06-10 09:36:47 -04:00
}
2021-02-08 10:48:17 -04:00
}
2021-08-02 07:21:44 -04:00
Header . RedirectsNameMap = RedirectsNameMapBuilder . GetNameMap ( ) ;
2021-02-08 10:48:17 -04:00
2022-04-25 07:37:07 -04:00
StoreEntriesWriter . Flush ( Header . StoreEntries ) ;
OptionalSegmentStoreEntriesWriter . Flush ( Header . OptionalSegmentStoreEntries ) ;
2021-02-08 10:48:17 -04:00
return Header ;
}