You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
560 lines
17 KiB
C++
560 lines
17 KiB
C++
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "DesktopPlatformPrivatePCH.h"
|
|
#include "DesktopPlatformBase.h"
|
|
#include "UProjectInfo.h"
|
|
#include "EngineVersion.h"
|
|
#include "ModuleManager.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "DesktopPlatform"
|
|
|
|
FDesktopPlatformBase::FDesktopPlatformBase()
|
|
{
|
|
LauncherInstallationTimestamp = FDateTime::MinValue();
|
|
}
|
|
|
|
FString FDesktopPlatformBase::GetCurrentEngineIdentifier()
|
|
{
|
|
if(CurrentEngineIdentifier.Len() == 0 && !GetEngineIdentifierFromRootDir(FPlatformMisc::RootDir(), CurrentEngineIdentifier))
|
|
{
|
|
CurrentEngineIdentifier.Empty();
|
|
}
|
|
return CurrentEngineIdentifier;
|
|
}
|
|
|
|
void FDesktopPlatformBase::EnumerateLauncherEngineInstallations(TMap<FString, FString> &OutInstallations)
|
|
{
|
|
// Cache the launcher install list if necessary
|
|
ReadLauncherInstallationList();
|
|
|
|
// We've got a list of launcher installations. Filter it by the engine installations.
|
|
for(TMap<FString, FString>::TConstIterator Iter(LauncherInstallationList); Iter; ++Iter)
|
|
{
|
|
FString AppName = Iter.Key();
|
|
if(AppName.RemoveFromStart(TEXT("UE_"), ESearchCase::CaseSensitive))
|
|
{
|
|
OutInstallations.Add(AppName, Iter.Value());
|
|
}
|
|
}
|
|
}
|
|
|
|
void FDesktopPlatformBase::EnumerateLauncherSampleInstallations(TArray<FString> &OutInstallations)
|
|
{
|
|
// Cache the launcher install list if necessary
|
|
ReadLauncherInstallationList();
|
|
|
|
// We've got a list of launcher installations. Filter it by the engine installations.
|
|
for(TMap<FString, FString>::TConstIterator Iter(LauncherInstallationList); Iter; ++Iter)
|
|
{
|
|
FString AppName = Iter.Key();
|
|
if(!AppName.StartsWith(TEXT("UE_"), ESearchCase::CaseSensitive))
|
|
{
|
|
OutInstallations.Add(Iter.Value());
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FDesktopPlatformBase::GetEngineRootDirFromIdentifier(const FString &Identifier, FString &OutRootDir)
|
|
{
|
|
// Get all the installations
|
|
TMap<FString, FString> Installations;
|
|
EnumerateEngineInstallations(Installations);
|
|
|
|
// Find the one with the right identifier
|
|
for (TMap<FString, FString>::TConstIterator Iter(Installations); Iter; ++Iter)
|
|
{
|
|
if (Iter->Key == Identifier)
|
|
{
|
|
OutRootDir = Iter->Value;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool FDesktopPlatformBase::GetEngineIdentifierFromRootDir(const FString &RootDir, FString &OutIdentifier)
|
|
{
|
|
// Get all the installations
|
|
TMap<FString, FString> Installations;
|
|
EnumerateEngineInstallations(Installations);
|
|
|
|
// Normalize the root directory
|
|
FString NormalizedRootDir = RootDir;
|
|
FPaths::NormalizeDirectoryName(NormalizedRootDir);
|
|
|
|
// Find the label for the given directory
|
|
for (TMap<FString, FString>::TConstIterator Iter(Installations); Iter; ++Iter)
|
|
{
|
|
if (Iter->Value == NormalizedRootDir)
|
|
{
|
|
OutIdentifier = Iter->Key;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Otherwise just try to add it
|
|
return RegisterEngineInstallation(RootDir, OutIdentifier);
|
|
}
|
|
|
|
bool FDesktopPlatformBase::GetDefaultEngineIdentifier(FString &OutId)
|
|
{
|
|
TMap<FString, FString> Installations;
|
|
EnumerateEngineInstallations(Installations);
|
|
|
|
bool bRes = false;
|
|
if (Installations.Num() > 0)
|
|
{
|
|
// Default to the first install
|
|
TMap<FString, FString>::TConstIterator Iter(Installations);
|
|
OutId = Iter.Key();
|
|
++Iter;
|
|
|
|
// Try to find the most preferred install
|
|
for(; Iter; ++Iter)
|
|
{
|
|
if(IsPreferredEngineIdentifier(Iter.Key(), OutId))
|
|
{
|
|
OutId = Iter.Key();
|
|
}
|
|
}
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
bool FDesktopPlatformBase::GetDefaultEngineRootDir(FString &OutDirName)
|
|
{
|
|
FString Identifier;
|
|
return GetDefaultEngineIdentifier(Identifier) && GetEngineRootDirFromIdentifier(Identifier, OutDirName);
|
|
}
|
|
|
|
bool FDesktopPlatformBase::IsPreferredEngineIdentifier(const FString &Identifier, const FString &OtherIdentifier)
|
|
{
|
|
int32 Version = ParseReleaseVersion(Identifier);
|
|
int32 OtherVersion = ParseReleaseVersion(OtherIdentifier);
|
|
|
|
if(Version != OtherVersion)
|
|
{
|
|
return Version > OtherVersion;
|
|
}
|
|
else
|
|
{
|
|
return Identifier > OtherIdentifier;
|
|
}
|
|
}
|
|
|
|
bool FDesktopPlatformBase::IsStockEngineRelease(const FString &Identifier)
|
|
{
|
|
return Identifier.Len() > 0 && FChar::IsDigit(Identifier[0]);
|
|
}
|
|
|
|
bool FDesktopPlatformBase::IsSourceDistribution(const FString &EngineRootDir)
|
|
{
|
|
// Check for the existence of a SourceBuild.txt file
|
|
FString SourceBuildPath = EngineRootDir / TEXT("Engine/Build/SourceDistribution.txt");
|
|
return (IFileManager::Get().FileSize(*SourceBuildPath) >= 0);
|
|
}
|
|
|
|
bool FDesktopPlatformBase::IsPerforceBuild(const FString &EngineRootDir)
|
|
{
|
|
// Check for the existence of a SourceBuild.txt file
|
|
FString PerforceBuildPath = EngineRootDir / TEXT("Engine/Build/PerforceBuild.txt");
|
|
return (IFileManager::Get().FileSize(*PerforceBuildPath) >= 0);
|
|
}
|
|
|
|
bool FDesktopPlatformBase::IsValidRootDirectory(const FString &RootDir)
|
|
{
|
|
FString EngineBinariesDirName = RootDir / TEXT("Engine/Binaries");
|
|
FPaths::NormalizeDirectoryName(EngineBinariesDirName);
|
|
return IFileManager::Get().DirectoryExists(*EngineBinariesDirName);
|
|
}
|
|
|
|
bool FDesktopPlatformBase::SetEngineIdentifierForProject(const FString &ProjectFileName, const FString &InIdentifier)
|
|
{
|
|
// Load the project file
|
|
TSharedPtr<FJsonObject> ProjectFile = LoadProjectFile(ProjectFileName);
|
|
if (!ProjectFile.IsValid())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Check if the project is a non-foreign project of the given engine installation. If so, blank the identifier
|
|
// string to allow portability between source control databases. GetEngineIdentifierForProject will translate
|
|
// the association back into a local identifier on other machines or syncs.
|
|
FString Identifier = InIdentifier;
|
|
if(Identifier.Len() > 0)
|
|
{
|
|
FString RootDir;
|
|
if(GetEngineRootDirFromIdentifier(Identifier, RootDir))
|
|
{
|
|
const FUProjectDictionary &Dictionary = GetCachedProjectDictionary(RootDir);
|
|
if(!Dictionary.IsForeignProject(ProjectFileName))
|
|
{
|
|
Identifier.Empty();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set the association on the project and save it
|
|
ProjectFile->SetStringField(TEXT("EngineAssociation"), Identifier);
|
|
return SaveProjectFile(ProjectFileName, ProjectFile);
|
|
}
|
|
|
|
bool FDesktopPlatformBase::GetEngineIdentifierForProject(const FString &ProjectFileName, FString &OutIdentifier)
|
|
{
|
|
// Load the project file
|
|
TSharedPtr<FJsonObject> ProjectFile = LoadProjectFile(ProjectFileName);
|
|
if(!ProjectFile.IsValid())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Read the identifier from it
|
|
OutIdentifier = ProjectFile->GetStringField(TEXT("EngineAssociation"));
|
|
if(OutIdentifier.Len() > 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Otherwise scan up through the directory hierarchy to find an installation
|
|
FString ParentDir = FPaths::GetPath(ProjectFileName);
|
|
FPaths::NormalizeDirectoryName(ParentDir);
|
|
|
|
// Keep going until we reach the root
|
|
int32 SeparatorIdx;
|
|
while(ParentDir.FindLastChar(TEXT('/'), SeparatorIdx))
|
|
{
|
|
ParentDir.RemoveAt(SeparatorIdx, ParentDir.Len() - SeparatorIdx);
|
|
if(IsValidRootDirectory(ParentDir) && GetEngineIdentifierFromRootDir(ParentDir, OutIdentifier))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Otherwise check the engine version string for 4.0, in case this project existed before the engine association stuff went in
|
|
FString EngineVersionString = ProjectFile->GetStringField(TEXT("EngineVersion"));
|
|
if(EngineVersionString.Len() > 0)
|
|
{
|
|
FEngineVersion EngineVersion;
|
|
if(FEngineVersion::Parse(EngineVersionString, EngineVersion) && EngineVersion.IsPromotedBuild() && EngineVersion.ToString(EVersionComponent::Minor) == TEXT("4.0"))
|
|
{
|
|
OutIdentifier = TEXT("4.0");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FDesktopPlatformBase::CleanGameProject(const FString &ProjectDir, FFeedbackContext* Warn)
|
|
{
|
|
// Begin a task
|
|
Warn->BeginSlowTask(LOCTEXT("CleaningProject", "Removing stale build products..."), true);
|
|
|
|
// Enumerate all the files
|
|
TArray<FString> FileNames;
|
|
GetProjectBuildProducts(ProjectDir, FileNames);
|
|
|
|
// Remove all the files
|
|
for(int32 Idx = 0; Idx < FileNames.Num(); Idx++)
|
|
{
|
|
// Remove the file
|
|
if(!IFileManager::Get().Delete(*FileNames[Idx]))
|
|
{
|
|
Warn->Logf(ELogVerbosity::Error, TEXT("ERROR: Couldn't delete file '%s'"), *FileNames[Idx]);
|
|
return false;
|
|
}
|
|
|
|
// Try to remove an empty directory hierarchy
|
|
FString DirName = FPaths::GetPath(FileNames[Idx]);
|
|
for(;;)
|
|
{
|
|
TArray<FString> Contents;
|
|
IFileManager::Get().FindFiles(Contents, *(DirName / TEXT("*")), true, true);
|
|
|
|
if(Contents.Num() > 0) break;
|
|
if(!IFileManager::Get().DeleteDirectory(*DirName)) break;
|
|
|
|
int32 ParentIdx;
|
|
if(!DirName.FindLastChar(TEXT('/'), ParentIdx)) break;
|
|
|
|
DirName = DirName.Left(ParentIdx);
|
|
}
|
|
|
|
// Update the progress
|
|
Warn->UpdateProgress(Idx, FileNames.Num());
|
|
}
|
|
|
|
// End the task
|
|
Warn->EndSlowTask();
|
|
return true;
|
|
}
|
|
|
|
bool FDesktopPlatformBase::CompileGameProject(const FString& RootDir, const FString& ProjectFileName, FFeedbackContext* Warn)
|
|
{
|
|
// Get the target name
|
|
FString Arguments = FString::Printf(TEXT("%sEditor %s %s"), *FPaths::GetBaseFilename(ProjectFileName), FModuleManager::Get().GetUBTConfiguration(), FPlatformMisc::GetUBTPlatform());
|
|
|
|
// Append the project name if it's a foreign project
|
|
if ( !ProjectFileName.IsEmpty() )
|
|
{
|
|
FUProjectDictionary ProjectDictionary(RootDir);
|
|
if(ProjectDictionary.IsForeignProject(ProjectFileName))
|
|
{
|
|
Arguments += FString::Printf(TEXT(" -project=\"%s\""), *IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*ProjectFileName));
|
|
}
|
|
}
|
|
|
|
// Append the Rocket flag
|
|
if(!IsSourceDistribution(RootDir))
|
|
{
|
|
Arguments += TEXT(" -rocket");
|
|
}
|
|
|
|
// Append any other options
|
|
Arguments += " -editorrecompile -progress";
|
|
|
|
// Run UBT
|
|
return RunUnrealBuildTool(LOCTEXT("CompilingProject", "Compiling project..."), RootDir, Arguments, Warn);
|
|
}
|
|
|
|
bool FDesktopPlatformBase::GenerateProjectFiles(const FString& RootDir, const FString& ProjectFileName, FFeedbackContext* Warn)
|
|
{
|
|
#if PLATFORM_MAC
|
|
FString Arguments = TEXT("-xcodeprojectfile");
|
|
#else
|
|
FString Arguments = TEXT("-projectfiles");
|
|
#endif
|
|
|
|
// Build the arguments to pass to UBT
|
|
if ( !ProjectFileName.IsEmpty() )
|
|
{
|
|
// Figure out whether it's a foreign project
|
|
const FUProjectDictionary &ProjectDictionary = GetCachedProjectDictionary(RootDir);
|
|
if(ProjectDictionary.IsForeignProject(ProjectFileName))
|
|
{
|
|
Arguments += FString::Printf(TEXT(" -project=\"%s\""), *IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*ProjectFileName));
|
|
|
|
// Always include game source
|
|
Arguments += " -game";
|
|
|
|
// Determine whether or not to include engine source
|
|
if(IsSourceDistribution(RootDir))
|
|
{
|
|
Arguments += " -engine";
|
|
}
|
|
else
|
|
{
|
|
Arguments += " -rocket";
|
|
}
|
|
}
|
|
}
|
|
Arguments += " -progress";
|
|
|
|
// Run UnrealBuildTool
|
|
Warn->BeginSlowTask(LOCTEXT("GeneratingProjectFiles", "Generating project files..."), true, true);
|
|
bool bRes = RunUnrealBuildTool(LOCTEXT("GeneratingProjectFiles", "Generating project files..."), RootDir, Arguments, Warn);
|
|
Warn->EndSlowTask();
|
|
return bRes;
|
|
}
|
|
|
|
void FDesktopPlatformBase::ReadLauncherInstallationList()
|
|
{
|
|
FString InstalledListFile = FString(FPlatformProcess::ApplicationSettingsDir()) / TEXT("UnrealEngineLauncher/LauncherInstalled.dat");
|
|
|
|
// If the file does not exist, manually check for the 4.0 or 4.1 manifest
|
|
FDateTime NewListTimestamp = IFileManager::Get().GetTimeStamp(*InstalledListFile);
|
|
if(NewListTimestamp == FDateTime::MinValue())
|
|
{
|
|
if(LauncherInstallationList.Num() == 0)
|
|
{
|
|
CheckForLauncherEngineInstallation(TEXT("40003"), TEXT("UE_4.0"), LauncherInstallationList);
|
|
CheckForLauncherEngineInstallation(TEXT("1040003"), TEXT("UE_4.1"), LauncherInstallationList);
|
|
}
|
|
}
|
|
else if(NewListTimestamp != LauncherInstallationTimestamp)
|
|
{
|
|
// Read the installation manifest
|
|
FString InstalledText;
|
|
if (FFileHelper::LoadFileToString(InstalledText, *InstalledListFile))
|
|
{
|
|
// Deserialize the object
|
|
TSharedPtr< FJsonObject > RootObject;
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(InstalledText);
|
|
if (FJsonSerializer::Deserialize(Reader, RootObject) && RootObject.IsValid())
|
|
{
|
|
// Parse the list of installations
|
|
TArray< TSharedPtr<FJsonValue> > InstallationList = RootObject->GetArrayField(TEXT("InstallationList"));
|
|
for(int32 Idx = 0; Idx < InstallationList.Num(); Idx++)
|
|
{
|
|
TSharedPtr<FJsonObject> InstallationItem = InstallationList[Idx]->AsObject();
|
|
|
|
FString AppName = InstallationItem->GetStringField(TEXT("AppName"));
|
|
FString InstallLocation = InstallationItem->GetStringField(TEXT("InstallLocation"));
|
|
if(AppName.Len() > 0 && InstallLocation.Len() > 0)
|
|
{
|
|
FPaths::NormalizeDirectoryName(InstallLocation);
|
|
LauncherInstallationList.Add(AppName, InstallLocation);
|
|
}
|
|
}
|
|
}
|
|
LauncherInstallationTimestamp = NewListTimestamp;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FDesktopPlatformBase::CheckForLauncherEngineInstallation(const FString &AppId, const FString &Identifier, TMap<FString, FString> &OutInstallations)
|
|
{
|
|
FString ManifestText;
|
|
FString ManifestFileName = FString(FPlatformProcess::ApplicationSettingsDir()) / FString::Printf(TEXT("UnrealEngineLauncher/Data/Manifests/%s.manifest"), *AppId);
|
|
if (FFileHelper::LoadFileToString(ManifestText, *ManifestFileName))
|
|
{
|
|
TSharedPtr< FJsonObject > RootObject;
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(ManifestText);
|
|
if (FJsonSerializer::Deserialize(Reader, RootObject) && RootObject.IsValid())
|
|
{
|
|
TSharedPtr<FJsonObject> CustomFieldsObject = RootObject->GetObjectField(TEXT("CustomFields"));
|
|
if (CustomFieldsObject.IsValid())
|
|
{
|
|
FString InstallLocation = CustomFieldsObject->GetStringField("InstallLocation");
|
|
if (InstallLocation.Len() > 0)
|
|
{
|
|
OutInstallations.Add(Identifier, InstallLocation);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int32 FDesktopPlatformBase::ParseReleaseVersion(const FString &Version)
|
|
{
|
|
TCHAR *End;
|
|
|
|
uint64 Major = FCString::Strtoui64(*Version, &End, 10);
|
|
if (Major >= MAX_int16 || *(End++) != '.')
|
|
{
|
|
return INDEX_NONE;
|
|
}
|
|
|
|
uint64 Minor = FCString::Strtoui64(End, &End, 10);
|
|
if (Minor >= MAX_int16 || *End != 0)
|
|
{
|
|
return INDEX_NONE;
|
|
}
|
|
|
|
return (Major << 16) + Minor;
|
|
}
|
|
|
|
TSharedPtr<FJsonObject> FDesktopPlatformBase::LoadProjectFile(const FString &FileName)
|
|
{
|
|
FString FileContents;
|
|
|
|
if (!FFileHelper::LoadFileToString(FileContents, *FileName))
|
|
{
|
|
return TSharedPtr<FJsonObject>(NULL);
|
|
}
|
|
|
|
TSharedPtr< FJsonObject > JsonObject;
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(FileContents);
|
|
if (!FJsonSerializer::Deserialize(Reader, JsonObject) || !JsonObject.IsValid())
|
|
{
|
|
return TSharedPtr<FJsonObject>(NULL);
|
|
}
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
bool FDesktopPlatformBase::SaveProjectFile(const FString &FileName, TSharedPtr<FJsonObject> Object)
|
|
{
|
|
FString FileContents;
|
|
|
|
TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&FileContents);
|
|
if (!FJsonSerializer::Serialize(Object.ToSharedRef(), Writer))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!FFileHelper::SaveStringToFile(FileContents, *FileName))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
const FUProjectDictionary &FDesktopPlatformBase::GetCachedProjectDictionary(const FString& RootDir)
|
|
{
|
|
FString NormalizedRootDir = RootDir;
|
|
FPaths::NormalizeDirectoryName(NormalizedRootDir);
|
|
|
|
FUProjectDictionary *Dictionary = CachedProjectDictionaries.Find(NormalizedRootDir);
|
|
if(Dictionary == NULL)
|
|
{
|
|
Dictionary = &CachedProjectDictionaries.Add(RootDir, FUProjectDictionary(RootDir));
|
|
}
|
|
return *Dictionary;
|
|
}
|
|
|
|
void FDesktopPlatformBase::GetProjectBuildProducts(const FString& ProjectDir, TArray<FString> &OutFileNames)
|
|
{
|
|
FString NormalizedProjectDir = ProjectDir;
|
|
FPaths::NormalizeDirectoryName(NormalizedProjectDir);
|
|
|
|
// Find all the build roots
|
|
TArray<FString> BuildRootDirectories;
|
|
BuildRootDirectories.Add(NormalizedProjectDir);
|
|
|
|
// Add all the plugin directories
|
|
TArray<FString> PluginFileNames;
|
|
IFileManager::Get().FindFilesRecursive(PluginFileNames, *(NormalizedProjectDir / TEXT("Plugins")), TEXT("*.uplugin"), true, false);
|
|
for(int32 Idx = 0; Idx < PluginFileNames.Num(); Idx++)
|
|
{
|
|
BuildRootDirectories.Add(FPaths::GetPath(PluginFileNames[Idx]));
|
|
}
|
|
|
|
// Find all the target filenames
|
|
TArray<FString> TargetNames;
|
|
IFileManager::Get().FindFilesRecursive(TargetNames, *(NormalizedProjectDir / TEXT("Source")), TEXT("*.Target.cs"), true, false, false);
|
|
for(int32 Idx = 0; Idx < TargetNames.Num(); Idx++)
|
|
{
|
|
TargetNames[Idx] = FPaths::GetCleanFilename(TargetNames[Idx]);
|
|
TargetNames[Idx].RemoveFromEnd(TEXT(".Target.cs"));
|
|
}
|
|
TargetNames.Add(TEXT("UE4Editor"));
|
|
|
|
// Add the binaries for all of the build roots
|
|
for(int32 RootIdx = 0; RootIdx < BuildRootDirectories.Num(); RootIdx++)
|
|
{
|
|
const FString &BuildRootDirectory = BuildRootDirectories[RootIdx];
|
|
|
|
// Find all the binaries under this build root
|
|
TArray<FString> Binaries;
|
|
IFileManager::Get().FindFilesRecursive(Binaries, *(BuildRootDirectory / TEXT("Binaries")), TEXT("*"), true, false);
|
|
|
|
// Remove all the binaries starting with a target name
|
|
for(int32 BinaryIdx = 0; BinaryIdx < Binaries.Num(); BinaryIdx++)
|
|
{
|
|
FString BinaryName = FPaths::GetCleanFilename(Binaries[BinaryIdx]);
|
|
for(int32 TargetIdx = 0; TargetIdx < TargetNames.Num(); TargetIdx++)
|
|
{
|
|
if(BinaryName.StartsWith(TargetNames[TargetIdx]))
|
|
{
|
|
const TCHAR *End = *BinaryName + TargetNames[TargetIdx].Len();
|
|
if(*End == 0 || *End == TEXT('.') || *End == TEXT('-'))
|
|
{
|
|
OutFileNames.Add(Binaries[BinaryIdx]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add the intermediate folders for all of the build roots
|
|
for(int32 RootIdx = 0; RootIdx < BuildRootDirectories.Num(); RootIdx++)
|
|
{
|
|
IFileManager::Get().FindFilesRecursive(OutFileNames, *(BuildRootDirectories[RootIdx] / TEXT("Intermediate")), TEXT("*"), true, false, false);
|
|
}
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|