Skip to content

Commit

Permalink
Code clean and fixes for Base Game Export
Browse files Browse the repository at this point in the history
  • Loading branch information
Voulz committed Aug 4, 2024
1 parent 374004e commit 6ef6935
Show file tree
Hide file tree
Showing 14 changed files with 188 additions and 350 deletions.
28 changes: 20 additions & 8 deletions Source/GFPakExporter/Private/AuroraBuildTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class FMainFrameActionsNotificationTask // As per UATHelperModule.cpp
{
public:

FMainFrameActionsNotificationTask(TWeakPtr<SNotificationItem> InNotificationItemPtr, SNotificationItem::ECompletionState InCompletionState, const FText& InText, const FText& InLinkText = FText(), bool InExpireAndFadeout = true)
FMainFrameActionsNotificationTask(const TWeakPtr<SNotificationItem>& InNotificationItemPtr, SNotificationItem::ECompletionState InCompletionState, const FText& InText, const FText& InLinkText = FText(), bool InExpireAndFadeout = true)
: CompletionState(InCompletionState)
, NotificationItemPtr(InNotificationItemPtr)
, Text(InText)
Expand Down Expand Up @@ -204,8 +204,8 @@ void FAuroraBuildTask::HandleStageStarted(const FString& InStage)
if (ensure(LauncherWorker))
{
TArray<ILauncherTaskPtr> TaskList;
int NbTasks = LauncherWorker->GetTasks(TaskList);
int CurrentTask = 1 + TaskList.IndexOfByPredicate([](const ILauncherTaskPtr& Task)
const int NbTasks = LauncherWorker->GetTasks(TaskList);
const int CurrentTask = 1 + TaskList.IndexOfByPredicate([](const ILauncherTaskPtr& Task)
{
return Task->GetStatus() != ELauncherTaskStatus::Completed;
});
Expand Down Expand Up @@ -235,7 +235,9 @@ void FAuroraBuildTask::LaunchCompleted(bool Outcome, double ExecutionTime, int32
TGraphTask<FMainFrameActionsNotificationTask>::CreateTask().ConstructAndDispatchWhenReady(
NotificationItemPtr,
SNotificationItem::CS_Success,
FText::Format(LOCTEXT("UatProcessSucceededNotification", "'{0}' complete!"), FText::FromString(DLCSettings.Config.DLCName))
IsBaseGameBuildTask() ?
LOCTEXT("Notification_Title_BaseGame_Complete", "Aurora Project Packaging failed!") :
FText::Format(LOCTEXT("Notification_Title_DLC_Complete", "Aurora DLC Packaging '{0}' complete!"), FText::FromString(DLCSettings.Config.DLCName))
);
Status = ELauncherTaskStatus::Completed;
}
Expand All @@ -244,7 +246,9 @@ void FAuroraBuildTask::LaunchCompleted(bool Outcome, double ExecutionTime, int32
TGraphTask<FMainFrameActionsNotificationTask>::CreateTask().ConstructAndDispatchWhenReady(
NotificationItemPtr,
SNotificationItem::CS_Fail,
FText::Format(LOCTEXT("PackagerFailedNotification", "'{0}' failed!"), FText::FromString(DLCSettings.Config.DLCName)),
IsBaseGameBuildTask() ?
LOCTEXT("Notification_Title_BaseGame_Fail", "Aurora Project Packaging failed!") :
FText::Format(LOCTEXT("Notification_Title_DLC_Fail", "Aurora DLC Packaging '{0}' failed!"), FText::FromString(DLCSettings.Config.DLCName)),
FText(),
false);
Status = ELauncherTaskStatus::Failed;
Expand All @@ -261,15 +265,17 @@ void FAuroraBuildTask::LaunchCanceled(double ExecutionTime)
TGraphTask<FMainFrameActionsNotificationTask>::CreateTask().ConstructAndDispatchWhenReady(
NotificationItemPtr,
SNotificationItem::CS_Fail,
FText::Format(LOCTEXT("UatProcessFailedNotification", "'{0}' canceled!"), FText::FromString(DLCSettings.Config.DLCName))
IsBaseGameBuildTask() ?
LOCTEXT("Notification_Title_BaseGame_Cancel", "Aurora Project Packaging canceled!") :
FText::Format(LOCTEXT("Notification_Title_DLC_Cancel", "Aurora DLC Packaging '{0}' canceled!"), FText::FromString(DLCSettings.Config.DLCName))
);
Status = ELauncherTaskStatus::Pending;
}
}

bool FAuroraBuildTask::CreateNotification()
{
FText DLCName = FText::FromString(DLCSettings.Config.DLCName);
const FText DLCName = FText::FromString(DLCSettings.Config.DLCName);
{
FScopeLock Lock(&NotificationTextMutex);
NotificationText = FText::GetEmpty();
Expand Down Expand Up @@ -302,7 +308,13 @@ bool FAuroraBuildTask::CreateNotification()
FNotificationButtonInfo(
LOCTEXT("UatTaskDismiss", "Dismiss"),
FText(),
FSimpleDelegate::CreateSP(this, &FAuroraBuildTask::HandleNotificationDismissButtonClicked),
FSimpleDelegate::CreateLambda([SharedThis = AsShared().ToSharedPtr()]() // We want to keep the task alive with the notification
{
if (SharedThis)
{
SharedThis->HandleNotificationDismissButtonClicked();
}
}),
SNotificationItem::CS_Fail
)
);
Expand Down
90 changes: 52 additions & 38 deletions Source/GFPakExporter/Private/AuroraExporterSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,43 @@
#include "GFPakExporterLog.h"
#include "JsonObjectConverter.h"
#include "PluginUtils.h"
#include "Algo/MaxElement.h"


// -- FAuroraDLCExporterConfig
// -- FAuroraContentDLCExporterConfig

bool FAuroraDLCExporterConfig::HasValidDLCName() const
bool FAuroraContentDLCExporterConfig::HasValidDLCName() const
{
if (DLCName.IsEmpty())
{
return false;
}
FString PotentialPath = DLCName;
FPaths::NormalizeDirectoryName(PotentialPath);
FString Leaf = FPaths::GetPathLeaf(PotentialPath);
const FString Leaf = FPaths::GetPathLeaf(PotentialPath);
return Leaf == DLCName && !DLCName.Contains(TEXT("."));
}

bool FAuroraDLCExporterConfig::ShouldExportAsset(const FAssetData& AssetData) const
bool FAuroraContentDLCExporterConfig::ShouldExportAsset(const FAssetData& AssetData) const
{
if (Assets.Contains(AssetData.GetSoftObjectPath()))
const FName& PackageName = AssetData.PackageName;

// Some packages (like blueprints) might contains multiple assets, but we need to make sure all the assets from the package would be exported
if (Assets.ContainsByPredicate([&PackageName](const FSoftObjectPath& Asset)
{
return Asset.GetLongPackageFName() == PackageName;
}))
{
return true;
}

return PackagePaths.ContainsByPredicate([&AssetData](const FAuroraDirectoryPath& ContentFolder)
return PackagePaths.ContainsByPredicate([PackageNameStr = PackageName.ToString()](const FAuroraDirectoryPath& ContentFolder)
{
return FPaths::IsUnderDirectory(AssetData.PackagePath.ToString(), ContentFolder.Path);
return !ContentFolder.Path.IsEmpty() && FPaths::IsUnderDirectory(PackageNameStr, ContentFolder.Path);
});
}

FString FAuroraDLCExporterConfig::GetDefaultDLCNameBasedOnContent(const FString& FallbackName) const
FString FAuroraContentDLCExporterConfig::GetDefaultDLCNameBasedOnContent(const FString& FallbackName) const
{
// Here we are trying the get the common path between all the assets, and return the name of the common folder containing all these assets
TArray<FString> StartPath;
Expand Down Expand Up @@ -122,25 +129,24 @@ FString FAuroraDLCExporterConfig::GetDefaultDLCNameBasedOnContent(const FString&
return StartPath.IsEmpty() ? FallbackName : StartPath.Last();
}

TOptional<FAuroraDLCExporterConfig> FAuroraDLCExporterConfig::FromPluginName(const FString& InPluginName)
TOptional<FAuroraContentDLCExporterConfig> FAuroraContentDLCExporterConfig::FromPluginName(const FString& InPluginName)
{
if (FPluginUtils::IsValidPluginName(InPluginName))
{
FAuroraDLCExporterConfig Config;
FAuroraContentDLCExporterConfig Config;
Config.DLCName = InPluginName;
Config.PackagePaths.Add(FAuroraDirectoryPath{TEXT("/") + InPluginName});
return Config;
}
return TOptional<FAuroraDLCExporterConfig>{};
return TOptional<FAuroraContentDLCExporterConfig>{};
}


// --- FAuroraBaseGameExporterConfig

FAuroraBaseGameExporterConfig::EAssetExportRule FAuroraBaseGameExporterConfig::GetAssetExportRule(FName PackageName) const
{
const FSoftObjectPath ObjectPath{PackageName.ToString()};

// Firstly, if we are specifically referencing an asset, we can return the ExportRule directly
if (AssetsToInclude.ContainsByPredicate([&PackageName](const FSoftObjectPath& Asset)
{
return Asset.GetLongPackageFName() == PackageName;
Expand All @@ -156,30 +162,38 @@ FAuroraBaseGameExporterConfig::EAssetExportRule FAuroraBaseGameExporterConfig::G
{
return EAssetExportRule::Exclude;
}

// If not, an asset might be indirectly referenced by both the PackagePathsTo*Include* and PackagePathsTo*Exclude*
// Ex: Include: /Game/Maps Exclude: /Game/Maps/Folder/
// If that is the case, the most specific one should win, which is also the longest path. If they are the same, the asset will be included
const FAuroraDirectoryPath* MostSpecificInclude = Algo::MaxElementBy(PackagePathsToInclude, [&PackageName](const FAuroraDirectoryPath& ContentFolder)
{
return !ContentFolder.Path.IsEmpty() && FPaths::IsUnderDirectory(PackageName.ToString(), ContentFolder.Path) ?
ContentFolder.Path.Len() : 0;
});
const int MostSpecificIncludeLength = MostSpecificInclude ? MostSpecificInclude->Path.Len() : 0;

const bool bIncludedInPath = PackagePathsToInclude.ContainsByPredicate([&PackageName](const FAuroraDirectoryPath& ContentFolder)
const FAuroraDirectoryPath* MostSpecificExclude = Algo::MaxElementBy(PackagePathsToExclude, [&PackageName](const FAuroraDirectoryPath& ContentFolder)
{
return FPaths::IsUnderDirectory(PackageName.ToString(), ContentFolder.Path);
return !ContentFolder.Path.IsEmpty() && FPaths::IsUnderDirectory(PackageName.ToString(), ContentFolder.Path) ?
ContentFolder.Path.Len() : 0;
});
if (bIncludedInPath)
const int MostSpecificExcludeLength = MostSpecificExclude ? MostSpecificExclude->Path.Len() : 0;

if (MostSpecificIncludeLength > 0 && MostSpecificIncludeLength >= MostSpecificExcludeLength)
{
return EAssetExportRule::Include;
}

const bool bExcludedInPath = PackagePathsToExclude.ContainsByPredicate([&PackageName](const FAuroraDirectoryPath& ContentFolder)
{
return FPaths::IsUnderDirectory(PackageName.ToString(), ContentFolder.Path);
});
if (bExcludedInPath)
if (MostSpecificExcludeLength > 0)
{
return EAssetExportRule::Exclude;
}

return EAssetExportRule::Unknown;
}


// --- FAuroraDLCExporterSettings
// --- FAuroraContentDLCExporterSettings

bool FAuroraContentDLCExporterSettings::LoadJsonSettings(const TSharedPtr<FJsonObject>& JsonObject)
{
Expand All @@ -197,31 +211,31 @@ bool FAuroraContentDLCExporterSettings::LoadJsonSettings(const FString& InJsonPa
{
return false;
}
FString Filename = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*InJsonPath); // For Game builds to debug Sandbox File Paths
FString DebugAdjusted = InJsonPath == Filename ? FString{} : FString::Printf(TEXT(" (adjusted to '%s')"), *Filename);
const FString Filename = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*InJsonPath); // For Game builds to debug Sandbox File Paths
const FString DebugAdjusted = InJsonPath == Filename ? FString{} : FString::Printf(TEXT(" (adjusted to '%s')"), *Filename);

if (!FPaths::FileExists(Filename))
{
UE_LOG(LogGFPakExporter, Log, TEXT("FAuroraDLCExporterSettings::LoadJsonConfig: Json Configuration file '%s'%s not found."), *InJsonPath, *DebugAdjusted);
UE_LOG(LogGFPakExporter, Log, TEXT("FAuroraContentDLCExporterSettings::LoadJsonConfig: Json Configuration file '%s'%s not found."), *InJsonPath, *DebugAdjusted);
return false;
}

FString InJsonString;
if (!FFileHelper::LoadFileToString(InJsonString, *Filename))
{
UE_LOG(LogGFPakExporter, Error, TEXT("FAuroraDLCExporterSettings::LoadJsonConfig: Couldn't read file: '%s'%s"), *Filename, *DebugAdjusted);
UE_LOG(LogGFPakExporter, Error, TEXT("FAuroraContentDLCExporterSettings::LoadJsonConfig: Couldn't read file: '%s'%s"), *Filename, *DebugAdjusted);
return false;
}

TSharedPtr<FJsonObject> JsonRoot = MakeShared<FJsonObject>();
const TSharedRef<TJsonReader<>> JsonReader = TJsonReaderFactory<>::Create(InJsonString);
if (!FJsonSerializer::Deserialize(JsonReader, JsonRoot))
{
UE_LOG(LogGFPakExporter, Error, TEXT("FAuroraDLCExporterSettings::LoadJsonConfig: Couldn't parse json data from file: '%s'%s"), *Filename, *DebugAdjusted);
UE_LOG(LogGFPakExporter, Error, TEXT("FAuroraContentDLCExporterSettings::LoadJsonConfig: Couldn't parse json data from file: '%s'%s"), *Filename, *DebugAdjusted);
return false;
}

UE_LOG(LogGFPakExporter, Log, TEXT("FAuroraDLCExporterSettings::LoadJsonConfig: Loading from file: '%s'%s"), *Filename, *DebugAdjusted);
UE_LOG(LogGFPakExporter, Verbose, TEXT("FAuroraContentDLCExporterSettings::LoadJsonConfig: Loading from file: '%s'%s"), *Filename, *DebugAdjusted);
SettingsFilePath.FilePath = InJsonPath;
return LoadJsonSettings(JsonRoot);
}
Expand All @@ -243,26 +257,26 @@ bool FAuroraContentDLCExporterSettings::SaveJsonSettings(const FString& InJsonPa
{
return false;
}
FString Filename = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*InJsonPath); //For Game builds to debug Sandbox File Paths
const FString Filename = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*InJsonPath); //For Game builds to debug Sandbox File Paths

const TSharedPtr<FJsonObject> JsonRoot = MakeShared<FJsonObject>();
if (!SaveJsonSettings(JsonRoot))
{
UE_LOG(LogGFPakExporter, Error, TEXT("FAuroraDLCExporterSettings::SaveJsonConfig: Couldn't save the config to JSON: '%s'"), *Filename);
UE_LOG(LogGFPakExporter, Error, TEXT("FAuroraContentDLCExporterSettings::SaveJsonConfig: Couldn't save the config to JSON: '%s'"), *Filename);
return false;
}

FString OutJsonString;
const TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutJsonString);
if (!FJsonSerializer::Serialize(JsonRoot.ToSharedRef(), Writer))
{
UE_LOG(LogGFPakExporter, Error, TEXT("FAuroraDLCExporterSettings::SaveJsonConfig: Couldn't serialize the Json to file: '%s'"), *Filename);
UE_LOG(LogGFPakExporter, Error, TEXT("FAuroraContentDLCExporterSettings::SaveJsonConfig: Couldn't serialize the Json to file: '%s'"), *Filename);
return false;
}

if (!FFileHelper::SaveStringToFile(OutJsonString, *Filename))
{
UE_LOG(LogGFPakExporter, Error, TEXT("FAuroraDLCExporterSettings::SaveJsonConfig: Couldn't save to file: '%s'"), *Filename);
UE_LOG(LogGFPakExporter, Error, TEXT("FAuroraContentDLCExporterSettings::SaveJsonConfig: Couldn't save to file: '%s'"), *Filename);
return false;
}

Expand All @@ -288,8 +302,8 @@ bool FAuroraBaseGameExporterSettings::LoadJsonSettings(const FString& InJsonPath
{
return false;
}
FString Filename = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*InJsonPath); // For Game builds to debug Sandbox File Paths
FString DebugAdjusted = InJsonPath == Filename ? FString{} : FString::Printf(TEXT(" (adjusted to '%s')"), *Filename);
const FString Filename = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*InJsonPath); // For Game builds to debug Sandbox File Paths
const FString DebugAdjusted = InJsonPath == Filename ? FString{} : FString::Printf(TEXT(" (adjusted to '%s')"), *Filename);

if (!FPaths::FileExists(Filename))
{
Expand All @@ -312,7 +326,7 @@ bool FAuroraBaseGameExporterSettings::LoadJsonSettings(const FString& InJsonPath
return false;
}

UE_LOG(LogGFPakExporter, Log, TEXT("FAuroraBaseGameExporterSettings::LoadJsonConfig: Loading from file: '%s'%s"), *Filename, *DebugAdjusted);
UE_LOG(LogGFPakExporter, Verbose, TEXT("FAuroraBaseGameExporterSettings::LoadJsonConfig: Loading from file: '%s'%s"), *Filename, *DebugAdjusted);
SettingsFilePath.FilePath = InJsonPath;
return LoadJsonSettings(JsonRoot);
}
Expand All @@ -334,7 +348,7 @@ bool FAuroraBaseGameExporterSettings::SaveJsonSettings(const FString& InJsonPath
{
return false;
}
FString Filename = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*InJsonPath); //For Game builds to debug Sandbox File Paths
const FString Filename = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*InJsonPath); //For Game builds to debug Sandbox File Paths

const TSharedPtr<FJsonObject> JsonRoot = MakeShared<FJsonObject>();
if (!SaveJsonSettings(JsonRoot))
Expand Down
Loading

0 comments on commit 6ef6935

Please sign in to comment.