Merge branch 'main' into LoadPipelineFromGitHub
This commit is contained in:
@@ -48,9 +48,9 @@ ly_add_target(
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME EditorPythonBindings.Editor MODULE
|
||||
NAME EditorPythonBindings.Editor GEM_MODULE
|
||||
|
||||
NAMESPACE Gem
|
||||
OUTPUT_NAME Gem.EditorPythonBindings.Editor.b658359393884c4381c2fe2952b1472a.v0.1.0
|
||||
FILES_CMAKE
|
||||
editorpythonbindings_editor_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/Asset/AssetSystemComponent.h>
|
||||
@@ -348,73 +349,111 @@ namespace EditorPythonBindings
|
||||
{
|
||||
// the order of the Python paths is the order the Python bootstrap scripts will execute
|
||||
|
||||
AZStd::string gameFolder;
|
||||
auto settingsRegistry = AZ::SettingsRegistry::Get();
|
||||
settingsRegistry->Get(gameFolder, AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s",
|
||||
AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, AzFramework::AssetSystem::ProjectName));
|
||||
if (!settingsRegistry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameFolder.empty())
|
||||
AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath();
|
||||
if (projectPath.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto resolveScriptPath = [&pythonPathStack](AZStd::string_view path)
|
||||
{
|
||||
AZStd::string editorScriptsPath;
|
||||
AzFramework::StringFunc::Path::Join(path.data(), "Editor/Scripts", editorScriptsPath);
|
||||
AZ::IO::Path editorScriptsPath(path);
|
||||
editorScriptsPath /= "Editor/Scripts";
|
||||
if (AZ::IO::SystemFile::Exists(editorScriptsPath.c_str()))
|
||||
{
|
||||
pythonPathStack.emplace_back(editorScriptsPath);
|
||||
pythonPathStack.emplace_back(AZStd::move(editorScriptsPath.LexicallyNormal().Native()));
|
||||
}
|
||||
};
|
||||
|
||||
// The discovery order will be:
|
||||
// - engine
|
||||
// - gems
|
||||
// - project
|
||||
// - user(dev)
|
||||
// 1 - engine
|
||||
// 2 - gems
|
||||
// 3 - project
|
||||
// 4 - user(dev)
|
||||
|
||||
// engine
|
||||
const char* engineRoot = nullptr;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot);
|
||||
resolveScriptPath(engineRoot);
|
||||
|
||||
// gems
|
||||
auto moduleCallback = [this, &pythonPathStack, resolveScriptPath, engineRoot](const AZ::ModuleData& moduleData) -> bool
|
||||
// 1 - engine
|
||||
AZ::IO::FixedMaxPath engineRoot;
|
||||
if (settingsRegistry->Get(engineRoot.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); !engineRoot.empty())
|
||||
{
|
||||
if (moduleData.GetDynamicModuleHandle())
|
||||
{
|
||||
const AZ::OSString& modulePath = moduleData.GetDynamicModuleHandle()->GetFilename();
|
||||
AZStd::string fileName;
|
||||
AzFramework::StringFunc::Path::GetFileName(modulePath.c_str(), fileName);
|
||||
resolveScriptPath(engineRoot.Native());
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> tokens;
|
||||
AzFramework::StringFunc::Tokenize(fileName.c_str(), tokens, '.');
|
||||
if (tokens.size() > 2 && tokens[0] == "Gem")
|
||||
// 2 - gems
|
||||
struct GetGemSourcePathsVisitor
|
||||
: AZ::SettingsRegistryInterface::Visitor
|
||||
{
|
||||
GetGemSourcePathsVisitor(AZ::SettingsRegistryInterface& settingsRegistry)
|
||||
: m_settingsRegistry(settingsRegistry)
|
||||
{}
|
||||
void Visit(AZStd::string_view path, AZStd::string_view, AZ::SettingsRegistryInterface::Type,
|
||||
AZStd::string_view value) override
|
||||
{
|
||||
AZStd::string_view jsonSourcePathPointer{ path };
|
||||
// Remove the array index from the path and check if the JSON path ends with "/SourcePaths"
|
||||
AZ::StringFunc::TokenizeLast(jsonSourcePathPointer, "/");
|
||||
if (jsonSourcePathPointer.ends_with("/SourcePaths"))
|
||||
{
|
||||
resolveScriptPath(AZStd::string::format("%s/Gems/%s", engineRoot, tokens[1].c_str()));
|
||||
AZ::IO::Path newSourcePath = jsonSourcePathPointer;
|
||||
// Resolve any file aliases first - Do not use ResolvePath() as that assumes
|
||||
// any relative path is underneath the @assets@ alias
|
||||
if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr)
|
||||
{
|
||||
AZ::IO::FixedMaxPath replacedAliasPath;
|
||||
if (fileIoBase->ReplaceAlias(replacedAliasPath, value))
|
||||
{
|
||||
newSourcePath = AZ::IO::PathView(replacedAliasPath);
|
||||
}
|
||||
}
|
||||
|
||||
// The current assumption is that the gem source path is the relative to the engine root
|
||||
AZ::IO::Path engineRootPath;
|
||||
m_settingsRegistry.Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
||||
newSourcePath = (engineRootPath / newSourcePath).LexicallyNormal();
|
||||
|
||||
if (auto gemSourcePathIter = AZStd::find(m_gemSourcePaths.begin(), m_gemSourcePaths.end(), newSourcePath);
|
||||
gemSourcePathIter == m_gemSourcePaths.end())
|
||||
{
|
||||
m_gemSourcePaths.emplace_back(AZStd::move(newSourcePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
AZStd::vector<AZ::IO::Path> m_gemSourcePaths;
|
||||
private:
|
||||
AZ::SettingsRegistryInterface& m_settingsRegistry;
|
||||
};
|
||||
AZ::ModuleManagerRequestBus::Broadcast(&AZ::ModuleManagerRequestBus::Events::EnumerateModules, moduleCallback);
|
||||
|
||||
// project
|
||||
const char* appRoot = nullptr;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot);
|
||||
resolveScriptPath(AZStd::string::format("%s/%s", appRoot, gameFolder.c_str()));
|
||||
GetGemSourcePathsVisitor visitor{ *settingsRegistry };
|
||||
constexpr auto gemListKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::OrganizationRootKey)
|
||||
+ "/Gems";
|
||||
settingsRegistry->Visit(visitor, gemListKey);
|
||||
for (const AZ::IO::Path& gemSourcePath : visitor.m_gemSourcePaths)
|
||||
{
|
||||
resolveScriptPath(gemSourcePath.Native());
|
||||
}
|
||||
|
||||
// user
|
||||
// 3 - project
|
||||
resolveScriptPath(AZStd::string_view{ projectPath });
|
||||
|
||||
// 4 - user
|
||||
AZStd::string assetsType;
|
||||
AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, assetsType,
|
||||
AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, AzFramework::AssetSystem::Assets);
|
||||
if (!assetsType.empty())
|
||||
{
|
||||
// the pattern to user path is <appRoot>/Cache/<gameFolder>/<assetsType>/user e.g. c:/myroot/dev/Cache/MyProject/pc/user
|
||||
AZStd::string userRelativePath = AZStd::string::format("Cache/%s/%s/user", gameFolder.c_str(), assetsType.c_str());
|
||||
AZStd::string userCachePath;
|
||||
AzFramework::StringFunc::Path::Join(appRoot, userRelativePath.c_str(), userCachePath);
|
||||
resolveScriptPath(userCachePath);
|
||||
AZ::IO::FixedMaxPath userCachePath;
|
||||
if (settingsRegistry->Get(userCachePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder);
|
||||
!userCachePath.empty())
|
||||
{
|
||||
userCachePath /= "user";
|
||||
resolveScriptPath(userCachePath.Native());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,15 +532,17 @@ namespace EditorPythonBindings
|
||||
|
||||
bool PythonSystemComponent::ExtendSysPath(const AZStd::unordered_set<AZStd::string>& extendPaths)
|
||||
{
|
||||
AZStd::string oldPath{ Py_EncodeLocale(Py_GetPath(), nullptr) };
|
||||
AZStd::vector<AZStd::string> pathParts;
|
||||
AZ::StringFunc::Tokenize(oldPath, pathParts, DELIM, false, false);
|
||||
AZStd::unordered_set<AZStd::string> oldPathSet{ pathParts.begin(), pathParts.end() };
|
||||
AZStd::unordered_set<AZStd::string> oldPathSet;
|
||||
auto SplitPath = [&oldPathSet](AZStd::string_view pathPart)
|
||||
{
|
||||
oldPathSet.emplace(pathPart);
|
||||
};
|
||||
AZ::StringFunc::TokenizeVisitor(Py_EncodeLocale(Py_GetPath(), nullptr), SplitPath, DELIM);
|
||||
bool appended{ false };
|
||||
AZStd::string pathAppend{ "import sys\n" };
|
||||
for (const auto& thisStr : extendPaths)
|
||||
{
|
||||
if (oldPathSet.find(thisStr) == oldPathSet.end())
|
||||
if (!oldPathSet.contains(thisStr))
|
||||
{
|
||||
pathAppend.append(AZStd::string::format("sys.path.append('%s')\n", thisStr.c_str()));
|
||||
appended = true;
|
||||
|
||||
@@ -221,8 +221,7 @@ sys.version
|
||||
return static_cast<int>(LogTypes::Skip);
|
||||
};
|
||||
|
||||
AZStd::string filename;
|
||||
AzFramework::StringFunc::Path::ConstructFull(m_engineRoot, "Gems/EditorPythonBindings/Code/Tests", "EditorPythonBindingsTest", "py", filename);
|
||||
AZ::IO::Path filename = AZ::IO::PathView(m_engineRoot / "Gems" / "EditorPythonBindings" / "Code" / "Tests" / "EditorPythonBindingsTest.py");
|
||||
|
||||
AZ::Entity e;
|
||||
e.CreateComponent<EditorPythonBindings::PythonSystemComponent>();
|
||||
@@ -284,8 +283,7 @@ sys.version
|
||||
return static_cast<int>(LogTypes::Skip);
|
||||
};
|
||||
|
||||
AZStd::string filename;
|
||||
AzFramework::StringFunc::Path::ConstructFull(m_engineRoot, "Gems/EditorPythonBindings/Code/Tests", "EditorPythonBindingsTestWithArgs", "py", filename);
|
||||
AZ::IO::Path filename = AZ::IO::PathView(m_engineRoot / "Gems" / "EditorPythonBindings" / "Code" / "Tests" / "EditorPythonBindingsTestWithArgs.py");
|
||||
|
||||
AZ::Entity e;
|
||||
e.CreateComponent<EditorPythonBindings::PythonSystemComponent>();
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
#include <AzFramework/Application/Application.h>
|
||||
#include <AzFramework/CommandLine/CommandRegistrationBus.h>
|
||||
|
||||
#include <AzQtComponents/Utilities/QtPluginPaths.h>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
@@ -79,16 +79,14 @@ namespace UnitTest
|
||||
void SetUp() override
|
||||
{
|
||||
// fetch the Engine Root folder
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
int argc = 0;
|
||||
char** argv = nullptr;
|
||||
QCoreApplication qtApp(argc, argv);
|
||||
azsnprintf(m_engineRoot, sizeof(m_engineRoot), AzQtComponents::FindEngineRootDir(nullptr).toLocal8Bit().data());
|
||||
settingsRegistry->Get(m_engineRoot.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
||||
}
|
||||
|
||||
m_fileIOHelper = AZStd::make_unique<FileIOHelper>();
|
||||
m_fileIOHelper->m_fileIO.SetAlias("@devroot@", m_engineRoot);
|
||||
m_fileIOHelper->m_fileIO.SetAlias("@engroot@", m_engineRoot);
|
||||
m_fileIOHelper->m_fileIO.SetAlias("@devroot@", m_engineRoot.c_str());
|
||||
m_fileIOHelper->m_fileIO.SetAlias("@engroot@", m_engineRoot.c_str());
|
||||
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_enableDrilling = false;
|
||||
@@ -141,15 +139,15 @@ namespace UnitTest
|
||||
// required pure virtual overrides
|
||||
void NormalizePath(AZStd::string& ) override {}
|
||||
void NormalizePathKeepCase(AZStd::string& ) override {}
|
||||
void CalculateBranchTokenForAppRoot(AZStd::string& ) const override {}
|
||||
void CalculateBranchTokenForEngineRoot(AZStd::string& ) const override {}
|
||||
// Gets the engine root path for testing
|
||||
const char* GetEngineRoot() const override { return m_engineRoot; }
|
||||
const char* GetEngineRoot() const override { return m_engineRoot.c_str(); }
|
||||
// Retrieves the app root path for testing
|
||||
const char* GetAppRoot() const override { return m_engineRoot; }
|
||||
const char* GetAppRoot() const override { return m_engineRoot.c_str(); }
|
||||
|
||||
AZ::ComponentApplication m_app;
|
||||
AZStd::unique_ptr<FileIOHelper> m_fileIOHelper;
|
||||
AZStd::unique_ptr<CommandRegistrationBusSupression> m_commandRegistrationBusSupression;
|
||||
char m_engineRoot[1024];
|
||||
AZ::IO::FixedMaxPath m_engineRoot;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user