Skip to content

Commit 99d0c39

Browse files
authored
O3DE.exe Project-Centric "Open Editor" fix (o3de#5852)
* The O3DE.exe Open Editor button now attempts to open the Editor in the build directory of the project being opened. If their is no Editor within the build directory of the Project, it uses the Editor.exe in the current O3DE.exe executable directory if it exists Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Engine .gitignore now ignores the build directory if placed in the AutomatedTesting project Previously it was just ignoring a `[Bb]uild` directory if it was directly within the engine root. This change matches the behavior of the project templates. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Renamed the ProjectUtils GetEditorDirectory function to GetEditorExecutablePath Added a platform specific implementation for retrieving the path to the Editor executable in the GetEditorExectuablePath function. It first attempts to locate the Editor via checking the project build directory for an Editor executable before falling back to checking the binary directory of the currently running O3DE executable. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Correct the MacOS GetEditorExecutablePath to return the Editor path Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
1 parent 4ac8b5d commit 99d0c39

7 files changed

Lines changed: 201 additions & 39 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
.vscode/
44
__pycache__
55
AssetProcessorTemp/**
6-
[Bb]uild/**
6+
[Bb]uild/
77
[Oo]ut/**
88
CMakeUserPresets.json
99
[Cc]ache/

Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
3-
*
3+
*
44
* SPDX-License-Identifier: Apache-2.0 OR MIT
55
*
66
*/
@@ -10,6 +10,8 @@
1010
#include <QProcessEnvironment>
1111
#include <QDir>
1212

13+
#include <AzCore/Settings/SettingsRegistryImpl.h>
14+
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
1315
#include <AzCore/Utils/Utils.h>
1416

1517
namespace O3DE::ProjectManager
@@ -68,7 +70,7 @@ namespace O3DE::ProjectManager
6870

6971
QProcess process;
7072

71-
// if the project build path is relative, it should be relative to the project path
73+
// if the project build path is relative, it should be relative to the project path
7274
process.setWorkingDirectory(projectPath);
7375

7476
process.setProgram("cmake-gui");
@@ -80,7 +82,7 @@ namespace O3DE::ProjectManager
8082

8183
return AZ::Success();
8284
}
83-
85+
8486
AZ::Outcome<QString, QString> RunGetPythonScript(const QString& engineRoot)
8587
{
8688
return ExecuteCommandResultModalDialog(
@@ -89,9 +91,53 @@ namespace O3DE::ProjectManager
8991
QObject::tr("Running get_python script..."));
9092
}
9193

