Skip to content

Commit

Permalink
Merge pull request #47 from PlasticSCM/1002363-update-workspace-reloa…
Browse files Browse the repository at this point in the history
…d-map

Update workspace also reload the current map if needed
  • Loading branch information
juliomaqueda committed Nov 22, 2022
2 parents 96a98ce + 086dde0 commit d0af9d6
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 44 deletions.
94 changes: 78 additions & 16 deletions Source/PlasticSourceControl/Private/PlasticSourceControlMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,33 +451,95 @@ void FPlasticSourceControlMenu::DisplayFailureNotification(const FName& InOperat
UE_LOG(LogSourceControl, Error, TEXT("%s"), *NotificationText.ToString());
}

void FPlasticSourceControlMenu::OnSourceControlOperationComplete(const FSourceControlOperationRef& InOperation, ECommandResult::Type InResult)
// Get the World currently loaded by the Editor (and thus, access to the corresponding map package)
UWorld* GetCurrentWorld()
{
RemoveInProgressNotification();
if (GEditor)
{
if (UWorld* EditorWorld = GEditor->GetEditorWorldContext().World())
{
return EditorWorld;
}
}
return nullptr;
}

if (InOperation->GetName() == "SyncAll")
TArray<UPackage*> ListPackagesToReload(const TArray<FString>& InUpdatedFiles)
{
TArray<UPackage*> PackagesToReload;

PackagesToReload.Reserve(InUpdatedFiles.Num() + 1);
for (const FString& FilePath : InUpdatedFiles)
{
TSharedRef<FPlasticSyncAll, ESPMode::ThreadSafe> Operation = StaticCastSharedRef<FPlasticSyncAll>(InOperation);
FString PackageName;
FString FailureReason;
if (FPackageName::TryConvertFilenameToLongPackageName(FilePath, PackageName, &FailureReason))
{
// NOTE: this will only find packages loaded in memory
if (UPackage* Package = FindPackage(nullptr, *PackageName))
{
PackagesToReload.Emplace(Package);
UE_LOG(LogSourceControl, Log, TEXT("Reload: %s"), *PackageName);
}
}
// else, it means the file is not an asset from the Content/ folder (eg config, source code, anything else)
}

#if ENGINE_MAJOR_VERSION == 5
// Detects if some packages to reload are part of the current map
// (ie assets within __ExternalActors__ or __ExternalObjects__ from the new One File Per Actor (OFPA) in UE5)
// in which case the current map need to be reloaded, so it needs to be added to the list of packages if not already there
// (then UPackageTools::ReloadPackages() will handle unloading the map at the start of the reload, avoiding some crash, and reloading it at the end)
if (UWorld* CurrentWorld = GetCurrentWorld())
{
UPackage* CurrentMapPackage = CurrentWorld->GetOutermost();

// If the current map file has been updated, it will be reloaded automatically, so no need for the following
const FString CurrentMapFileAbsolute = FPaths::ConvertRelativePathToFull(CurrentMapPackage->GetLoadedPath().GetLocalFullPath());
const bool bHasCurrentMapBeenUpdated = InUpdatedFiles.FindByPredicate(
[&CurrentMapFileAbsolute](const FString& InFilePath) { return InFilePath.Equals(CurrentMapFileAbsolute, ESearchCase::IgnoreCase); }
) != nullptr;

TArray<UPackage*> PackagesToReload;
PackagesToReload.Reserve(Operation->UpdatedFiles.Num());
for (const FString& FilePath : Operation->UpdatedFiles)
if (!bHasCurrentMapBeenUpdated)
{
FString PackageName;
FString FailureReason;
if (FPackageName::TryConvertFilenameToLongPackageName(FilePath, PackageName, &FailureReason))
static const FString GamePath = FString("/Game");
const FString CurrentMapPath = *CurrentMapPackage->GetName(); // eg "/Game/Maps/OpenWorld"
const FString CurrentMapPathWithoutGamePrefix = CurrentMapPath.RightChop(GamePath.Len()); // eg "/Maps/OpenWorld"
const FString CurrentMapExternalActorPath = FPackagePath::GetExternalActorsFolderName() + CurrentMapPathWithoutGamePrefix; // eg "/__ExternalActors__/Maps/OpenWorld"
const FString CurrentMapExternalObjectPath = FPackagePath::GetExternalObjectsFolderName() + CurrentMapPathWithoutGamePrefix; // eg "/__ExternalObjects__/Maps/OpenWorld"

bool bNeedReloadCurrentMap = false;

for (const FString& FilePath : InUpdatedFiles)
{
// NOTE: this will only find packages loaded in memory
if (UPackage* Package = FindPackage(nullptr, *PackageName))
if (FilePath.Contains(CurrentMapExternalActorPath) || FilePath.Contains(CurrentMapExternalObjectPath))
{
PackagesToReload.Emplace(Package);
UE_LOG(LogSourceControl, Log, TEXT("Reload: %s"), *PackageName);
bNeedReloadCurrentMap = true;
break;
}
}
// else, it means the file is not an asset from the Content/ folder (eg config, source code, anything else)

if (bNeedReloadCurrentMap)
{
PackagesToReload.Add(CurrentMapPackage);
UE_LOG(LogSourceControl, Log, TEXT("Reload: %s"), *CurrentMapPath);
}
}
}
#endif

// Reload packages that where updated by the Sync operation
return PackagesToReload;
}

