2020-12-02 14:38:01 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "Settings/ProjectPackagingSettings.h"
# include "Misc/App.h"
# include "Misc/ConfigCacheIni.h"
# include "Interfaces/IProjectManager.h"
# include "DesktopPlatformModule.h"
2020-12-02 20:43:06 -04:00
# include "DeveloperToolSettingsDelegates.h"
2022-01-28 10:06:34 -05:00
# include "InstalledPlatformInfo.h"
2020-12-02 14:38:01 -04:00
# define LOCTEXT_NAMESPACE "SettingsClasses"
/* UProjectPackagingSettings interface
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
const UProjectPackagingSettings : : FConfigurationInfo UProjectPackagingSettings : : ConfigurationInfo [ ( int ) EProjectPackagingBuildConfigurations : : PPBC_MAX ] =
{
/* PPBC_Debug */ { EBuildConfiguration : : Debug , LOCTEXT ( " DebugConfiguration " , " Debug " ) , LOCTEXT ( " DebugConfigurationTooltip " , " Package the game in Debug configuration " ) } ,
/* PPBC_DebugGame */ { EBuildConfiguration : : DebugGame , LOCTEXT ( " DebugGameConfiguration " , " DebugGame " ) , LOCTEXT ( " DebugGameConfigurationTooltip " , " Package the game in DebugGame configuration " ) } ,
/* PPBC_Development */ { EBuildConfiguration : : Development , LOCTEXT ( " DevelopmentConfiguration " , " Development " ) , LOCTEXT ( " DevelopmentConfigurationTooltip " , " Package the game in Development configuration " ) } ,
/* PPBC_Test */ { EBuildConfiguration : : Test , LOCTEXT ( " TestConfiguration " , " Test " ) , LOCTEXT ( " TestConfigurationTooltip " , " Package the game in Test configuration " ) } ,
/* PPBC_Shipping */ { EBuildConfiguration : : Shipping , LOCTEXT ( " ShippingConfiguration " , " Shipping " ) , LOCTEXT ( " ShippingConfigurationTooltip " , " Package the game in Shipping configuration " ) } ,
} ;
UProjectPackagingSettings : : UProjectPackagingSettings ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
{
}
void UProjectPackagingSettings : : PostInitProperties ( )
{
// Build code projects by default
Build = EProjectPackagingBuild : : IfProjectHasCode ;
FixCookingPaths ( ) ;
Super : : PostInitProperties ( ) ;
}
void UProjectPackagingSettings : : FixCookingPaths ( )
{
// Fix AlwaysCook/NeverCook paths to use content root
for ( FDirectoryPath & PathToFix : DirectoriesToAlwaysCook )
{
if ( ! PathToFix . Path . IsEmpty ( ) & & ! PathToFix . Path . StartsWith ( TEXT ( " / " ) , ESearchCase : : CaseSensitive ) )
{
PathToFix . Path = FString : : Printf ( TEXT ( " /Game/%s " ) , * PathToFix . Path ) ;
}
}
for ( FDirectoryPath & PathToFix : DirectoriesToNeverCook )
{
if ( ! PathToFix . Path . IsEmpty ( ) & & ! PathToFix . Path . StartsWith ( TEXT ( " / " ) , ESearchCase : : CaseSensitive ) )
{
PathToFix . Path = FString : : Printf ( TEXT ( " /Game/%s " ) , * PathToFix . Path ) ;
}
}
for ( FDirectoryPath & PathToFix : TestDirectoriesToNotSearch )
{
if ( ! PathToFix . Path . IsEmpty ( ) & & ! PathToFix . Path . StartsWith ( TEXT ( " / " ) , ESearchCase : : CaseSensitive ) )
{
PathToFix . Path = FString : : Printf ( TEXT ( " /Game/%s " ) , * PathToFix . Path ) ;
}
}
}
# if WITH_EDITOR
void UProjectPackagingSettings : : PostEditChangeProperty ( FPropertyChangedEvent & PropertyChangedEvent )
{
Super : : PostEditChangeProperty ( PropertyChangedEvent ) ;
const FName Name = ( PropertyChangedEvent . MemberProperty ! = nullptr )
? PropertyChangedEvent . MemberProperty - > GetFName ( )
: NAME_None ;
if ( Name = = FName ( TEXT ( " DirectoriesToAlwaysCook " ) ) | | Name = = FName ( TEXT ( " DirectoriesToNeverCook " ) ) | | Name = = FName ( TEXT ( " TestDirectoriesToNotSearch " ) ) | | Name = = NAME_None )
{
// We need to fix paths for no name updates to catch the reloadconfig call
FixCookingPaths ( ) ;
}
else if ( Name = = FName ( ( TEXT ( " StagingDirectory " ) ) ) )
{
// fix up path
FString Path = StagingDirectory . Path ;
FPaths : : MakePathRelativeTo ( Path , FPlatformProcess : : BaseDir ( ) ) ;
StagingDirectory . Path = Path ;
}
else if ( Name = = FName ( TEXT ( " ForDistribution " ) ) )
{
if ( ForDistribution & & BuildConfiguration ! = EProjectPackagingBuildConfigurations : : PPBC_Shipping )
{
BuildConfiguration = EProjectPackagingBuildConfigurations : : PPBC_Shipping ;
// force serialization for "Build COnfiguration"
UpdateSinglePropertyInConfigFile ( GetClass ( ) - > FindPropertyByName ( GET_MEMBER_NAME_CHECKED ( UProjectPackagingSettings , BuildConfiguration ) ) , GetDefaultConfigFilename ( ) ) ;
}
}
else if ( Name = = FName ( TEXT ( " bGenerateChunks " ) ) )
{
if ( bGenerateChunks )
{
UsePakFile = true ;
}
}
else if ( Name = = FName ( TEXT ( " UsePakFile " ) ) )
{
if ( ! UsePakFile )
{
bGenerateChunks = false ;
bBuildHttpChunkInstallData = false ;
}
}
else if ( Name = = FName ( TEXT ( " bBuildHTTPChunkInstallData " ) ) )
{
if ( bBuildHttpChunkInstallData )
{
UsePakFile = true ;
bGenerateChunks = true ;
//Ensure data is something valid
if ( HttpChunkInstallDataDirectory . Path . IsEmpty ( ) )
{
auto CloudInstallDir = FPaths : : ConvertRelativePathToFull ( FPaths : : GetPath ( FPaths : : GetProjectFilePath ( ) ) ) / TEXT ( " ChunkInstall " ) ;
HttpChunkInstallDataDirectory . Path = CloudInstallDir ;
}
if ( HttpChunkInstallDataVersion . IsEmpty ( ) )
{
HttpChunkInstallDataVersion = TEXT ( " release1 " ) ;
}
}
}
else if ( Name = = FName ( ( TEXT ( " ApplocalPrerequisitesDirectory " ) ) ) )
{
// If a variable is already in use, assume the user knows what they are doing and don't modify the path
if ( ! ApplocalPrerequisitesDirectory . Path . Contains ( " $( " ) )
{
// Try making the path local to either project or engine directories.
FString EngineRootedPath = ApplocalPrerequisitesDirectory . Path ;
FString EnginePath = FPaths : : ConvertRelativePathToFull ( FPaths : : GetPath ( FPaths : : EngineDir ( ) ) ) + " / " ;
FPaths : : MakePathRelativeTo ( EngineRootedPath , * EnginePath ) ;
if ( FPaths : : IsRelative ( EngineRootedPath ) )
{
ApplocalPrerequisitesDirectory . Path = " $(EngineDir)/ " + EngineRootedPath ;
return ;
}
FString ProjectRootedPath = ApplocalPrerequisitesDirectory . Path ;
FString ProjectPath = FPaths : : ConvertRelativePathToFull ( FPaths : : GetPath ( FPaths : : GetProjectFilePath ( ) ) ) + " / " ;
FPaths : : MakePathRelativeTo ( ProjectRootedPath , * ProjectPath ) ;
if ( FPaths : : IsRelative ( EngineRootedPath ) )
{
ApplocalPrerequisitesDirectory . Path = " $(ProjectDir)/ " + ProjectRootedPath ;
return ;
}
}
}
}
bool UProjectPackagingSettings : : CanEditChange ( const FProperty * InProperty ) const
{
return Super : : CanEditChange ( InProperty ) ;
}
# endif
TArray < EProjectPackagingBuildConfigurations > UProjectPackagingSettings : : GetValidPackageConfigurations ( )
{
// Check if the project has code
FProjectStatus ProjectStatus ;
bool bHasCode = IProjectManager : : Get ( ) . QueryStatusForCurrentProject ( ProjectStatus ) & & ProjectStatus . bCodeBasedProject ;
2022-01-28 10:06:34 -05:00
EProjectType ProjectType = bHasCode ? EProjectType : : Code : EProjectType : : Content ;
2020-12-02 14:38:01 -04:00
// If if does, find all the targets
const TArray < FTargetInfo > * Targets = nullptr ;
if ( bHasCode )
{
Targets = & ( FDesktopPlatformModule : : Get ( ) - > GetTargetsForCurrentProject ( ) ) ;
}
// Set up all the configurations
TArray < EProjectPackagingBuildConfigurations > Configurations ;
for ( int32 Idx = 0 ; Idx < ( int ) EProjectPackagingBuildConfigurations : : PPBC_MAX ; Idx + + )
{
EProjectPackagingBuildConfigurations PackagingConfiguration = ( EProjectPackagingBuildConfigurations ) Idx ;
// Check the target type is valid
const UProjectPackagingSettings : : FConfigurationInfo & Info = UProjectPackagingSettings : : ConfigurationInfo [ Idx ] ;
2022-01-28 10:06:34 -05:00
if ( FInstalledPlatformInfo : : Get ( ) . IsValid ( TOptional < EBuildTargetType > ( ) , TOptional < FString > ( ) , Info . Configuration , ProjectType , EInstalledPlatformState : : Downloaded ) )
2020-12-02 14:38:01 -04:00
{
2022-01-28 10:06:34 -05:00
Configurations . Add ( PackagingConfiguration ) ;
2020-12-02 14:38:01 -04:00
}
}
return Configurations ;
}
2022-01-28 10:06:34 -05:00
2022-01-19 18:54:41 -05:00
static const FTargetInfo * FindBestTargetInfo ( const FString & TargetName , bool bContentOnlyUsesEngineTargets , bool * bOutIsProjectTarget = nullptr )
2020-12-02 14:38:01 -04:00
{
2022-01-19 18:54:41 -05:00
bool bUseEngineTargets = false ;
if ( bContentOnlyUsesEngineTargets )
2020-12-02 14:38:01 -04:00
{
2022-01-19 18:54:41 -05:00
// Collect build targets. Content-only projects use Engine targets.
FProjectStatus ProjectStatus ;
bUseEngineTargets = ! ( IProjectManager : : Get ( ) . QueryStatusForCurrentProject ( ProjectStatus ) & & ProjectStatus . bCodeBasedProject ) ;
}
if ( bOutIsProjectTarget ! = nullptr )
{
* bOutIsProjectTarget = ! bUseEngineTargets ;
2021-08-26 15:21:50 -04:00
}
2021-09-01 13:08:18 -04:00
IDesktopPlatform * DesktopPlatform = FDesktopPlatformModule : : Get ( ) ;
2022-01-19 18:54:41 -05:00
const TArray < FTargetInfo > & TargetsRef = bUseEngineTargets ? DesktopPlatform - > GetTargetsForProject ( FString ( ) ) : DesktopPlatform - > GetTargetsForCurrentProject ( ) ;
2021-09-01 13:08:18 -04:00
2021-08-26 15:21:50 -04:00
const FTargetInfo * DefaultGameTarget = nullptr ;
const FTargetInfo * DefaultClientTarget = nullptr ;
2021-09-01 13:08:18 -04:00
for ( const FTargetInfo & Target : TargetsRef )
2021-08-26 15:21:50 -04:00
{
2022-01-19 18:54:41 -05:00
if ( Target . Name = = TargetName )
2021-08-26 15:21:50 -04:00
{
return & Target ;
}
else if ( Target . Type = = EBuildTargetType : : Game & & ( DefaultGameTarget = = nullptr | | Target . Name < DefaultGameTarget - > Name ) )
2020-12-02 14:38:01 -04:00
{
DefaultGameTarget = & Target ;
}
else if ( Target . Type = = EBuildTargetType : : Client & & ( DefaultClientTarget = = nullptr | | Target . Name < DefaultClientTarget - > Name ) )
{
DefaultClientTarget = & Target ;
}
}
return ( DefaultGameTarget ! = nullptr ) ? DefaultGameTarget : DefaultClientTarget ;
2022-01-19 18:54:41 -05:00
2020-12-02 14:38:01 -04:00
}
2022-01-19 18:54:41 -05:00
const FTargetInfo * UProjectPackagingSettings : : GetBuildTargetInfo ( ) const
{
return FindBestTargetInfo ( BuildTarget , false ) ;
}
const FTargetInfo * UProjectPackagingSettings : : GetBuildTargetInfoForPlatform ( FName PlatformName , bool & bOutIsProjectTarget ) const
{
return FindBestTargetInfo ( GetBuildTargetForPlatform ( PlatformName ) , true , & bOutIsProjectTarget ) ;
}
const FTargetInfo * UProjectPackagingSettings : : GetLaunchOnTargetInfo ( ) const
{
return FindBestTargetInfo ( LaunchOnTarget , true ) ;
}
2020-12-02 14:38:01 -04:00
EProjectPackagingBuildConfigurations UProjectPackagingSettings : : GetBuildConfigurationForPlatform ( FName PlatformName ) const
{
const EProjectPackagingBuildConfigurations * Value = PerPlatformBuildConfig . Find ( PlatformName ) ;
2021-06-15 15:14:23 -04:00
// PPBC_MAX defines the default project setting case and should be handled accordingly.
return Value = = nullptr ? EProjectPackagingBuildConfigurations : : PPBC_MAX : * Value ;
2020-12-02 14:38:01 -04:00
}
void UProjectPackagingSettings : : SetBuildConfigurationForPlatform ( FName PlatformName , EProjectPackagingBuildConfigurations Configuration )
{
2021-10-27 15:14:40 -04:00
if ( Configuration = = EProjectPackagingBuildConfigurations : : PPBC_MAX )
2021-06-15 15:14:23 -04:00
{
2021-10-27 15:14:40 -04:00
PerPlatformBuildConfig . Remove ( PlatformName ) ;
}
else
{
PerPlatformBuildConfig . Add ( PlatformName , Configuration ) ;
2021-06-15 15:14:23 -04:00
}
2020-12-02 14:38:01 -04:00
}
2021-06-15 15:14:23 -04:00
FName UProjectPackagingSettings : : GetTargetFlavorForPlatform ( FName FlavorName ) const
2020-12-02 14:38:01 -04:00
{
2021-06-15 15:14:23 -04:00
const FName * Value = PerPlatformTargetFlavorName . Find ( FlavorName ) ;
// the flavor name is also the name of the vanilla info
return Value = = nullptr ? FlavorName : * Value ;
}
void UProjectPackagingSettings : : SetTargetFlavorForPlatform ( FName PlatformName , FName TargetFlavorName )
{
PerPlatformTargetFlavorName . Add ( PlatformName , TargetFlavorName ) ;
}
FString UProjectPackagingSettings : : GetBuildTargetForPlatform ( FName PlatformName ) const
{
const FString * Value = PerPlatformBuildTarget . Find ( PlatformName ) ;
// empty string defines the default project setting case and should be handled accordingly.
return Value = = nullptr ? " " : * Value ;
}
void UProjectPackagingSettings : : SetBuildTargetForPlatform ( FName PlatformName , FString BuildTargetName )
{
2021-10-27 15:14:40 -04:00
if ( BuildTargetName . IsEmpty ( ) )
{
PerPlatformBuildTarget . Remove ( PlatformName ) ;
}
else
{
PerPlatformBuildTarget . Add ( PlatformName , BuildTargetName ) ;
}
2020-12-02 14:38:01 -04:00
}
2021-10-27 15:14:40 -04:00
# undef LOCTEXT_NAMESPACE