Add PluginUtils::FindLoadedPlugin

PluginUtils::LoadPlugin improvements and API cleanup:
- Add SynchronousAssetsScan and OutAlreadyLoaded params
- Make all loading options false by default (caller opts-in on whatever it wants instead of opting out on some)
- Put OutFailReason in the loading param struct
- Deprecate MountPlugin API and rename it LoadPlugin to mirror UnloadPlugin terminology
#rb Rex.Hill
#preflight 61a8fc58e8314ee7b598f55d

#ROBOMERGE-AUTHOR: dave.belanger
#ROBOMERGE-SOURCE: CL 18358835 via CL 18364441 via CL 18364493 via CL 18364530 via CL 18434167 via CL 18435484
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v897-18405271)

[CL 18436249 by dave belanger in ue5-release-engine-test branch]
This commit is contained in:
dave belanger
2021-12-10 18:33:00 -05:00
parent 738cf245ec
commit e59338fcbb
11 changed files with 488 additions and 108 deletions

View File

@@ -33,7 +33,19 @@ namespace PluginUtils
// The text macro to replace with the actual plugin name when copying files
const FString PLUGIN_NAME = TEXT("PLUGIN_NAME");
bool CopyPluginTemplateFolder(const TCHAR* DestinationDirectory, const TCHAR* Source, const FString& PluginName, FText& FailReason, TArray<FString>& InOutFilePathsWritten)
PRAGMA_DISABLE_DEPRECATION_WARNINGS
FPluginUtils::FLoadPluginParams ConvertToLoadPluginParams(const FPluginUtils::FMountPluginParams& MountParams, FText* FailReason)
{
FPluginUtils::FLoadPluginParams LoadParams;
LoadParams.bSelectInContentBrowser = MountParams.bSelectInContentBrowser;
LoadParams.bEnablePluginInProject = MountParams.bEnablePluginInProject;
LoadParams.bUpdateProjectPluginSearchPath = MountParams.bUpdateProjectPluginSearchPath;
LoadParams.OutFailReason = FailReason;
return LoadParams;
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
bool CopyPluginTemplateFolder(const TCHAR* DestinationDirectory, const TCHAR* Source, const FString& PluginName, TArray<FString>& InOutFilePathsWritten, FText* OutFailReason = nullptr)
{
check(DestinationDirectory);
check(Source);
@@ -49,14 +61,20 @@ namespace PluginUtils
// Does Source dir exist?
if (!PlatformFile.DirectoryExists(*SourceDir))
{
FailReason = FText::Format(LOCTEXT("InvalidPluginTemplateFolder", "Plugin template folder doesn't exist\n{0}"), FText::FromString(FPaths::ConvertRelativePathToFull(SourceDir)));
if (OutFailReason)
{
*OutFailReason = FText::Format(LOCTEXT("InvalidPluginTemplateFolder", "Plugin template folder doesn't exist\n{0}"), FText::FromString(FPaths::ConvertRelativePathToFull(SourceDir)));
}
return false;
}
// Destination directory exists already or can be created ?
if (!PlatformFile.DirectoryExists(*DestDir) && !PlatformFile.CreateDirectoryTree(*DestDir))
{
FailReason = FText::Format(LOCTEXT("FailedToCreateDestinationFolder", "Failed to create destination folder\n{0}"), FText::FromString(FPaths::ConvertRelativePathToFull(DestDir)));
if (OutFailReason)
{
*OutFailReason = FText::Format(LOCTEXT("FailedToCreateDestinationFolder", "Failed to create destination folder\n{0}"), FText::FromString(FPaths::ConvertRelativePathToFull(DestDir)));
}
return false;
}
@@ -70,16 +88,16 @@ namespace PluginUtils
TArray<FString> NameReplacementFileTypes;
TArray<FString> IgnoredFileTypes;
TArray<FString> CopyUnmodifiedFileTypes;
FText& FailReason;
TArray<FString>& FilePathsWritten;
FText* FailReason;
FCopyPluginFilesAndDirs(IPlatformFile& InPlatformFile, const TCHAR* InSourceRoot, const TCHAR* InDestRoot, const FString& InPluginName, FText& InFailReason, TArray<FString>& InFilePathsWritten)
FCopyPluginFilesAndDirs(IPlatformFile& InPlatformFile, const TCHAR* InSourceRoot, const TCHAR* InDestRoot, const FString& InPluginName, TArray<FString>& InFilePathsWritten, FText* InFailReason)
: PlatformFile(InPlatformFile)
, SourceRoot(InSourceRoot)
, DestRoot(InDestRoot)
, PluginName(InPluginName)
, FailReason(InFailReason)
, FilePathsWritten(InFilePathsWritten)
, FailReason(InFailReason)
{
// Which file types we want to replace instances of PLUGIN_NAME with the new Plugin Name
NameReplacementFileTypes.Add(TEXT("cs"));
@@ -111,7 +129,10 @@ namespace PluginUtils
// create new directory structure
if (!PlatformFile.CreateDirectoryTree(*NewName) && !PlatformFile.DirectoryExists(*NewName))
{
FailReason = FText::Format(LOCTEXT("FailedToCreatePluginSubFolder", "Failed to create plugin subfolder\n{0}"), FText::FromString(FPaths::ConvertRelativePathToFull(NewName)));
if (FailReason)
{
*FailReason = FText::Format(LOCTEXT("FailedToCreatePluginSubFolder", "Failed to create plugin subfolder\n{0}"), FText::FromString(FPaths::ConvertRelativePathToFull(NewName)));
}
return false;
}
}
@@ -142,7 +163,10 @@ namespace PluginUtils
FString OutFileContents;
if (!FFileHelper::LoadFileToString(OutFileContents, FilenameOrDirectory))
{
FailReason = FText::Format(LOCTEXT("FailedToReadPluginTemplateFile", "Failed to read plugin template file\n{0}"), FText::FromString(FPaths::ConvertRelativePathToFull(FilenameOrDirectory)));
if (FailReason)
{
*FailReason = FText::Format(LOCTEXT("FailedToReadPluginTemplateFile", "Failed to read plugin template file\n{0}"), FText::FromString(FPaths::ConvertRelativePathToFull(FilenameOrDirectory)));
}
return false;
}
@@ -157,7 +181,10 @@ namespace PluginUtils
if (!FFileHelper::SaveStringToFile(OutFileContents, *NewName))
{
FailReason = FText::Format(LOCTEXT("FailedToWritePluginFile", "Failed to write plugin file\n{0}"), FText::FromString(FPaths::ConvertRelativePathToFull(NewName)));
if (FailReason)
{
*FailReason = FText::Format(LOCTEXT("FailedToWritePluginFile", "Failed to write plugin file\n{0}"), FText::FromString(FPaths::ConvertRelativePathToFull(NewName)));
}
return false;
}
}
@@ -167,7 +194,10 @@ namespace PluginUtils
if (!PlatformFile.CopyFile(*NewName, FilenameOrDirectory))
{
// Not all files could be copied
FailReason = FText::Format(LOCTEXT("FailedToCopyPluginTemplateFile", "Failed to copy plugin template file\nFrom: {0}\nTo: {1}"), FText::FromString(FPaths::ConvertRelativePathToFull(FilenameOrDirectory)), FText::FromString(FPaths::ConvertRelativePathToFull(NewName)));
if (FailReason)
{
*FailReason = FText::Format(LOCTEXT("FailedToCopyPluginTemplateFile", "Failed to copy plugin template file\nFrom: {0}\nTo: {1}"), FText::FromString(FPaths::ConvertRelativePathToFull(FilenameOrDirectory)), FText::FromString(FPaths::ConvertRelativePathToFull(NewName)));
}
return false;
}
}
@@ -179,7 +209,7 @@ namespace PluginUtils
};
// copy plugin files and directories visitor
FCopyPluginFilesAndDirs CopyFilesAndDirs(PlatformFile, *SourceDir, *DestDir, PluginName, FailReason, InOutFilePathsWritten);
FCopyPluginFilesAndDirs CopyFilesAndDirs(PlatformFile, *SourceDir, *DestDir, PluginName, InOutFilePathsWritten, OutFailReason);
// create all files subdirectories and files in subdirectories!
return PlatformFile.IterateDirectoryRecursively(*SourceDir, CopyFilesAndDirs);
@@ -232,7 +262,7 @@ namespace PluginUtils
if (FilesToScan.Num() > 0)
{
IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(AssetRegistryConstants::ModuleName).Get();
AssetRegistry.ScanFilesSynchronous(FilesToScan);
for (const FString& File : FilesToScan)
@@ -274,19 +304,17 @@ namespace PluginUtils
}
}
TSharedPtr<IPlugin> MountPluginInternal(const FString& PluginName, const FString& PluginLocation, const FPluginUtils::FMountPluginParams& MountParams, FText& FailReason, const bool bIsNewPlugin)
TSharedPtr<IPlugin> LoadPluginInternal(const FString& PluginName, const FString& PluginLocation, const FString& PluginFilePath, FPluginUtils::FLoadPluginParams& LoadParams, const bool bIsNewPlugin)
{
ensure(!PluginLocation.IsEmpty());
LoadParams.bOutAlreadyLoaded = false;
const FString PluginFilePath = FPluginUtils::GetPluginFilePath(PluginLocation, PluginName, /*bFullPath*/ true);
if (MountParams.bUpdateProjectPluginSearchPath)
if (LoadParams.bUpdateProjectPluginSearchPath)
{
FPluginUtils::AddToPluginSearchPathIfNeeded(PluginLocation, /*bRefreshPlugins=*/true, /*bUpdateProjectFile=*/true);
}
else
{
if (!IPluginManager::Get().AddToPluginsList(PluginFilePath, &FailReason))
if (!IPluginManager::Get().AddToPluginsList(PluginFilePath, LoadParams.OutFailReason))
{
return nullptr;
}
@@ -296,48 +324,83 @@ namespace PluginUtils
TSharedPtr<IPlugin> Plugin = IPluginManager::Get().FindPlugin(PluginName);
if (!Plugin)
{
FailReason = FText::Format(LOCTEXT("FailedToRegisterPlugin", "Failed to register plugin\n{0}"), FText::FromString(FPluginUtils::GetPluginFilePath(PluginLocation, PluginName, /*bFullPath*/ true)));
if (LoadParams.OutFailReason)
{
*LoadParams.OutFailReason = FText::Format(LOCTEXT("FailedToRegisterPlugin", "Failed to register plugin\n{0}"), FText::FromString(PluginFilePath));
}
return nullptr;
}
// Double check the path matches
if (!FPaths::IsSamePath(Plugin->GetDescriptorFileName(), PluginFilePath))
{
const FString PluginFilePathFull = FPaths::ConvertRelativePathToFull(Plugin->GetDescriptorFileName());
FailReason = FText::Format(LOCTEXT("PluginNameAlreadyUsed", "There's already a plugin named {0} at this location:\n{1}"), FText::FromString(PluginName), FText::FromString(PluginFilePathFull));
if (LoadParams.OutFailReason)
{
const FString PluginFilePathFull = FPaths::ConvertRelativePathToFull(Plugin->GetDescriptorFileName());
*LoadParams.OutFailReason = FText::Format(LOCTEXT("PluginNameAlreadyUsed", "There's already a plugin named {0} at this location:\n{1}"), FText::FromString(PluginName), FText::FromString(PluginFilePathFull));
}
return nullptr;
}
const FString PluginRootFolder = Plugin->CanContainContent() ? Plugin->GetMountedAssetPath() : FString();
LoadParams.bOutAlreadyLoaded = !bIsNewPlugin && Plugin->IsEnabled() && (PluginRootFolder.IsEmpty() || FPackageName::MountPointExists(PluginRootFolder));
// Enable this plugin in the project
if (MountParams.bEnablePluginInProject && !IProjectManager::Get().SetPluginEnabled(PluginName, true, FailReason))
if (LoadParams.bEnablePluginInProject)
{
FailReason = FText::Format(LOCTEXT("FailedToEnablePluginInProject", "Failed to enable plugin in current project\n{0}"), FailReason);
return nullptr;
FText FailReason;
if (!IProjectManager::Get().SetPluginEnabled(PluginName, true, FailReason))
{
if (LoadParams.OutFailReason)
{
*LoadParams.OutFailReason = FText::Format(LOCTEXT("FailedToEnablePluginInProject", "Failed to enable plugin in current project\n{0}"), FailReason);
}
return nullptr;
}
}
// Mount the new plugin (mount content folder if any and load modules if any)
if (bIsNewPlugin)
if (!LoadParams.bOutAlreadyLoaded)
{
IPluginManager::Get().MountNewlyCreatedPlugin(PluginName);
}
else
{
IPluginManager::Get().MountExplicitlyLoadedPlugin(PluginName);
// Mount the new plugin (mount content folder if any and load modules if any)
if (bIsNewPlugin)
{
IPluginManager::Get().MountNewlyCreatedPlugin(PluginName);
}
else
{
IPluginManager::Get().MountExplicitlyLoadedPlugin(PluginName);
}
if (!Plugin->IsEnabled())
{
if (LoadParams.OutFailReason)
{
*LoadParams.OutFailReason = FText::Format(LOCTEXT("FailedToEnablePlugin", "Failed to enable plugin because it is not configured as bExplicitlyLoaded=true\n{0}"), FText::FromString(PluginFilePath));
}
return nullptr;
}
}
if (!Plugin->IsEnabled())
{
FailReason = FText::Format(LOCTEXT("FailedToEnablePlugin", "Failed to enable plugin because it is not configured as bExplicitlyLoaded=true\n{0}"), FText::FromString(FPluginUtils::GetPluginFilePath(PluginLocation, PluginName, /*bFullPath*/ true)));
return nullptr;
}
const bool bSelectInContentBrowser = LoadParams.bSelectInContentBrowser && !IsRunningCommandlet();
// Select plugin Content folder in content browser
if (MountParams.bSelectInContentBrowser && Plugin->CanContainContent() && !IsRunningCommandlet())
if ((bSelectInContentBrowser || LoadParams.bSynchronousAssetsScan) && !PluginRootFolder.IsEmpty() && (LoadParams.bOutAlreadyLoaded || FPackageName::MountPointExists(PluginRootFolder)))
{
IContentBrowserSingleton& ContentBrowser = FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser").Get();
const bool bIsEnginePlugin = FPaths::IsUnderDirectory(PluginLocation, FPaths::EnginePluginsDir());
ContentBrowser.ForceShowPluginContent(bIsEnginePlugin);
ContentBrowser.SetSelectedPaths({ Plugin->GetMountedAssetPath() }, /*bNeedsRefresh*/ true);
if (LoadParams.bSynchronousAssetsScan)
{
// Scan plugin assets
IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(AssetRegistryConstants::ModuleName).Get();
AssetRegistry.ScanPathsSynchronous({ PluginRootFolder }, /*bForceRescan=*/ true);
}
if (bSelectInContentBrowser)
{
// Select plugin root folder in content browser
IContentBrowserSingleton& ContentBrowser = FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser").Get();
const bool bIsEnginePlugin = FPaths::IsUnderDirectory(PluginLocation, FPaths::EnginePluginsDir());
ContentBrowser.ForceShowPluginContent(bIsEnginePlugin);
ContentBrowser.SetSelectedPaths({ PluginRootFolder }, /*bNeedsRefresh*/ true);
}
}
return Plugin;
@@ -388,7 +451,7 @@ FString FPluginUtils::GetPluginResourcesFolder(const FString& PluginLocation, co
return PluginResourcesFolder;
}
TSharedPtr<IPlugin> FPluginUtils::CreateAndMountNewPlugin(const FString& PluginName, const FString& PluginLocation, const FNewPluginParams& CreationParams, const FMountPluginParams& MountParams, FText& FailReason)
TSharedPtr<IPlugin> FPluginUtils::CreateAndLoadNewPlugin(const FString& PluginName, const FString& PluginLocation, const FNewPluginParams& CreationParams, FLoadPluginParams& LoadParams)
{
FNewPluginParamsWithDescriptor ExCreationParams;
ExCreationParams.PluginIconPath = CreationParams.PluginIconPath;
@@ -411,31 +474,40 @@ TSharedPtr<IPlugin> FPluginUtils::CreateAndMountNewPlugin(const FString& PluginN
ExCreationParams.Descriptor.Modules.Add(FModuleDescriptor(*PluginName, CreationParams.ModuleDescriptorType, CreationParams.LoadingPhase));
}
return CreateAndMountNewPlugin(PluginName, PluginLocation, ExCreationParams, MountParams, FailReason);
return CreateAndLoadNewPlugin(PluginName, PluginLocation, ExCreationParams, LoadParams);
}
TSharedPtr<IPlugin> FPluginUtils::CreateAndMountNewPlugin(const FString& PluginName, const FString& PluginLocation, const FNewPluginParamsWithDescriptor& CreationParams, const FMountPluginParams& MountParams, FText& FailReason)
TSharedPtr<IPlugin> FPluginUtils::CreateAndLoadNewPlugin(const FString& PluginName, const FString& PluginLocation, const FNewPluginParamsWithDescriptor& CreationParams, FLoadPluginParams& LoadParams)
{
// Early validations on new plugin params
if (PluginName.IsEmpty())
{
FailReason = LOCTEXT("CreateNewPluginParam_NoPluginName", "Missing plugin name");
if (LoadParams.OutFailReason)
{
*LoadParams.OutFailReason = LOCTEXT("CreateNewPluginParam_NoPluginName", "Missing plugin name");
}
return nullptr;
}
if (PluginLocation.IsEmpty())
{
FailReason = LOCTEXT("CreateNewPluginParam_NoPluginLocation", "Missing plugin location");
if (LoadParams.OutFailReason)
{
*LoadParams.OutFailReason = LOCTEXT("CreateNewPluginParam_NoPluginLocation", "Missing plugin location");
}
return nullptr;
}
if ((CreationParams.Descriptor.Modules.Num() > 0) && (CreationParams.TemplateFolders.Num() == 0))
{
FailReason = LOCTEXT("CreateNewPluginParam_NoTemplateFolder", "A template folder must be specified to create a plugin with code");
if (LoadParams.OutFailReason)
{
*LoadParams.OutFailReason = LOCTEXT("CreateNewPluginParam_NoTemplateFolder", "A template folder must be specified to create a plugin with code");
}
return nullptr;
}
if (!FPluginUtils::ValidateNewPluginNameAndLocation(PluginName, PluginLocation, &FailReason))
if (!FPluginUtils::ValidateNewPluginNameAndLocation(PluginName, PluginLocation, LoadParams.OutFailReason))
{
return nullptr;
}
@@ -451,7 +523,10 @@ TSharedPtr<IPlugin> FPluginUtils::CreateAndMountNewPlugin(const FString& PluginN
if (!PlatformFile.DirectoryExists(*PluginFolder) && !PlatformFile.CreateDirectoryTree(*PluginFolder))
{
FailReason = FText::Format(LOCTEXT("FailedToCreatePluginFolder", "Failed to create plugin folder\n{0}"), FText::FromString(PluginFolder));
if (LoadParams.OutFailReason)
{
*LoadParams.OutFailReason = FText::Format(LOCTEXT("FailedToCreatePluginFolder", "Failed to create plugin folder\n{0}"), FText::FromString(PluginFolder));
}
bSucceeded = false;
break;
}
@@ -461,7 +536,10 @@ TSharedPtr<IPlugin> FPluginUtils::CreateAndMountNewPlugin(const FString& PluginN
const FString PluginContentFolder = FPluginUtils::GetPluginContentFolder(PluginLocation, PluginName, /*bFullPath*/ true);
if (!PlatformFile.DirectoryExists(*PluginContentFolder) && !PlatformFile.CreateDirectory(*PluginContentFolder))
{
FailReason = FText::Format(LOCTEXT("FailedToCreatePluginContentFolder", "Failed to create plugin Content folder\n{0}"), FText::FromString(PluginContentFolder));
if (LoadParams.OutFailReason)
{
*LoadParams.OutFailReason = FText::Format(LOCTEXT("FailedToCreatePluginContentFolder", "Failed to create plugin Content folder\n{0}"), FText::FromString(PluginContentFolder));
}
bSucceeded = false;
break;
}
@@ -469,7 +547,7 @@ TSharedPtr<IPlugin> FPluginUtils::CreateAndMountNewPlugin(const FString& PluginN
// Write the uplugin file
const FString PluginFilePath = FPluginUtils::GetPluginFilePath(PluginLocation, PluginName, /*bFullPath*/ true);
if (!CreationParams.Descriptor.Save(PluginFilePath, FailReason))
if (!CreationParams.Descriptor.Save(PluginFilePath, LoadParams.OutFailReason))
{
bSucceeded = false;
break;
@@ -483,7 +561,10 @@ TSharedPtr<IPlugin> FPluginUtils::CreateAndMountNewPlugin(const FString& PluginN
const FString DestinationPluginIconPath = FPaths::Combine(ResourcesFolder, TEXT("Icon128.png"));
if (IFileManager::Get().Copy(*DestinationPluginIconPath, *CreationParams.PluginIconPath, /*bReplaceExisting=*/ false) != COPY_OK)
{
FailReason = FText::Format(LOCTEXT("FailedToCopyPluginIcon", "Failed to copy plugin icon\nFrom: {0}\nTo: {1}"), FText::FromString(FPaths::ConvertRelativePathToFull(CreationParams.PluginIconPath)), FText::FromString(DestinationPluginIconPath));
if (LoadParams.OutFailReason)
{
*LoadParams.OutFailReason = FText::Format(LOCTEXT("FailedToCopyPluginIcon", "Failed to copy plugin icon\nFrom: {0}\nTo: {1}"), FText::FromString(FPaths::ConvertRelativePathToFull(CreationParams.PluginIconPath)), FText::FromString(DestinationPluginIconPath));
}
bSucceeded = false;
break;
}
@@ -496,9 +577,12 @@ TSharedPtr<IPlugin> FPluginUtils::CreateAndMountNewPlugin(const FString& PluginN
GWarn->BeginSlowTask(LOCTEXT("CopyingPluginTemplate", "Copying plugin template files..."), /*ShowProgressDialog*/ true, /*bShowCancelButton*/ false);
for (const FString& TemplateFolder : CreationParams.TemplateFolders)
{
if (!PluginUtils::CopyPluginTemplateFolder(*PluginFolder, *TemplateFolder, PluginName, FailReason, NewFilePaths))
if (!PluginUtils::CopyPluginTemplateFolder(*PluginFolder, *TemplateFolder, PluginName, NewFilePaths, LoadParams.OutFailReason))
{
FailReason = FText::Format(LOCTEXT("FailedToCopyPluginTemplate", "Failed to copy plugin template files\nFrom: {0}\nTo: {1}\n{2}"), FText::FromString(FPaths::ConvertRelativePathToFull(TemplateFolder)), FText::FromString(PluginFolder), FailReason);
if (LoadParams.OutFailReason)
{
*LoadParams.OutFailReason = FText::Format(LOCTEXT("FailedToCopyPluginTemplate", "Failed to copy plugin template files\nFrom: {0}\nTo: {1}\n{2}"), FText::FromString(FPaths::ConvertRelativePathToFull(TemplateFolder)), FText::FromString(PluginFolder), *LoadParams.OutFailReason);
}
bSucceeded = false;
break;
}
@@ -518,7 +602,10 @@ TSharedPtr<IPlugin> FPluginUtils::CreateAndMountNewPlugin(const FString& PluginN
const FString Arguments = FString::Printf(TEXT("%s %s %s -Plugin=\"%s\" -Project=\"%s\" -Progress -NoHotReloadFromIDE"), FPlatformMisc::GetUBTTargetName(), FModuleManager::Get().GetUBTConfiguration(), FPlatformMisc::GetUBTPlatform(), *PluginFilePath, *ProjectFileName);
if (!FDesktopPlatformModule::Get()->RunUnrealBuildTool(FText::Format(LOCTEXT("CompilingPlugin", "Compiling {0} plugin..."), FText::FromString(PluginName)), FPaths::RootDir(), Arguments, GWarn))
{
FailReason = LOCTEXT("FailedToCompilePlugin", "Failed to compile plugin source code. See output log for more information.");
if (LoadParams.OutFailReason)
{
*LoadParams.OutFailReason = LOCTEXT("FailedToCompilePlugin", "Failed to compile plugin source code. See output log for more information.");
}
bSucceeded = false;
break;
}
@@ -529,14 +616,17 @@ TSharedPtr<IPlugin> FPluginUtils::CreateAndMountNewPlugin(const FString& PluginN
// Generate project files if we happen to be using a project file.
if (!FDesktopPlatformModule::Get()->GenerateProjectFiles(FPaths::RootDir(), FPaths::GetProjectFilePath(), GWarn))
{
FailReason = LOCTEXT("FailedToGenerateProjectFiles", "Failed to generate project files");
if (LoadParams.OutFailReason)
{
*LoadParams.OutFailReason = LOCTEXT("FailedToGenerateProjectFiles", "Failed to generate project files");
}
bSucceeded = false;
break;
}
}
// Mount the new plugin
NewPlugin = PluginUtils::MountPluginInternal(PluginName, PluginLocation, MountParams, FailReason, /*bIsNewPlugin*/ true);
// Load the new plugin
NewPlugin = PluginUtils::LoadPluginInternal(PluginName, PluginLocation, PluginFilePath, LoadParams, /*bIsNewPlugin*/ true);
if (!NewPlugin)
{
bSucceeded = false;
@@ -576,22 +666,71 @@ TSharedPtr<IPlugin> FPluginUtils::CreateAndMountNewPlugin(const FString& PluginN
return NewPlugin;
}
TSharedPtr<IPlugin> FPluginUtils::MountPlugin(const FString& PluginName, const FString& PluginLocation, const FMountPluginParams& MountParams, FText& FailReason)
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TSharedPtr<IPlugin> FPluginUtils::CreateAndMountNewPlugin(const FString& PluginName, const FString& PluginLocation, const FNewPluginParams& CreationParams, const FMountPluginParams& MountParams, FText& FailReason)
{
FLoadPluginParams LoadParams = PluginUtils::ConvertToLoadPluginParams(MountParams, &FailReason);
return CreateAndLoadNewPlugin(PluginName, PluginLocation, CreationParams, LoadParams);
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TSharedPtr<IPlugin> FPluginUtils::CreateAndMountNewPlugin(const FString& PluginName, const FString& PluginLocation, const FNewPluginParamsWithDescriptor& CreationParams, const FMountPluginParams& MountParams, FText& FailReason)
{
FLoadPluginParams LoadParams = PluginUtils::ConvertToLoadPluginParams(MountParams, &FailReason);
return CreateAndLoadNewPlugin(PluginName, PluginLocation, CreationParams, LoadParams);
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
TSharedPtr<IPlugin> FPluginUtils::LoadPlugin(const FString& PluginName, const FString& PluginLocation, FLoadPluginParams& LoadParams)
{
// Valide that the uplugin file exists.
const FString PluginFilePath = FPluginUtils::GetPluginFilePath(PluginLocation, PluginName, /*bFullPath*/ true);
if (!FPaths::FileExists(PluginFilePath))
{
FailReason = FText::Format(LOCTEXT("PluginFileDoesNotExist", "Plugin file does not exist\n{0}"), FText::FromString(PluginFilePath));
if (LoadParams.OutFailReason)
{
*LoadParams.OutFailReason = FText::Format(LOCTEXT("PluginFileDoesNotExist", "Plugin file does not exist\n{0}"), FText::FromString(PluginFilePath));
}
return nullptr;
}
if (!IsValidPluginName(PluginName, &FailReason))
if (!IsValidPluginName(PluginName, LoadParams.OutFailReason))
{
return nullptr;
}
return PluginUtils::MountPluginInternal(PluginName, PluginLocation, MountParams, FailReason, /*bIsNewPlugin*/ false);
return PluginUtils::LoadPluginInternal(PluginName, PluginLocation, PluginFilePath, LoadParams, /*bIsNewPlugin*/ false);
}
TSharedPtr<IPlugin> FPluginUtils::LoadPlugin(const FString& PluginFileName, FLoadPluginParams& LoadParams)
{
const FString PluginLocation = FPaths::GetPath(FPaths::GetPath(PluginFileName));
const FString PluginName = FPaths::GetBaseFilename(PluginFileName);
return LoadPlugin(PluginName, PluginLocation, LoadParams);
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TSharedPtr<IPlugin> FPluginUtils::MountPlugin(const FString& PluginName, const FString& PluginLocation, const FMountPluginParams& MountParams, FText& FailReason)
{
FLoadPluginParams LoadParams = PluginUtils::ConvertToLoadPluginParams(MountParams, &FailReason);
return LoadPlugin(PluginName, PluginLocation, LoadParams);
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
TSharedPtr<IPlugin> FPluginUtils::FindLoadedPlugin(const FString& PluginDescriptorFileName)
{
TSharedPtr<IPlugin> Plugin = IPluginManager::Get().FindPlugin(FPaths::GetBaseFilename(PluginDescriptorFileName));
if (Plugin &&
Plugin->IsEnabled() &&
FPaths::IsSamePath(Plugin->GetDescriptorFileName(), PluginDescriptorFileName) &&
(!Plugin->CanContainContent() || FPackageName::MountPointExists(Plugin->GetMountedAssetPath())))
{
return Plugin;
}
return TSharedPtr<IPlugin>();
}
bool FPluginUtils::UnloadPlugin(const TSharedRef<IPlugin>& Plugin, FText* OutFailReason /*= nullptr*/)
@@ -631,9 +770,9 @@ bool FPluginUtils::UnloadPlugins(const TConstArrayView<TSharedRef<IPlugin>> Plug
}
// Synchronous scan plugins to make sure we find all their assets.
IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry")).Get();
IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(AssetRegistryConstants::ModuleName).Get();
if (PluginContentMountPoints.IsEmpty() == false)
if (!PluginContentMountPoints.IsEmpty())
{
AssetRegistry.ScanPathsSynchronous(PluginContentMountPoints, /*bForceRescan=*/ true);
}

View File

@@ -114,6 +114,34 @@ public:
TArray<FString> TemplateFolders;
};
/**
* Parameters for loading/mounting a plugin
*/
struct FLoadPluginParams
{
/** Whether to synchronously scan all assets in the plugin */
bool bSynchronousAssetsScan = false;
/** Whether to select the plugin Content folder (if any) in the content browser */
bool bSelectInContentBrowser = false;
/** Whether to enable the plugin in the current project config */
bool bEnablePluginInProject = false;
/**
* Whether to update the project additional plugin directories (persistently saved in uproject file)
* if the plugin location is not under the engine or project plugin folder
*/
bool bUpdateProjectPluginSearchPath = false;
/** Outputs whether the plugin was already loaded */
bool bOutAlreadyLoaded = false;
/** Outputs the reason the plugin loading failed (if applicable) */
FText* OutFailReason = nullptr;
};
struct UE_DEPRECATED(5.1, "FMountPluginParams is deprecated; please use FLoadPluginParams instead") FMountPluginParams;
/**
* Parameters for mounting a plugin.
*/
@@ -133,16 +161,28 @@ public:
};
/**
* Helper to create and mount a new plugin.
* Helper to create and load a new plugin
* @param PluginName Plugin name
* @param PluginLocation Directory that contains the plugin folder
* @param CreationParams Plugin creation parameters
* @param MountParams Plugin mounting parameters
* @param FailReason Reason the plugin creation/mount failed
* @param MountParams Plugin loading parameters
* @return The newly created plugin. If something goes wrong during the creation process, the plugin folder gets deleted and null is returned.
* @note MountParams.OutFailReason outputs the reason the plugin creation or loading failed (if applicable)
* @note Will fail if the plugin already exists
*/
static TSharedPtr<IPlugin> CreateAndMountNewPlugin(const FString& PluginName, const FString& PluginLocation, const FNewPluginParams& CreationParams, const FMountPluginParams& MountParams, FText& FailReason);
static TSharedPtr<IPlugin> CreateAndLoadNewPlugin(const FString& PluginName, const FString& PluginLocation, const FNewPluginParams& CreationParams, FLoadPluginParams& LoadParams);
/**
* Helper to create and load a new plugin
* @param PluginName Plugin name
* @param PluginLocation Directory that contains the plugin folder
* @param CreationParams Plugin creation parameters
* @param LoadParams Plugin loading parameters
* @return The newly created plugin. If something goes wrong during the creation process, the plugin folder gets deleted and null is returned.
* @note MountParams.OutFailReason outputs the reason the plugin creation or loading failed (if applicable)
* @note Will fail if the plugin already exists
*/
static TSharedPtr<IPlugin> CreateAndLoadNewPlugin(const FString& PluginName, const FString& PluginLocation, const FNewPluginParamsWithDescriptor& CreationParams, FLoadPluginParams& LoadParams);
/**
* Helper to create and mount a new plugin.
@@ -154,18 +194,83 @@ public:
* @return The newly created plugin. If something goes wrong during the creation process, the plugin folder gets deleted and null is returned.
* @note Will fail if the plugin already exists
*/
PRAGMA_DISABLE_DEPRECATION_WARNINGS
UE_DEPRECATED(5.1, "CreateAndMountNewPlugin is deprecated; please use CreateAndLoadNewPlugin instead")
static TSharedPtr<IPlugin> CreateAndMountNewPlugin(const FString& PluginName, const FString& PluginLocation, const FNewPluginParams& CreationParams, const FMountPluginParams& MountParams, FText& FailReason);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/**
* Helper to create and mount a new plugin.
* @param PluginName Plugin name
* @param PluginLocation Directory that contains the plugin folder
* @param CreationParams Plugin creation parameters
* @param MountParams Plugin mounting parameters
* @param FailReason Reason the plugin creation/mount failed
* @return The newly created plugin. If something goes wrong during the creation process, the plugin folder gets deleted and null is returned.
* @note Will fail if the plugin already exists
*/
PRAGMA_DISABLE_DEPRECATION_WARNINGS
UE_DEPRECATED(5.1, "CreateAndMountNewPlugin is deprecated; please use CreateAndLoadNewPlugin instead")
static TSharedPtr<IPlugin> CreateAndMountNewPlugin(const FString& PluginName, const FString& PluginLocation, const FNewPluginParamsWithDescriptor& CreationParams, const FMountPluginParams& MountParams, FText& FailReason);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/**
* Load/mount the specified plugin
* @param PluginName Plugin name
* @param PluginLocation Directory that contains the plugin folder
* @param LoadParams Plugin loading parameters
* @return The loaded plugin or null on failure
*/
static TSharedPtr<IPlugin> LoadPlugin(const FString& PluginName, const FString& PluginLocation, FLoadPluginParams& LoadParams);
/**
* Load/mount the specified plugin
* @param PluginName Plugin name
* @param PluginLocation Directory that contains the plugin folder
* @return The loaded plugin or null on failure
*/
static TSharedPtr<IPlugin> LoadPlugin(const FString& PluginName, const FString& PluginLocation)
{
FLoadPluginParams Params;
return LoadPlugin(PluginName, PluginLocation, Params);
}
/**
* Load/mount the specified plugin
* @param PluginFileName Plugin descriptor file path
* @param LoadParams Plugin loading parameters
* @return The loaded plugin or null on failure
*/
static TSharedPtr<IPlugin> LoadPlugin(const FString& PluginFileName, FLoadPluginParams& LoadParams);
/**
* Load/mount the specified plugin
* @param PluginFileName Plugin descriptor file path
* @return The loaded plugin or null on failure
*/
static TSharedPtr<IPlugin> LoadPlugin(const FString& PluginFileName)
{
FLoadPluginParams Params;
return LoadPlugin(PluginFileName, Params);
}
/**
* Load/mount the specified plugin.
* @param PluginName Plugin name
* @param PluginLocation Directory that contains the plugin folder
* @note the plugin search path will get updated if necessary
* @param MountParams Plugin mounting parameters
* @param FailReason Reason the plugin failed to load
* @return The mounted plugin or null on failure
*/
PRAGMA_DISABLE_DEPRECATION_WARNINGS
UE_DEPRECATED(5.1, "MountPlugin is deprecated; please use LoadPlugin instead")
static TSharedPtr<IPlugin> MountPlugin(const FString& PluginName, const FString& PluginLocation, const FMountPluginParams& MountParams, FText& FailReason);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/**
* Finds a loaded plugin from a plugin descriptor file path
*/
static TSharedPtr<IPlugin> FindLoadedPlugin(const FString& PluginDescriptorFileName);
/**
* Unload assets from the specified plugin and unmount it

View File

@@ -660,15 +660,16 @@ FReply SNewPluginWizard::OnCreatePluginClicked()
CreationParams.Descriptor.bIsBetaVersion = DescriptorData->bIsBetaVersion;
}
FPluginUtils::FMountPluginParams MountParams;
MountParams.bEnablePluginInProject = true;
MountParams.bUpdateProjectPluginSearchPath = true;
MountParams.bSelectInContentBrowser = ShowPluginContentDirectoryCheckBox->IsChecked();
FText FailReason;
FPluginUtils::FLoadPluginParams LoadParams;
LoadParams.bEnablePluginInProject = true;
LoadParams.bUpdateProjectPluginSearchPath = true;
LoadParams.bSelectInContentBrowser = ShowPluginContentDirectoryCheckBox->IsChecked();
LoadParams.OutFailReason = &FailReason;
Template->CustomizeDescriptorBeforeCreation(CreationParams.Descriptor);
FText FailReason;
TSharedPtr<IPlugin> NewPlugin = FPluginUtils::CreateAndMountNewPlugin(PluginName, PluginFolderPath, CreationParams, MountParams, FailReason);
TSharedPtr<IPlugin> NewPlugin = FPluginUtils::CreateAndLoadNewPlugin(PluginName, PluginFolderPath, CreationParams, LoadParams);
const bool bSucceeded = NewPlugin.IsValid();

View File

@@ -75,13 +75,16 @@ FLocalizationTargetDescriptor::FLocalizationTargetDescriptor(FString InName, ELo
{
}
bool FLocalizationTargetDescriptor::Read(const FJsonObject& InObject, FText& OutFailReason)
bool FLocalizationTargetDescriptor::Read(const FJsonObject& InObject, FText* OutFailReason /*= nullptr*/)
{
// Read the target name
TSharedPtr<FJsonValue> NameValue = InObject.TryGetField(TEXT("Name"));
if (!NameValue.IsValid() || NameValue->Type != EJson::String)
{
OutFailReason = LOCTEXT("TargetWithoutAName", "Found a 'Localization Target' entry with a missing 'Name' field");
if (OutFailReason)
{
*OutFailReason = LOCTEXT("TargetWithoutAName", "Found a 'Localization Target' entry with a missing 'Name' field");
}
return false;
}
Name = NameValue->AsString();
@@ -93,7 +96,10 @@ bool FLocalizationTargetDescriptor::Read(const FJsonObject& InObject, FText& Out
LoadingPolicy = ELocalizationTargetDescriptorLoadingPolicy::FromString(*LoadingPolicyValue->AsString());
if (LoadingPolicy == ELocalizationTargetDescriptorLoadingPolicy::Max)
{
OutFailReason = FText::Format(LOCTEXT("TargetWithInvalidLoadingPolicy", "Localization Target entry '{0}' specified an unrecognized target LoadingPolicy '{1}'"), FText::FromString(Name), FText::FromString(LoadingPolicyValue->AsString()));
if (OutFailReason)
{
*OutFailReason = FText::Format(LOCTEXT("TargetWithInvalidLoadingPolicy", "Localization Target entry '{0}' specified an unrecognized target LoadingPolicy '{1}'"), FText::FromString(Name), FText::FromString(LoadingPolicyValue->AsString()));
}
return false;
}
}
@@ -101,7 +107,12 @@ bool FLocalizationTargetDescriptor::Read(const FJsonObject& InObject, FText& Out
return true;
}
bool FLocalizationTargetDescriptor::ReadArray(const FJsonObject& InObject, const TCHAR* InName, TArray<FLocalizationTargetDescriptor>& OutTargets, FText& OutFailReason)
bool FLocalizationTargetDescriptor::Read(const FJsonObject& InObject, FText& OutFailReason)
{
return Read(InObject, &OutFailReason);
}
bool FLocalizationTargetDescriptor::ReadArray(const FJsonObject& InObject, const TCHAR* InName, TArray<FLocalizationTargetDescriptor>& OutTargets, FText* OutFailReason /*= nullptr*/)
{
bool bResult = true;
@@ -125,7 +136,10 @@ bool FLocalizationTargetDescriptor::ReadArray(const FJsonObject& InObject, const
}
else
{
OutFailReason = LOCTEXT("TargetWithInvalidTargetsArray", "The 'Localization Targets' array has invalid contents and was not able to be loaded.");
if (OutFailReason)
{
*OutFailReason = LOCTEXT("TargetWithInvalidTargetsArray", "The 'Localization Targets' array has invalid contents and was not able to be loaded.");
}
bResult = false;
}
}
@@ -134,6 +148,11 @@ bool FLocalizationTargetDescriptor::ReadArray(const FJsonObject& InObject, const
return bResult;
}
bool FLocalizationTargetDescriptor::ReadArray(const FJsonObject& InObject, const TCHAR* InName, TArray<FLocalizationTargetDescriptor>& OutTargets, FText& OutFailReason)
{
return ReadArray(InObject, InName, OutTargets, &OutFailReason);
}
void FLocalizationTargetDescriptor::Write(TJsonWriter<>& Writer) const
{
TSharedRef<FJsonObject> DescriptorJsonObject = MakeShared<FJsonObject>();

View File

@@ -157,13 +157,16 @@ FModuleDescriptor::FModuleDescriptor(const FName InName, EHostType::Type InType,
{
}
bool FModuleDescriptor::Read(const FJsonObject& Object, FText& OutFailReason)
bool FModuleDescriptor::Read(const FJsonObject& Object, FText* OutFailReason /*= nullptr*/)
{
// Read the module name
TSharedPtr<FJsonValue> NameValue = Object.TryGetField(TEXT("Name"));
if(!NameValue.IsValid() || NameValue->Type != EJson::String)
{
OutFailReason = LOCTEXT("ModuleWithoutAName", "Found a 'Module' entry with a missing 'Name' field");
if (OutFailReason)
{
*OutFailReason = LOCTEXT("ModuleWithoutAName", "Found a 'Module' entry with a missing 'Name' field");
}
return false;
}
Name = FName(*NameValue->AsString());
@@ -172,13 +175,19 @@ bool FModuleDescriptor::Read(const FJsonObject& Object, FText& OutFailReason)
TSharedPtr<FJsonValue> TypeValue = Object.TryGetField(TEXT("Type"));
if(!TypeValue.IsValid() || TypeValue->Type != EJson::String)
{
OutFailReason = FText::Format( LOCTEXT( "ModuleWithoutAType", "Found Module entry '{0}' with a missing 'Type' field" ), FText::FromName(Name) );
if (OutFailReason)
{
*OutFailReason = FText::Format( LOCTEXT( "ModuleWithoutAType", "Found Module entry '{0}' with a missing 'Type' field" ), FText::FromName(Name) );
}
return false;
}
Type = EHostType::FromString(*TypeValue->AsString());
if(Type == EHostType::Max)
{
OutFailReason = FText::Format( LOCTEXT( "ModuleWithInvalidType", "Module entry '{0}' specified an unrecognized module Type '{1}'" ), FText::FromName(Name), FText::FromString(TypeValue->AsString()) );
if (OutFailReason)
{
*OutFailReason = FText::Format( LOCTEXT( "ModuleWithInvalidType", "Module entry '{0}' specified an unrecognized module Type '{1}'" ), FText::FromName(Name), FText::FromString(TypeValue->AsString()) );
}
return false;
}
@@ -189,7 +198,10 @@ bool FModuleDescriptor::Read(const FJsonObject& Object, FText& OutFailReason)
LoadingPhase = ELoadingPhase::FromString(*LoadingPhaseValue->AsString());
if(LoadingPhase == ELoadingPhase::Max)
{
OutFailReason = FText::Format( LOCTEXT( "ModuleWithInvalidLoadingPhase", "Module entry '{0}' specified an unrecognized module LoadingPhase '{1}'" ), FText::FromName(Name), FText::FromString(LoadingPhaseValue->AsString()) );
if (OutFailReason)
{
*OutFailReason = FText::Format( LOCTEXT( "ModuleWithInvalidLoadingPhase", "Module entry '{0}' specified an unrecognized module LoadingPhase '{1}'" ), FText::FromName(Name), FText::FromString(LoadingPhaseValue->AsString()) );
}
return false;
}
}
@@ -217,7 +229,12 @@ bool FModuleDescriptor::Read(const FJsonObject& Object, FText& OutFailReason)
return true;
}
bool FModuleDescriptor::ReadArray(const FJsonObject& Object, const TCHAR* Name, TArray<FModuleDescriptor>& OutModules, FText& OutFailReason)
bool FModuleDescriptor::Read(const FJsonObject& Object, FText& OutFailReason)
{
return Read(Object, &OutFailReason);
}
bool FModuleDescriptor::ReadArray(const FJsonObject& Object, const TCHAR* Name, TArray<FModuleDescriptor>& OutModules, FText* OutFailReason /*= nullptr*/)
{
bool bResult = true;
@@ -242,7 +259,10 @@ bool FModuleDescriptor::ReadArray(const FJsonObject& Object, const TCHAR* Name,
}
else
{
OutFailReason = LOCTEXT( "ModuleWithInvalidModulesArray", "The 'Modules' array has invalid contents and was not able to be loaded." );
if (OutFailReason)
{
*OutFailReason = LOCTEXT( "ModuleWithInvalidModulesArray", "The 'Modules' array has invalid contents and was not able to be loaded." );
}
bResult = false;
}
}
@@ -251,6 +271,11 @@ bool FModuleDescriptor::ReadArray(const FJsonObject& Object, const TCHAR* Name,
return bResult;
}
bool FModuleDescriptor::ReadArray(const FJsonObject& Object, const TCHAR* Name, TArray<FModuleDescriptor>& OutModules, FText& OutFailReason)
{
return ReadArray(Object, Name, OutModules, &OutFailReason);
}
void FModuleDescriptor::Write(TJsonWriter<>& Writer) const
{
TSharedRef<FJsonObject> ModuleJsonObject = MakeShared<FJsonObject>();

View File

@@ -11,33 +11,42 @@
namespace PluginDescriptor
{
bool ReadFile(const FString& FileName, FString& Text, FText& OutFailReason)
bool ReadFile(const FString& FileName, FString& Text, FText* OutFailReason = nullptr)
{
if (!FFileHelper::LoadFileToString(Text, *FileName))
{
OutFailReason = FText::Format(LOCTEXT("FailedToLoadDescriptorFile", "Failed to open descriptor file '{0}'"), FText::FromString(FileName));
if (OutFailReason)
{
*OutFailReason = FText::Format(LOCTEXT("FailedToLoadDescriptorFile", "Failed to open descriptor file '{0}'"), FText::FromString(FileName));
}
return false;
}
return true;
}
bool WriteFile(const FString& FileName, const FString& Text, FText& OutFailReason)
bool WriteFile(const FString& FileName, const FString& Text, FText* OutFailReason = nullptr)
{
if (!FFileHelper::SaveStringToFile(Text, *FileName))
{
OutFailReason = FText::Format(LOCTEXT("FailedToWriteDescriptorFile", "Failed to write plugin descriptor file '{0}'. Perhaps the file is Read-Only?"), FText::FromString(FileName));
if (OutFailReason)
{
*OutFailReason = FText::Format(LOCTEXT("FailedToWriteDescriptorFile", "Failed to write plugin descriptor file '{0}'. Perhaps the file is Read-Only?"), FText::FromString(FileName));
}
return false;
}
return true;
}
TSharedPtr<FJsonObject> DeserializeJson(const FString& Text, FText& OutFailReason)
TSharedPtr<FJsonObject> DeserializeJson(const FString& Text, FText* OutFailReason = nullptr)
{
TSharedPtr<FJsonObject> JsonObject;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Text);
if (!FJsonSerializer::Deserialize(Reader, JsonObject) || !JsonObject.IsValid())
{
OutFailReason = FText::Format(LOCTEXT("FailedToReadDescriptorFile", "Failed to read file. {0}"), FText::FromString(Reader->GetErrorMessage()));
if (OutFailReason)
{
*OutFailReason = FText::Format(LOCTEXT("FailedToReadDescriptorFile", "Failed to read file. {0}"), FText::FromString(Reader->GetErrorMessage()));
}
return TSharedPtr<FJsonObject>();
}
return JsonObject;
@@ -82,7 +91,7 @@ FPluginDescriptor::FPluginDescriptor()
}
bool FPluginDescriptor::Load(const FString& FileName, FText& OutFailReason)
bool FPluginDescriptor::Load(const FString& FileName, FText* OutFailReason /*= nullptr*/)
{
#if WITH_EDITOR
CachedJson.Reset();
@@ -97,8 +106,12 @@ bool FPluginDescriptor::Load(const FString& FileName, FText& OutFailReason)
return false;
}
bool FPluginDescriptor::Load(const FString& FileName, FText& OutFailReason)
{
return Load(FileName, &OutFailReason);
}
bool FPluginDescriptor::Read(const FString& Text, FText& OutFailReason)
bool FPluginDescriptor::Read(const FString& Text, FText* OutFailReason /*= nullptr*/)
{
#if WITH_EDITOR
CachedJson.Reset();
@@ -122,8 +135,12 @@ bool FPluginDescriptor::Read(const FString& Text, FText& OutFailReason)
return false;
}
bool FPluginDescriptor::Read(const FString& Text, FText& OutFailReason)
{
return Read(Text, &OutFailReason);
}
bool FPluginDescriptor::Read(const FJsonObject& Object, FText& OutFailReason)
bool FPluginDescriptor::Read(const FJsonObject& Object, FText* OutFailReason /*= nullptr*/)
{
// Read the file version
int32 FileVersionInt32;
@@ -131,7 +148,10 @@ bool FPluginDescriptor::Read(const FJsonObject& Object, FText& OutFailReason)
{
if(!Object.TryGetNumberField(TEXT("PluginFileVersion"), FileVersionInt32))
{
OutFailReason = LOCTEXT("InvalidProjectFileVersion", "File does not have a valid 'FileVersion' number.");
if (OutFailReason)
{
*OutFailReason = LOCTEXT("InvalidProjectFileVersion", "File does not have a valid 'FileVersion' number.");
}
return false;
}
}
@@ -140,9 +160,12 @@ bool FPluginDescriptor::Read(const FJsonObject& Object, FText& OutFailReason)
EPluginDescriptorVersion PluginFileVersion = (EPluginDescriptorVersion)FileVersionInt32;
if ((PluginFileVersion <= EPluginDescriptorVersion::Invalid) || (PluginFileVersion > EPluginDescriptorVersion::Latest))
{
FText ReadVersionText = FText::FromString(FString::Printf(TEXT("%d"), (int32)PluginFileVersion));
FText LatestVersionText = FText::FromString(FString::Printf(TEXT("%d"), (int32)EPluginDescriptorVersion::Latest));
OutFailReason = FText::Format( LOCTEXT("ProjectFileVersionTooLarge", "File appears to be in a newer version ({0}) of the file format that we can load (max version: {1})."), ReadVersionText, LatestVersionText);
if (OutFailReason)
{
const FText ReadVersionText = FText::FromString(FString::Printf(TEXT("%d"), (int32)PluginFileVersion));
const FText LatestVersionText = FText::FromString(FString::Printf(TEXT("%d"), (int32)EPluginDescriptorVersion::Latest));
*OutFailReason = FText::Format(LOCTEXT("ProjectFileVersionTooLarge", "File appears to be in a newer version ({0}) of the file format that we can load (max version: {1})."), ReadVersionText, LatestVersionText);
}
return false;
}
@@ -218,7 +241,12 @@ bool FPluginDescriptor::Read(const FJsonObject& Object, FText& OutFailReason)
return true;
}
bool FPluginDescriptor::Save(const FString& FileName, FText& OutFailReason) const
bool FPluginDescriptor::Read(const FJsonObject& Object, FText& OutFailReason)
{
return Read(Object, &OutFailReason);
}
bool FPluginDescriptor::Save(const FString& FileName, FText* OutFailReason /*= nullptr*/) const
{
// Write the descriptor to text
FString Text;
@@ -228,6 +256,11 @@ bool FPluginDescriptor::Save(const FString& FileName, FText& OutFailReason) cons
return PluginDescriptor::WriteFile(FileName, Text, OutFailReason);
}
bool FPluginDescriptor::Save(const FString& FileName, FText& OutFailReason) const
{
return Save(FileName, &OutFailReason);
}
void FPluginDescriptor::Write(FString& Text) const
{
// Write the contents of the descriptor to a string. Make sure the writer is destroyed so that the contents are flushed to the string.
@@ -389,7 +422,7 @@ void FPluginDescriptor::UpdateJson(FJsonObject& JsonObject) const
#endif
}
bool FPluginDescriptor::UpdatePluginFile(const FString& FileName, FText& OutFailReason) const
bool FPluginDescriptor::UpdatePluginFile(const FString& FileName, FText* OutFailReason /*= nullptr*/) const
{
if (IFileManager::Get().FileExists(*FileName))
{
@@ -413,7 +446,10 @@ bool FPluginDescriptor::UpdatePluginFile(const FString& FileName, FText& OutFail
TSharedRef<TJsonWriter<>> JsonWriter = TJsonWriterFactory<>::Create(&JsonText);
if (!ensure(FJsonSerializer::Serialize(JsonObject.ToSharedRef(), JsonWriter)))
{
OutFailReason = LOCTEXT("FailedToWriteDescriptor", "Failed to write plugin descriptor content");
if (OutFailReason)
{
*OutFailReason = LOCTEXT("FailedToWriteDescriptor", "Failed to write plugin descriptor content");
}
return false;
}
}
@@ -430,6 +466,11 @@ bool FPluginDescriptor::UpdatePluginFile(const FString& FileName, FText& OutFail
}
}
bool FPluginDescriptor::UpdatePluginFile(const FString& FileName, FText& OutFailReason) const
{
return UpdatePluginFile(FileName, &OutFailReason);
}
bool FPluginDescriptor::SupportsTargetPlatform(const FString& Platform) const
{
if (bHasExplicitPlatforms)

View File

@@ -117,19 +117,25 @@ bool FPluginReferenceDescriptor::IsSupportedTargetPlatform(const FString& Platfo
}
}
bool FPluginReferenceDescriptor::Read( const FJsonObject& Object, FText& OutFailReason )
bool FPluginReferenceDescriptor::Read(const FJsonObject& Object, FText* OutFailReason /*= nullptr*/)
{
// Get the name
if(!Object.TryGetStringField(TEXT("Name"), Name))
{
OutFailReason = LOCTEXT("PluginReferenceWithoutName", "Plugin references must have a 'Name' field");
if (OutFailReason)
{
*OutFailReason = LOCTEXT("PluginReferenceWithoutName", "Plugin references must have a 'Name' field");
}
return false;
}
// Get the enabled field
if(!Object.TryGetBoolField(TEXT("Enabled"), bEnabled))
{
OutFailReason = LOCTEXT("PluginReferenceWithoutEnabled", "Plugin references must have an 'Enabled' field");
if (OutFailReason)
{
*OutFailReason = LOCTEXT("PluginReferenceWithoutEnabled", "Plugin references must have an 'Enabled' field");
}
return false;
}
@@ -159,8 +165,12 @@ bool FPluginReferenceDescriptor::Read( const FJsonObject& Object, FText& OutFail
return true;
}
bool FPluginReferenceDescriptor::Read(const FJsonObject& Object, FText& OutFailReason)
{
return Read(Object, &OutFailReason);
}
bool FPluginReferenceDescriptor::ReadArray( const FJsonObject& Object, const TCHAR* Name, TArray<FPluginReferenceDescriptor>& OutPlugins, FText& OutFailReason )
bool FPluginReferenceDescriptor::ReadArray(const FJsonObject& Object, const TCHAR* Name, TArray<FPluginReferenceDescriptor>& OutPlugins, FText* OutFailReason /*= nullptr*/)
{
const TArray< TSharedPtr<FJsonValue> > *Array;
@@ -187,6 +197,10 @@ bool FPluginReferenceDescriptor::ReadArray( const FJsonObject& Object, const TCH
return true;
}
bool FPluginReferenceDescriptor::ReadArray(const FJsonObject& Object, const TCHAR* Name, TArray<FPluginReferenceDescriptor>& OutPlugins, FText& OutFailReason)
{
return ReadArray(Object, Name, OutPlugins, &OutFailReason);
}
void FPluginReferenceDescriptor::Write(TJsonWriter<>& Writer) const
{

View File

@@ -61,9 +61,15 @@ struct PROJECTS_API FLocalizationTargetDescriptor
/** Normal constructor */
FLocalizationTargetDescriptor(FString InName = FString(), ELocalizationTargetDescriptorLoadingPolicy::Type InLoadingPolicy = ELocalizationTargetDescriptorLoadingPolicy::Never);
/** Reads a descriptor from the given JSON object */
bool Read(const FJsonObject& InObject, FText* OutFailReason = nullptr);
/** Reads a descriptor from the given JSON object */
bool Read(const FJsonObject& InObject, FText& OutFailReason);
/** Reads an array of targets from the given JSON object */
static bool ReadArray(const FJsonObject& InObject, const TCHAR* InName, TArray<FLocalizationTargetDescriptor>& OutTargets, FText* OutFailReason = nullptr);
/** Reads an array of targets from the given JSON object */
static bool ReadArray(const FJsonObject& InObject, const TCHAR* InName, TArray<FLocalizationTargetDescriptor>& OutTargets, FText& OutFailReason);

View File

@@ -186,9 +186,15 @@ struct PROJECTS_API FModuleDescriptor
/** Normal constructor */
FModuleDescriptor(const FName InName = NAME_None, EHostType::Type InType = EHostType::Runtime, ELoadingPhase::Type InLoadingPhase = ELoadingPhase::Default);
/** Reads a descriptor from the given JSON object */
bool Read(const FJsonObject& Object, FText* OutFailReason = nullptr);
/** Reads a descriptor from the given JSON object */
bool Read(const FJsonObject& Object, FText& OutFailReason);
/** Reads an array of modules from the given JSON object */
static bool ReadArray(const FJsonObject& Object, const TCHAR* Name, TArray<FModuleDescriptor>& OutModules, FText* OutFailReason = nullptr);
/** Reads an array of modules from the given JSON object */
static bool ReadArray(const FJsonObject& Object, const TCHAR* Name, TArray<FModuleDescriptor>& OutModules, FText& OutFailReason);

View File

@@ -134,15 +134,27 @@ struct PROJECTS_API FPluginDescriptor
/** Constructor. */
FPluginDescriptor();
/** Loads the descriptor from the given file. */
bool Load(const FString& FileName, FText* OutFailReason = nullptr);
/** Loads the descriptor from the given file. */
bool Load(const FString& FileName, FText& OutFailReason);
/** Reads the descriptor from the given string */
bool Read(const FString& Text, FText* OutFailReason = nullptr);
/** Reads the descriptor from the given string */
bool Read(const FString& Text, FText& OutFailReason);
/** Reads the descriptor from the given JSON object */
bool Read(const FJsonObject& Object, FText* OutFailReason = nullptr);
/** Reads the descriptor from the given JSON object */
bool Read(const FJsonObject& Object, FText& OutFailReason);
/** Saves the descriptor from the given file. */
bool Save(const FString& FileName, FText* OutFailReason = nullptr) const;
/** Saves the descriptor from the given file. */
bool Save(const FString& FileName, FText& OutFailReason) const;
@@ -155,6 +167,12 @@ struct PROJECTS_API FPluginDescriptor
/** Updates the given json object with values in this descriptor */
void UpdateJson(FJsonObject& JsonObject) const;
/**
* Updates the content of the specified plugin file with values in this descriptor
* (hence preserving json fields that the plugin descriptor doesn't know about)
*/
bool UpdatePluginFile(const FString& FileName, FText* OutFailReason = nullptr) const;
/**
* Updates the content of the specified plugin file with values in this descriptor
* (hence preserving json fields that the plugin descriptor doesn't know about)

View File

@@ -67,9 +67,15 @@ struct PROJECTS_API FPluginReferenceDescriptor
/** Determines if the referenced plugin is supported for the given platform */
bool IsSupportedTargetPlatform(const FString& Platform) const;
/** Reads the descriptor from the given JSON object */
bool Read(const FJsonObject& Object, FText* OutFailReason = nullptr);
/** Reads the descriptor from the given JSON object */
bool Read(const FJsonObject& Object, FText& OutFailReason);
/** Reads an array of modules from the given JSON object */
static bool ReadArray(const FJsonObject& Object, const TCHAR* Name, TArray<FPluginReferenceDescriptor>& OutModules, FText* OutFailReason = nullptr);
/** Reads an array of modules from the given JSON object */
static bool ReadArray(const FJsonObject& Object, const TCHAR* Name, TArray<FPluginReferenceDescriptor>& OutModules, FText& OutFailReason);