2021-10-01 09:30:43 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
2023-02-10 08:44:31 -05:00
# include "HAL/FileManager.h"
2021-10-01 09:30:43 -04:00
# include "HAL/IConsoleManager.h"
# include "Logging/LogMacros.h"
2022-08-09 10:47:23 -04:00
# include "Misc/PackageName.h"
2023-02-10 08:44:31 -05:00
# include "Misc/PackagePath.h"
2023-02-09 04:42:06 -05:00
# include "UObject/PackageFileSummary.h"
# include "UObject/PackageResourceManager.h"
2023-02-10 08:44:31 -05:00
# include "UObject/PackageTrailer.h"
2023-02-09 04:42:06 -05:00
2021-10-01 09:30:43 -04:00
namespace UE
{
# if WITH_EDITORONLY_DATA
2022-05-30 07:35:08 -04:00
FString BytesToString ( int64 SizeInBytes )
{
if ( SizeInBytes < ( 8 * 1024 ) )
{
return FString : : Printf ( TEXT ( " %4d bytes " ) , SizeInBytes ) ;
}
else if ( SizeInBytes < ( 1024 * 1024 ) )
{
2023-05-08 09:40:17 -04:00
double SizeInKb = static_cast < double > ( SizeInBytes ) / ( 1024.0 ) ;
2022-05-30 07:35:08 -04:00
return FString : : Printf ( TEXT ( " %.2f KB " ) , SizeInKb ) ;
}
else
{
2023-05-08 09:40:17 -04:00
double SizeInMB = static_cast < double > ( SizeInBytes ) / ( 1024.0 * 1024.0 ) ;
2022-05-30 07:35:08 -04:00
return FString : : Printf ( TEXT ( " %.2f MB " ) , SizeInMB ) ;
}
}
2023-02-09 04:42:06 -05:00
void LogPackageError ( FArchive * Ar , const TCHAR * DebugName )
{
if ( Ar = = nullptr )
{
2023-05-26 15:52:39 -04:00
UE_LOG ( LogVirtualization , Error , TEXT ( " Could not find the package file: '%s' " ) , DebugName ) ;
2023-02-09 04:42:06 -05:00
return ;
}
FPackageFileSummary Summary ;
* Ar < < Summary ;
if ( Ar - > IsError ( ) )
{
UE_LOG ( LogVirtualization , Error , TEXT ( " Could not find load the package summary from disk: '%s' " ) , DebugName ) ;
return ;
}
if ( Summary . Tag ! = PACKAGE_FILE_TAG )
{
UE_LOG ( LogVirtualization , Error , TEXT ( " Package summary seems to be corrupted: '%s' " ) , DebugName ) ;
return ;
}
int32 PackageVersion = Summary . GetFileVersionUE ( ) . ToValue ( ) ;
if ( PackageVersion > = ( int32 ) EUnrealEngineObjectUE5Version : : PAYLOAD_TOC )
{
UE_LOG ( LogVirtualization , Error , TEXT ( " Package trailer is missing from the package file: '%s' " ) , DebugName ) ;
return ;
}
2023-05-26 15:52:39 -04:00
UE_LOG ( LogVirtualization , Error , TEXT ( " Package is tool old (version %d) to have a package trailer (version %d): '%s' " ) , PackageVersion , int ( EUnrealEngineObjectUE5Version : : PAYLOAD_TOC ) , DebugName ) ;
2023-02-09 04:42:06 -05:00
}
void LogPackageError ( const FPackagePath & Path )
{
const FString DebugName = Path . GetPackageName ( ) ;
TUniquePtr < FArchive > PackageAr = IPackageResourceManager : : Get ( ) . OpenReadExternalResource ( EPackageExternalResource : : WorkspaceDomainFile , DebugName ) ;
LogPackageError ( PackageAr . Get ( ) , * DebugName ) ;
}
void LogPackageError ( const FString & Path )
{
TUniquePtr < FArchive > PackageAr ( IFileManager : : Get ( ) . CreateFileReader ( * Path ) ) ;
LogPackageError ( PackageAr . Get ( ) , * Path ) ;
}
2021-10-01 09:30:43 -04:00
/**
* This function is used to write information about package ' s payloads to the log file . This has no
* practical development use and should only be used for debugging purposes .
*
* @ param Args The function expects each arg to be a valid package path . Failure to provide a valid
* package path will result in errors being written to the log .
*/
2022-01-19 06:21:21 -05:00
void DumpPackagePayloadInfo ( const TArray < FString > & Args )
2021-10-01 09:30:43 -04:00
{
if ( Args . Num ( ) = = 0 )
{
UE_LOG ( LogVirtualization , Error , TEXT ( " Command 'DumpPackagePayloadInfo' called without any arguments " ) ) ;
return ;
}
for ( const FString & Arg : Args )
{
2022-08-17 06:36:41 -04:00
FString PathString ;
2021-10-01 09:30:43 -04:00
2022-08-17 06:36:41 -04:00
if ( FPackageName : : ParseExportTextPath ( Arg , nullptr /*OutClassName*/ , & PathString ) )
2022-08-09 10:47:23 -04:00
{
2022-08-17 06:36:41 -04:00
PathString = FPackageName : : ObjectPathToPackageName ( PathString ) ;
2022-08-09 10:47:23 -04:00
}
else
{
2022-08-17 06:36:41 -04:00
PathString = Arg ;
2022-08-09 10:47:23 -04:00
}
2022-08-17 06:36:41 -04:00
FPackageTrailer Trailer ;
FPackagePath Path ;
if ( FPackagePath : : TryFromMountedName ( PathString , Path ) )
{
2022-05-17 07:54:28 -04:00
if ( ! FPackageTrailer : : TryLoadFromPackage ( Path , Trailer ) )
2021-10-01 09:30:43 -04:00
{
2023-02-09 04:42:06 -05:00
LogPackageError ( Path ) ;
2021-10-01 09:30:43 -04:00
continue ;
}
2022-08-17 06:36:41 -04:00
}
else if ( IFileManager : : Get ( ) . FileExists ( * PathString ) )
{
// IF we couldn't turn it into a FPackagePath it could be a path to a package not under any current mount point.
// So for a final attempt we will see if we can find the file on disk and load the package trailer that way.
2022-05-17 07:54:28 -04:00
2022-08-17 06:36:41 -04:00
if ( ! FPackageTrailer : : TryLoadFromFile ( PathString , Trailer ) )
2021-10-01 09:30:43 -04:00
{
2023-02-09 04:42:06 -05:00
LogPackageError ( PathString ) ;
2022-08-17 06:36:41 -04:00
continue ;
}
2021-10-01 09:30:43 -04:00
}
else
{
UE_LOG ( LogVirtualization , Error , TEXT ( " Arg '%s' could not be converted to a valid package path " ) , * Arg ) ;
2022-08-17 06:36:41 -04:00
continue ;
}
TArray < FIoHash > LocalPayloadIds = Trailer . GetPayloads ( UE : : EPayloadStorageType : : Local ) ;
TArray < FIoHash > VirtualizedPayloadIds = Trailer . GetPayloads ( UE : : EPayloadStorageType : : Virtualized ) ;
UE_LOG ( LogVirtualization , Display , TEXT ( " " ) ) ; // Blank line to make the output easier to read
UE_LOG ( LogVirtualization , Display , TEXT ( " Package: '%s' has %d local and %d virtualized payloads " ) , * Path . GetDebugName ( ) , LocalPayloadIds . Num ( ) , VirtualizedPayloadIds . Num ( ) ) ;
if ( LocalPayloadIds . Num ( ) > 0 )
{
UE_LOG ( LogVirtualization , Display , TEXT ( " LocalPayloads: " ) ) ;
UE_LOG ( LogVirtualization , Display , TEXT ( " Index | %-40s | SizeOnDisk | FilterReason " ) , TEXT ( " PayloadIdentifier " ) ) ;
for ( int32 Index = 0 ; Index < LocalPayloadIds . Num ( ) ; + + Index )
{
FPayloadInfo Info = Trailer . GetPayloadInfo ( LocalPayloadIds [ Index ] ) ;
UE_LOG ( LogVirtualization , Display , TEXT ( " %02d | %s | %-10s | %s " ) ,
Index ,
* LexToString ( LocalPayloadIds [ Index ] ) ,
* BytesToString ( Info . CompressedSize ) ,
* LexToString ( Info . FilterFlags ) ) ;
}
}
if ( VirtualizedPayloadIds . Num ( ) > 0 )
{
UE_LOG ( LogVirtualization , Display , TEXT ( " VirtualizedPayloads: " ) ) ;
UE_LOG ( LogVirtualization , Display , TEXT ( " Index| \t %-40s| \t FilterReason " ) , TEXT ( " PayloadIdentifier " ) ) ;
for ( int32 Index = 0 ; Index < VirtualizedPayloadIds . Num ( ) ; + + Index )
{
FPayloadInfo Info = Trailer . GetPayloadInfo ( VirtualizedPayloadIds [ Index ] ) ;
UE_LOG ( LogVirtualization , Display , TEXT ( " %02d: | \t %s| \t %s " ) , Index , * LexToString ( VirtualizedPayloadIds [ Index ] ) , * LexToString ( Info . FilterFlags ) ) ;
}
2021-10-01 09:30:43 -04:00
}
}
}
/**
* Note that this command is only valid when ' WITH_EDITORONLY_DATA 1 ' as virtualized payloads are not
* expected to exist at runtime .
*/
static FAutoConsoleCommand CCmdDumpPayloadToc = FAutoConsoleCommand (
TEXT ( " DumpPackagePayloadInfo " ) ,
TEXT ( " Writes out information about a package's payloads to the log. " ) ,
2022-01-19 06:21:21 -05:00
FConsoleCommandWithArgsDelegate : : CreateStatic ( DumpPackagePayloadInfo ) ) ;
2021-10-01 09:30:43 -04:00
# endif //WITH_EDITORONLY_DATA
2023-05-26 15:52:39 -04:00
} // namespace UE