void FPlasticSourceControlMenu::OnSourceControlOperationComplete(const FSourceControlOperationRef& InOperation, ECommandResult::Type InResult)
{
RemoveInProgressNotification();

if (InOperation->GetName() == "SyncAll")
{
// Reload packages that where updated by the Sync operation (and the current map if needed)
TSharedRef<FPlasticSyncAll, ESPMode::ThreadSafe> Operation = StaticCastSharedRef<FPlasticSyncAll>(InOperation);
TArray<UPackage*> PackagesToReload = ListPackagesToReload(Operation->UpdatedFiles);
ReloadPackages(PackagesToReload);
}
else if (InOperation->GetName() == "RevertAll")
Expand Down
54 changes: 26 additions & 28 deletions Source/PlasticSourceControl/Private/PlasticSourceControlUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "PlasticSourceControlShell.h"
#include "PlasticSourceControlState.h"
#include "ISourceControlModule.h"
#include "ScopedTempFile.h"

#include "Runtime/Launch/Resources/Version.h"
#if ENGINE_MAJOR_VERSION == 4
Expand Down Expand Up @@ -1434,47 +1435,44 @@ bool RunSync(const TArray<FString>& InFiles, const bool bInIsPartialWorkspace, T
{
bool bResult = false;

// TODO: const FScopedTempFile TempFile;
const FString TempFilename = FPaths::CreateTempFilename(*FPaths::ConvertRelativePathToFull(FPaths::ProjectLogDir()), TEXT("Plastic-Temp"), TEXT(".xml"));

TArray<FString> InfoMessages;
TArray<FString> Parameters;
Parameters.Add(FString::Printf(TEXT("--xml=\"%s\""), *TempFilename));
Parameters.Add(TEXT("--encoding=\"utf-8\""));
// Update specified directory to the head of the repository
// Detect special case for a partial checkout (CS:-1 in Gluon mode)!
if (!bInIsPartialWorkspace)
{
const FScopedTempFile TempFile;
Parameters.Add(FString::Printf(TEXT("--xml=\"%s\""), *TempFile.GetFilename()));
Parameters.Add(TEXT("--encoding=\"utf-8\""));
Parameters.Add(TEXT("--last"));
Parameters.Add(TEXT("--dontmerge"));
bResult = PlasticSourceControlUtils::RunCommand(TEXT("update"), Parameters, InFiles, InfoMessages, OutErrorMessages);
}
else
{
bResult = PlasticSourceControlUtils::RunCommand(TEXT("partial update"), Parameters, InFiles, InfoMessages, OutErrorMessages);
}

if (bResult)
{
// Parse the result of the
FString Results;
if (FFileHelper::LoadFileToString(Results, *TempFilename))
bResult = PlasticSourceControlUtils::RunCommand(TEXT("update"), Parameters, TArray<FString>(), InfoMessages, OutErrorMessages);
if (bResult)
{
FXmlFile XmlFile;
{
TRACE_CPUPROFILER_EVENT_SCOPE(PlasticSourceControlUtils::RunSync::FXmlFile::LoadFile);
bResult = XmlFile.LoadFile(Results, EConstructMethod::ConstructFromBuffer);
}
if (bResult)
{
bResult = ParseSyncResults(XmlFile, OutUpdatedFiles);
}
else
// Load and parse the result of the update command
FString Results;
if (FFileHelper::LoadFileToString(Results, *TempFile.GetFilename()))
{
UE_LOG(LogSourceControl, Error, TEXT("RunSync: XML parse error '%s'"), *XmlFile.GetLastError())
FXmlFile XmlFile;
{
TRACE_CPUPROFILER_EVENT_SCOPE(PlasticSourceControlUtils::RunSync::FXmlFile::LoadFile);
bResult = XmlFile.LoadFile(Results, EConstructMethod::ConstructFromBuffer);
}
if (bResult)
{
bResult = ParseSyncResults(XmlFile, OutUpdatedFiles);
}
else
{
UE_LOG(LogSourceControl, Error, TEXT("RunSync: XML parse error '%s'"), *XmlFile.GetLastError())
}
}
}
}
else
{
bResult = PlasticSourceControlUtils::RunCommand(TEXT("partial update"), Parameters, InFiles, InfoMessages, OutErrorMessages);
}

return bResult;
}
Expand Down
5 changes: 5 additions & 0 deletions Source/PlasticSourceControl/Private/ScopedTempFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@

#include "ISourceControlModule.h" // LogSourceControl

FScopedTempFile::FScopedTempFile()
{
Filename = FPaths::CreateTempFilename(*FPaths::ProjectLogDir(), TEXT("Plastic-Temp"), TEXT(".txt"));
}

FScopedTempFile::FScopedTempFile(const FString& InText)
{
Filename = FPaths::CreateTempFilename(*FPaths::ProjectLogDir(), TEXT("Plastic-Temp"), TEXT(".txt"));
Expand Down
3 changes: 3 additions & 0 deletions Source/PlasticSourceControl/Private/ScopedTempFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
class FScopedTempFile
{
public:
/** Default constructor - only hold a temp filename */
FScopedTempFile();

/** Constructor - open & write string to temp file */
explicit FScopedTempFile(const FString& InText);
explicit FScopedTempFile(const FText& InText);
Expand Down

0 comments on commit d0af9d6

Please sign in to comment.