92-
AZ::IO::FixedMaxPath GetEditorDirectory()
94+
AZ::IO::FixedMaxPath GetEditorExecutablePath(const AZ::IO::PathView& projectPath)
9395
{
94-
return AZ::Utils::GetExecutableDirectory();
96+
AZ::IO::FixedMaxPath editorPath;
97+
AZ::IO::FixedMaxPath fixedProjectPath{ projectPath };
98+
// First attempt to launch the Editor.exe within the project build directory if it exists
99+
AZ::IO::FixedMaxPath buildPathSetregPath = fixedProjectPath
100+
/ AZ::SettingsRegistryInterface::DevUserRegistryFolder
101+
/ "Platform" / AZ_TRAIT_OS_PLATFORM_CODENAME / "build_path.setreg";
102+
if (AZ::IO::SystemFile::Exists(buildPathSetregPath.c_str()))
103+
{
104+
AZ::SettingsRegistryImpl settingsRegistry;
105+
// Merge the build_path.setreg into the local SettingsRegistry instance
106+
if (AZ::IO::FixedMaxPath projectBuildPath;
107+
settingsRegistry.MergeSettingsFile(buildPathSetregPath.Native(),
108+
AZ::SettingsRegistryInterface::Format::JsonMergePatch)
109+
&& settingsRegistry.Get(projectBuildPath.Native(), AZ::SettingsRegistryMergeUtils::ProjectBuildPath))
110+
{
111+
// local Settings Registry will be used to merge the build_path.setreg for the supplied projectPath
112+
AZ::IO::FixedMaxPath buildConfigurationPath = (fixedProjectPath / projectBuildPath).LexicallyNormal();
113+
114+
// First try <project-build-path>/bin/$<CONFIG> and if that path doesn't exist
115+
// try <project-build-path>/bin/$<PLATFORM>/$<CONFIG>
116+
buildConfigurationPath /= "bin";
117+
if (editorPath = (buildConfigurationPath / AZ_BUILD_CONFIGURATION_TYPE / "Editor").
118+
ReplaceExtension(AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
119+
AZ::IO::SystemFile::Exists(editorPath.c_str()))
120+
{
121+
return editorPath;
122+
}
123+
else if (editorPath = (buildConfigurationPath / AZ_TRAIT_OS_PLATFORM_CODENAME
124+
/ AZ_BUILD_CONFIGURATION_TYPE / "Editor").
125+
ReplaceExtension(AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
126+
AZ::IO::SystemFile::Exists(editorPath.c_str()))
127+
{
128+
return editorPath;
129+
}
130+
}
131+
}
132+
133+
// Fall back to checking if an Editor exists in O3DE executable directory
134+
editorPath = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "Editor";
135+
editorPath.ReplaceExtension(AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
136+
if (AZ::IO::SystemFile::Exists(editorPath.c_str()))
137+
{
138+
return editorPath;
139+
}
140+
return {};
95141
}
96142

97143
AZ::Outcome<QString, QString> CreateDesktopShortcut([[maybe_unused]] const QString& filename, [[maybe_unused]] const QString& targetPath, [[maybe_unused]] const QStringList& arguments)

Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
3-
*
3+
*
44
* SPDX-License-Identifier: Apache-2.0 OR MIT
55
*
66
*/
@@ -11,8 +11,9 @@
1111
#include <QStandardPaths>
1212
#include <QDir>
1313

14-
#include <AzCore/Utils/Utils.h>
14+
#include <AzCore/Settings/SettingsRegistryImpl.h>
1515
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
16+
#include <AzCore/Utils/Utils.h>
1617

1718
namespace O3DE::ProjectManager
1819
{
@@ -21,7 +22,7 @@ namespace O3DE::ProjectManager
2122
AZ::Outcome<void, QString> SetupCommandLineProcessEnvironment()
2223
{
2324
// For CMake on Mac, if its installed through home-brew, then it will be installed
24-
// under /usr/local/bin, which may not be in the system PATH environment.
25+
// under /usr/local/bin, which may not be in the system PATH environment.
2526
// Add that path for the command line process so that it will be able to locate
2627
// a home-brew installed version of CMake
2728
QString pathEnv = qEnvironmentVariable("PATH");
@@ -73,11 +74,11 @@ namespace O3DE::ProjectManager
7374

7475

7576
return AZ::Success(xcodeBuilderVersionNumber);
76-
}
77+
}
7778

7879
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath)
7980
{
80-
const QString cmakeHelp = QObject::tr("Please verify you've installed CMake.app from "
81+
const QString cmakeHelp = QObject::tr("Please verify you've installed CMake.app from "
8182
"<a href=\"https://cmake.org\">cmake.org</a> or, if using HomeBrew, "
8283
"have installed it with <pre>brew install --cask cmake</pre>");
8384
QString cmakeAppPath = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, "CMake.app", QStandardPaths::LocateDirectory);
@@ -95,7 +96,7 @@ namespace O3DE::ProjectManager
9596

9697
QProcess process;
9798

98-
// if the project build path is relative, it should be relative to the project path
99+
// if the project build path is relative, it should be relative to the project path
99100
process.setWorkingDirectory(projectPath);
100101
process.setProgram("open");
101102
process.setArguments({"-a", "CMake", "--args", "-S", projectPath, "-B", projectBuildPath});
@@ -106,7 +107,7 @@ namespace O3DE::ProjectManager
106107

107108
return AZ::Success();
108109
}
109-
110+
110111
AZ::Outcome<QString, QString> RunGetPythonScript(const QString& engineRoot)
111112
{
112113
return ExecuteCommandResultModalDialog(
@@ -115,30 +116,74 @@ namespace O3DE::ProjectManager
115116
QObject::tr("Running get_python script..."));
116117
}
117118

118-
AZ::IO::FixedMaxPath GetEditorDirectory()
119+
AZ::IO::FixedMaxPath GetEditorExecutablePath(const AZ::IO::PathView& projectPath)
119120
{
120-
AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory();
121-
AZ::IO::FixedMaxPath editorPath{ executableDirectory };
122-
editorPath /= "../../../Editor.app/Contents/MacOS";
123-
editorPath = editorPath.LexicallyNormal();
124-
if (!AZ::IO::SystemFile::IsDirectory(editorPath.c_str()))
121+
AZ::IO::FixedMaxPath editorPath;
122+
AZ::IO::FixedMaxPath fixedProjectPath{ projectPath };
123+
124+
// First attempt to launch the Editor.exe within the project build directory if it exists
125+
AZ::IO::FixedMaxPath buildPathSetregPath = fixedProjectPath
126+
/ AZ::SettingsRegistryInterface::DevUserRegistryFolder
127+
/ "Platform" / AZ_TRAIT_OS_PLATFORM_CODENAME / "build_path.setreg";
128+
if (AZ::IO::SystemFile::Exists(buildPathSetregPath.c_str()))
129+
{
130+
AZ::SettingsRegistryImpl localRegistry;
131+
// Merge the build_path.setreg into the local SettingsRegistry instance
132+
if (AZ::IO::FixedMaxPath projectBuildPath;
133+
localRegistry.MergeSettingsFile(buildPathSetregPath.Native(),
134+
AZ::SettingsRegistryInterface::Format::JsonMergePatch)
135+
&& localRegistry.Get(projectBuildPath.Native(), AZ::SettingsRegistryMergeUtils::ProjectBuildPath))
136+
{
137+
// local Settings Registry will be used to merge the build_path.setreg for the supplied projectPath
138+
AZ::IO::FixedMaxPath buildConfigurationPath = (fixedProjectPath / projectBuildPath).LexicallyNormal();
139+
140+
// First try "<project-build-path>/bin/$<CONFIG>/Editor.app/Contents/MacOS"
141+
// Followed by "<project-build-path>/bin/$<PLATFORM>/$<CONFIG>/Editor.app/Contents/MacOS"
142+
// Directory existence is checked in this case
143+
buildConfigurationPath /= "bin";
144+
if (editorPath = (buildConfigurationPath
145+
/ AZ_BUILD_CONFIGURATION_TYPE / "Editor.app/Contents/MacOS/Editor");
146+
AZ::IO::SystemFile::Exists(editorPath.c_str()))
147+
{
148+
return editorPath;
149+
}
150+
else if (editorPath = (buildConfigurationPath / AZ_TRAIT_OS_PLATFORM_CODENAME
151+
/ AZ_BUILD_CONFIGURATION_TYPE / "Editor.app/Contents/MacOS/Editor");
152+
AZ::IO::SystemFile::Exists(editorPath.c_str()))
153+
{
154+
return editorPath;
155+
}
156+
}
157+
}
158+
159+
// Fall back to locating the Editor.app bundle which should exists
160+
// outside of the current O3DE.app bundle
161+
editorPath = (AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) /
162+
"../../../Editor.app/Contents/MacOS/Editor").LexicallyNormal();
163+
164+
if (!AZ::IO::SystemFile::Exists(editorPath.c_str()))
125165
{
166+
// Attempt to search the O3DE.app global settings registry for an InstalledBinaryFolder
167+
// key which indicates the relative path to an SDK binary directory on MacOS
126168
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
127169
{
128170
if (AZ::IO::FixedMaxPath installedBinariesPath;
129-
settingsRegistry->Get(installedBinariesPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
171+
settingsRegistry->Get(installedBinariesPath.Native(),
172+
AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
130173
{
131174
if (AZ::IO::FixedMaxPath engineRootFolder;
132-
settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
175+
settingsRegistry->Get(engineRootFolder.Native(),
176+
AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
133177
{
134-
editorPath = engineRootFolder / installedBinariesPath / "Editor.app/Contents/MacOS";
178+
editorPath = engineRootFolder / installedBinariesPath / "Editor.app/Contents/MacOS/Editor";
135179
}
136180
}
137181
}
138182

139-
if (!AZ::IO::SystemFile::IsDirectory(editorPath.c_str()))
183+
if (!AZ::IO::SystemFile::Exists(editorPath.c_str()))
140184
{
141185
AZ_Error("ProjectManager", false, "Unable to find the Editor app bundle!");
186+
return {};
142187
}
143188
}
144189

Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
3-
*
3+
*
44
* SPDX-License-Identifier: Apache-2.0 OR MIT
55
*
66
*/
@@ -15,6 +15,8 @@
1515
#include <QProcessEnvironment>
1616
#include <QStandardPaths>
1717

18+
#include <AzCore/Settings/SettingsRegistryImpl.h>
19+
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
1820
#include <AzCore/Utils/Utils.h>
1921

2022
namespace O3DE::ProjectManager
@@ -27,7 +29,7 @@ namespace O3DE::ProjectManager
2729
auto engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
2830
if (!engineInfoResult.IsSuccess())
2931
{
30-
return AZ::Failure(QObject::tr("Failed to get engine info"));
32+
return AZ::Failure(QObject::tr("Failed to get engine info"));
3133
}
3234
auto engineInfo = engineInfoResult.GetValue();
3335

@@ -52,7 +54,7 @@ namespace O3DE::ProjectManager
5254

5355
AZ::Outcome<QString, QString> FindSupportedCompilerForPlatform()
5456
{
55-
// Validate that cmake is installed
57+
// Validate that cmake is installed
5658
auto cmakeProcessEnvResult = SetupCommandLineProcessEnvironment();
5759
if (!cmakeProcessEnvResult.IsSuccess())
5860
{
@@ -109,7 +111,7 @@ namespace O3DE::ProjectManager
109111
" or update to a newer version before proceeding to the next step."
110112
" While installing configure Visual Studio with these <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#visual-studio-configuration'>workloads</a>."));
111113
}
112-
114+
113115
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath)
114116
{
115117
AZ::Outcome processEnvResult = SetupCommandLineProcessEnvironment();
@@ -127,7 +129,7 @@ namespace O3DE::ProjectManager
127129

128130
QProcess process;
129131

130-
// if the project build path is relative, it should be relative to the project path
132+
// if the project build path is relative, it should be relative to the project path
131133
process.setWorkingDirectory(projectPath);
132134

133135
process.setProgram("cmake-gui");
@@ -149,9 +151,53 @@ namespace O3DE::ProjectManager
149151
QObject::tr("Running get_python script..."));
150152
}
151153

152-
AZ::IO::FixedMaxPath GetEditorDirectory()
154+
AZ::IO::FixedMaxPath GetEditorExecutablePath(const AZ::IO::PathView& projectPath)
153155
{
154-
return AZ::Utils::GetExecutableDirectory();
156+
AZ::IO::FixedMaxPath editorPath;
157+
AZ::IO::FixedMaxPath fixedProjectPath{ projectPath };
158+
// First attempt to launch the Editor.exe within the project build directory if it exists
159+
AZ::IO::FixedMaxPath buildPathSetregPath = fixedProjectPath
160+
/ AZ::SettingsRegistryInterface::DevUserRegistryFolder
161+
/ "Platform" / AZ_TRAIT_OS_PLATFORM_CODENAME / "build_path.setreg";
162+
if (AZ::IO::SystemFile::Exists(buildPathSetregPath.c_str()))
163+
{
164+
AZ::SettingsRegistryImpl settingsRegistry;
165+
// Merge the build_path.setreg into the local SettingsRegistry instance
166+
if (AZ::IO::FixedMaxPath projectBuildPath;
167+
settingsRegistry.MergeSettingsFile(buildPathSetregPath.Native(),
168+
AZ::SettingsRegistryInterface::Format::JsonMergePatch)
169+
&& settingsRegistry.Get(projectBuildPath.Native(), AZ::SettingsRegistryMergeUtils::ProjectBuildPath))
170+
{
171+
// local Settings Registry will be used to merge the build_path.setreg for the supplied projectPath
172+
AZ::IO::FixedMaxPath buildConfigurationPath = (fixedProjectPath / projectBuildPath).LexicallyNormal();
173+
174+
// First try <project-build-path>/bin/$<CONFIG> and if that path doesn't exist
175+
// try <project-build-path>/bin/$<PLATFORM>/$<CONFIG>
176+
buildConfigurationPath /= "bin";
177+
if (editorPath = (buildConfigurationPath / AZ_BUILD_CONFIGURATION_TYPE / "Editor").
178+
ReplaceExtension(AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
179+
AZ::IO::SystemFile::Exists(editorPath.c_str()))
180+
{
181+
return editorPath;
182+
}
183+
else if (editorPath = (buildConfigurationPath / AZ_TRAIT_OS_PLATFORM_CODENAME
184+
/ AZ_BUILD_CONFIGURATION_TYPE / "Editor").
185+
ReplaceExtension(AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
186+
AZ::IO::SystemFile::Exists(editorPath.c_str()))
187+
{
188+
return editorPath;
189+
}
190+
}
191+
}
192+
193+
// Fall back to checking if an Editor exists in O3DE executable directory
194+
editorPath = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "Editor";
195+
editorPath.ReplaceExtension(AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
196+
if (AZ::IO::SystemFile::Exists(editorPath.c_str()))
197+
{
198+
return editorPath;
199+
}
200+
return {};
155201
}
156202

157203
AZ::Outcome<QString, QString> CreateDesktopShortcut(const QString& filename, const QString& targetPath, const QStringList& arguments)

Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,7 @@ namespace O3DE::ProjectManager
215215
#if AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT
216216
menu->addAction(tr("Create Editor desktop shortcut..."), this, [this]()
217217
{
218-
AZ::IO::FixedMaxPath executableDirectory = ProjectUtils::GetEditorDirectory();
219-
AZStd::string executableFilename = "Editor";
220-
AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
218+
AZ::IO::FixedMaxPath editorExecutablePath = ProjectUtils::GetEditorExecutablePath(m_projectInfo.m_path.toUtf8().constData());
221219

222220
const QString shortcutName = QString("%1 Editor").arg(m_projectInfo.m_displayName);
223221
const QString arg = QString("--regset=\"/Amazon/AzCore/Bootstrap/project_path=%1\"").arg(m_projectInfo.m_path);

Code/Tools/ProjectManager/Source/ProjectUtils.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,27 @@ namespace O3DE::ProjectManager
7676
*/
7777
AZ::Outcome<QString, QString> CreateDesktopShortcut(const QString& filename, const QString& targetPath, const QStringList& arguments);
7878

79-
AZ::IO::FixedMaxPath GetEditorDirectory();
79+
/**
80+
* Lookup the location of an Editor executable executable that can be used with the
81+
* supplied project path
82+
* First the method attempts to locate a build directory with the project path
83+
* via querying the <project-path>/user/Registry/Platform/<platform>/build_path.setreg
84+
* Once that is done a path is formed to locate the Editor executable within the that build
85+
* directory.
86+
* Two paths will checked for the existence of an Editor
87+
* - "<project-build-directory>/bin/$<CONFIG>/Editor"
88+
* - "<project-build-directory>/bin/<platform>/$<CONFIG>/Editor"
89+
* Where <platform> is the current platform the O3DE executable is running on and $<CONFIG> is the
90+
* current build configuration the O3DE executable
91+
*
92+
* If neiether of the above paths contain an Editor application, then a path to the Editor
93+
* is formed by combinding the O3DE executable directory with the filename of Editor
94+
* - "<executable-directory>/Editor"
95+
*
96+
* @param projectPath Path to the root of the project
97+
* @return path of the Editor Executable if found or an empty path if not
98+
*/
99+
AZ::IO::FixedMaxPath GetEditorExecutablePath(const AZ::IO::PathView& projectPath);
80100

81101
} // namespace ProjectUtils
82102
} // namespace O3DE::ProjectManager

0 commit comments

Comments
 (0)