Merge branch 'stabilization/2106' into gitflow_210609

This commit is contained in:
daimini
2021-06-09 14:26:29 -07:00
46 changed files with 138929 additions and 329 deletions
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:92fae957e7559bc486cf11d454dda4e066c1d25f03f7ff43d76f0869c54fec4e
size 41820
oid sha256:68193ec6abac0cb04fd9842d540814d31655b8ffd1c5a9ff1086fe800c0c8c72
size 40812
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:46eadb0c54b22ef320639c05086abb3df6147623da0a15ff85e52a752c1114b4
size 38908
oid sha256:bf9aa8e1075a1f1c3e3e15958106e4f79760e37abfc4e87b823712873984cb8d
size 19516
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6d032e52065468197a83056aabe8565b4add43e046c3bcd0d838c2f41cb96607
size 33420
oid sha256:2cf646a0a977c2edc5ee2ab6351ef633f194ce60c59ea3cb8359f71648db668e
size 374492
@@ -41,7 +41,7 @@ def PrefabLevel_OpensLevelWithEntities():
EXPECTED_EMPTY_ENTITY_POS = Vector3(10.00, 20.0, 30.0)
helper.init_idle()
helper.open_level("prefab", "PrefabLevel_OpensLevelWithEntities")
helper.open_level("Prefab", "PrefabLevel_OpensLevelWithEntities")
def find_entity(entity_name):
searchFilter = entity.SearchFilter()
@@ -1,5 +1,5 @@
{
"Source": "Levels/PrefabLevel_OpensLevelWithEntities/PrefabLevel_OpensLevelWithEntities.prefab",
"Source": "Levels/Prefab/PrefabLevel_OpensLevelWithEntities/PrefabLevel_OpensLevelWithEntities.prefab",
"ContainerEntity": {
"Id": "Entity_[403811863694]",
"Name": "Level",
@@ -15,7 +15,8 @@
"Component_[13764860261821571747]": {
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
"Id": 13764860261821571747,
"Parent Entity": ""
"Parent Entity": "",
"Cached World Transform Parent": ""
},
"Component_[15844324401733835865]": {
"$type": "EditorEntitySortComponent",
+18 -18
View File
@@ -88,28 +88,28 @@ if(NOT INSTALLED_ENGINE)
# Add external subdirectories listed in the engine.json. LY_EXTERNAL_SUBDIRS is a cache variable so the user can add extra
# external subdirectories
add_engine_json_external_subdirectories()
get_property(external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS)
list(APPEND LY_EXTERNAL_SUBDIRS ${external_subdirs})
# Loop over the additional external subdirectories and invoke add_subdirectory on them
foreach(external_directory ${LY_EXTERNAL_SUBDIRS})
# Hash the extenal_directory name and append it to the Binary Directory section of add_subdirectory
# This is to deal with potential situations where multiple external directories has the same last directory name
# For example if D:/Company1/RayTracingGem and F:/Company2/Path/RayTracingGem were both added as a subdirectory
file(REAL_PATH ${external_directory} full_directory_path)
string(SHA256 full_directory_hash ${full_directory_path})
# Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit
# when the external subdirectory contains relative paths of significant length
string(SUBSTRING ${full_directory_hash} 0 8 full_directory_hash)
# Use the last directory as the suffix path to use for the Binary Directory
get_filename_component(directory_name ${external_directory} NAME)
add_subdirectory(${external_directory} ${CMAKE_BINARY_DIR}/External/${directory_name}-${full_directory_hash})
endforeach()
else()
ly_find_o3de_packages()
endif()
get_property(external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS)
list(APPEND LY_EXTERNAL_SUBDIRS ${external_subdirs})
# Loop over the additional external subdirectories and invoke add_subdirectory on them
foreach(external_directory ${LY_EXTERNAL_SUBDIRS})
# Hash the extenal_directory name and append it to the Binary Directory section of add_subdirectory
# This is to deal with potential situations where multiple external directories has the same last directory name
# For example if D:/Company1/RayTracingGem and F:/Company2/Path/RayTracingGem were both added as a subdirectory
file(REAL_PATH ${external_directory} full_directory_path)
string(SHA256 full_directory_hash ${full_directory_path})
# Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit
# when the external subdirectory contains relative paths of significant length
string(SUBSTRING ${full_directory_hash} 0 8 full_directory_hash)
# Use the last directory as the suffix path to use for the Binary Directory
get_filename_component(directory_name ${external_directory} NAME)
add_subdirectory(${external_directory} ${CMAKE_BINARY_DIR}/External/${directory_name}-${full_directory_hash})
endforeach()
################################################################################
# Post-processing
################################################################################
@@ -161,7 +161,56 @@ namespace AZ
return "A pair is an fixed size collection of two elements.";
}
};
template<typename T>
void GetTypeNamesFold(AZStd::vector<AZStd::string>& result, AZ::BehaviorContext& context)
{
result.push_back(OnDemandPrettyName<T>::Get(context));
};
template<typename... T>
void GetTypeNames(AZStd::vector<AZStd::string>& result, AZ::BehaviorContext& context)
{
(GetTypeNamesFold<T>(result, context), ...);
};
template<typename T>
void GetTypeNamesFold(AZStd::string& result, AZ::BehaviorContext& context)
{
if (!result.empty())
{
result += ", ";
}
result += OnDemandPrettyName<T>::Get(context);
};
template<typename... T>
void GetTypeNames(AZStd::string& result, AZ::BehaviorContext& context)
{
(GetTypeNamesFold<T>(result, context), ...);
};
template<typename... T>
struct OnDemandPrettyName<AZStd::tuple<T...>>
{
static AZStd::string Get(AZ::BehaviorContext& context)
{
AZStd::string typeNames;
GetTypeNames<T...>(typeNames, context);
return AZStd::string::format("Tuple<%s>", typeNames.c_str());
}
};
template<typename... T>
struct OnDemandToolTip<AZStd::tuple<T...>>
{
static AZStd::string Get(AZ::BehaviorContext&)
{
return "A tuple is an fixed size collection of any number of any type of element.";
}
};
template<class Key, class MappedType, class Hasher, class EqualKey, class Allocator>
struct OnDemandPrettyName< AZStd::unordered_map<Key, MappedType, Hasher, EqualKey, Allocator> >
{
@@ -813,20 +813,27 @@ namespace AZ
{
using ContainerType = AZStd::tuple<T...>;
template<size_t Index>
static void ReflectUnpackMethodFold(BehaviorContext::ClassBuilder<ContainerType>& builder)
template<typename Targ, size_t Index>
static void ReflectUnpackMethodFold(BehaviorContext::ClassBuilder<ContainerType>& builder, const AZStd::vector<AZStd::string>& typeNames)
{
const AZStd::string methodName = AZStd::string::format("Get%zu", Index);
builder->Method(methodName.data(), [](ContainerType& value) { return AZStd::get<Index>(value); })
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
builder->Method(methodName.data(), [](ContainerType& thisPointer) { return AZStd::get<Index>(thisPointer); })
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::List)
->Attribute(AZ::ScriptCanvasAttributes::TupleGetFunctionIndex, Index)
;
builder->Property
( AZStd::string::format("element_%zu_%s", Index, typeNames[Index].c_str()).c_str()
, [](ContainerType& thisPointer) { return AZStd::get<Index>(thisPointer); }
, [](ContainerType& thisPointer, const Targ& element) { AZStd::get<Index>(thisPointer) = element; });
}
template<size_t... Indices>
template<typename... Targ, size_t... Indices>
static void ReflectUnpackMethods(BehaviorContext::ClassBuilder<ContainerType>& builder, AZStd::index_sequence<Indices...>)
{
(ReflectUnpackMethodFold<Indices>(builder), ...);
AZStd::vector<AZStd::string> typeNames;
ScriptCanvasOnDemandReflection::GetTypeNames<T...>(typeNames, *builder.m_context);
(ReflectUnpackMethodFold<Targ, Indices>(builder, typeNames), ...);
}
static void Reflect(ReflectContext* context)
@@ -851,9 +858,10 @@ namespace AZ
->Attribute(AZ::ScriptCanvasAttributes::TupleConstructorFunction, constructorHolder)
;
ReflectUnpackMethods(builder, AZStd::make_index_sequence<sizeof...(T)>{});
ReflectUnpackMethods<T...>(builder, AZStd::make_index_sequence<sizeof...(T)>{});
builder->Method("GetSize", []() { return AZStd::tuple_size<ContainerType>::value; })
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::List)
;
}
}
+2 -1
View File
@@ -113,7 +113,8 @@ namespace AZ
//! Save a string to a file. Otherwise returns a failure with error message.
AZ::Outcome<void, AZStd::string> WriteFile(AZStd::string_view content, AZStd::string_view filePath);
//! Read a file into a string. Returns a failure with error message if the content could not be loaded.
//! Read a file into a string. Returns a failure with error message if the content could not be loaded or if
//! the file size is larger than the max file size provided.
template<typename Container = AZStd::string>
AZ::Outcome<Container, AZStd::string> ReadFile(AZStd::string_view filePath, size_t maxFileSize = DefaultMaxFileSize);
}
+21 -25
View File
@@ -8,29 +8,25 @@
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/AzTest/Platform/${PAL_PLATFORM_NAME})
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/AzTest/Platform/${PAL_PLATFORM_NAME})
ly_add_target(
NAME AzTest STATIC
NAMESPACE AZ
FILES_CMAKE
AzTest/aztest_files.cmake
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
.
${pal_dir}
BUILD_DEPENDENCIES
PUBLIC
3rdParty::googletest::GMock
3rdParty::googletest::GTest
3rdParty::GoogleBenchmark
AZ::AzCore
PLATFORM_INCLUDE_FILES
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
)
endif()
ly_add_target(
NAME AzTest STATIC
NAMESPACE AZ
FILES_CMAKE
AzTest/aztest_files.cmake
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
.
${pal_dir}
BUILD_DEPENDENCIES
PUBLIC
3rdParty::googletest::GMock
3rdParty::googletest::GTest
3rdParty::GoogleBenchmark
AZ::AzCore
PLATFORM_INCLUDE_FILES
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
)
@@ -185,13 +185,7 @@ namespace AzToolsFramework
bool PrefabEditorEntityOwnershipService::LoadFromStream(AZ::IO::GenericStream& stream, AZStd::string_view filename)
{
Reset();
// Make loading from stream to behave the same in terms of filesize as regular loading of prefabs
// This may need to be revisited in the future for supporting higher sizes along with prefab loading
if (stream.GetLength() > Prefab::MaxPrefabFileSize)
{
AZ_Error("Prefab", false, "'%.*s' prefab content is bigger than the max supported size (%f MB)", AZ_STRING_ARG(filename), Prefab::MaxPrefabFileSize / (1024.f * 1024.f));
return false;
}
const size_t bufSize = stream.GetLength();
AZStd::unique_ptr<char[]> buf(new char[bufSize]);
AZ::IO::SizeType bytes = stream.Read(bufSize, buf.get());
@@ -74,7 +74,7 @@ namespace AzToolsFramework
return InvalidTemplateId;
}
auto readResult = AZ::Utils::ReadFile(GetFullPath(filePath).Native(), MaxPrefabFileSize);
auto readResult = AZ::Utils::ReadFile(GetFullPath(filePath).Native(), AZStd::numeric_limits<size_t>::max());
if (!readResult.IsSuccess())
{
AZ_Error(
@@ -21,8 +21,6 @@ namespace AzToolsFramework
{
namespace Prefab
{
constexpr size_t MaxPrefabFileSize = 1024 * 1024;
/*!
* PrefabLoaderInterface
* Interface for saving/loading Prefab files.
@@ -901,7 +901,13 @@ namespace AzToolsFramework
return AZ::Failure(AZStd::string("No entities to duplicate."));
}
if (!EntitiesBelongToSameInstance(entityIds))
const EntityIdList entityIdsNoLevelInstance = GenerateEntityIdListWithoutLevelInstance(entityIds);
if (entityIdsNoLevelInstance.empty())
{
return AZ::Failure(AZStd::string("No entities to duplicate because only instance selected is the level instance."));
}
if (!EntitiesBelongToSameInstance(entityIdsNoLevelInstance))
{
return AZ::Failure(AZStd::string("Cannot duplicate multiple entities belonging to different instances with one operation."
"Change your selection to contain entities in the same instance."));
@@ -909,7 +915,7 @@ namespace AzToolsFramework
// We've already verified the entities are all owned by the same instance,
// so we can just retrieve our instance from the first entity in the list.
AZ::EntityId firstEntityIdToDuplicate = entityIds[0];
AZ::EntityId firstEntityIdToDuplicate = entityIdsNoLevelInstance[0];
InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDuplicate);
if (!commonOwningInstance.has_value())
{
@@ -929,7 +935,7 @@ namespace AzToolsFramework
// This will cull out any entities that have ancestors in the list, since we will end up duplicating
// the full nested hierarchy with what is returned from RetrieveAndSortPrefabEntitiesAndInstances
AzToolsFramework::EntityIdSet duplicationSet = AzToolsFramework::GetCulledEntityHierarchy(entityIds);
AzToolsFramework::EntityIdSet duplicationSet = AzToolsFramework::GetCulledEntityHierarchy(entityIdsNoLevelInstance);
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
@@ -1004,17 +1010,19 @@ namespace AzToolsFramework
PrefabOperationResult PrefabPublicHandler::DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants)
{
if (entityIds.empty())
const EntityIdList entityIdsNoLevelInstance = GenerateEntityIdListWithoutLevelInstance(entityIds);
if (entityIdsNoLevelInstance.empty())
{
return AZ::Success();
}
if (!EntitiesBelongToSameInstance(entityIds))
if (!EntitiesBelongToSameInstance(entityIdsNoLevelInstance))
{
return AZ::Failure(AZStd::string("Cannot delete multiple entities belonging to different instances with one operation."));
}
AZ::EntityId firstEntityIdToDelete = entityIds[0];
AZ::EntityId firstEntityIdToDelete = entityIdsNoLevelInstance[0];
InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDelete);
// If the first entity id is a container entity id, then we need to mark its parent as the common owning instance because you
@@ -1025,7 +1033,7 @@ namespace AzToolsFramework
}
// Retrieve entityList from entityIds
EntityList inputEntityList = EntityIdListToEntityList(entityIds);
EntityList inputEntityList = EntityIdListToEntityList(entityIdsNoLevelInstance);
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
@@ -1081,7 +1089,7 @@ namespace AzToolsFramework
}
else
{
for (AZ::EntityId entityId : entityIds)
for (AZ::EntityId entityId : entityIdsNoLevelInstance)
{
InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
// If this is the container entity, it actually represents the instance so get its owner
@@ -1437,6 +1445,22 @@ namespace AzToolsFramework
return (outEntities.size() + outInstances.size()) > 0;
}
EntityIdList PrefabPublicHandler::GenerateEntityIdListWithoutLevelInstance(
const EntityIdList& entityIds) const
{
EntityIdList outEntityIds;
outEntityIds.reserve(entityIds.size()); // Actual size could be smaller.
for (const AZ::EntityId& entityId : entityIds)
{
if (!IsLevelInstanceContainerEntity(entityId))
{
outEntityIds.emplace_back(entityId);
}
}
return outEntityIds;
}
bool PrefabPublicHandler::EntitiesBelongToSameInstance(const EntityIdList& entityIds) const
{
if (entityIds.size() <= 1)
@@ -70,6 +70,7 @@ namespace AzToolsFramework
PrefabOperationResult DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants);
bool RetrieveAndSortPrefabEntitiesAndInstances(const EntityList& inputEntities, Instance& commonRootEntityOwningInstance,
EntityList& outEntities, AZStd::vector<Instance*>& outInstances) const;
EntityIdList GenerateEntityIdListWithoutLevelInstance(const EntityIdList& entityIds) const;
InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const;
bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const;
@@ -16,6 +16,7 @@ set_property(GLOBAL PROPERTY LAUNCHER_UNIFIED_BINARY_DIR ${CMAKE_CURRENT_BINARY_
# When using an installed engine, this file will be included by the FindLauncherGenerator.cmake script
get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME)
foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJECTS)
# Computes the realpath to the project
# If the project_path is relative, it is evaluated relative to the ${LY_ROOT_FOLDER}
# Otherwise the the absolute project_path is returned with symlinks resolved
@@ -35,6 +36,28 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC
"to the LY_PROJECTS_TARGET_NAME global property. Other configuration errors might occur")
endif()
endif()
################################################################################
# Assets
################################################################################
if(PAL_TRAIT_BUILD_HOST_TOOLS)
add_custom_target(${project_name}.Assets
COMMENT "Processing ${project_name} assets..."
COMMAND "${CMAKE_COMMAND}"
-DLY_LOCK_FILE=$<TARGET_FILE_DIR:AZ::AssetProcessorBatch>/project_assets.lock
-P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake
EXEC_COMMAND $<TARGET_FILE:AZ::AssetProcessorBatch>
--zeroAnalysisMode
--project-path=${project_real_path}
--platforms=${LY_ASSET_DEPLOY_ASSET_TYPE}
)
set_target_properties(${project_name}.Assets
PROPERTIES
EXCLUDE_FROM_ALL TRUE
FOLDER ${project_name}
)
endif()
################################################################################
# Monolithic game
################################################################################
+3
View File
@@ -729,6 +729,9 @@ bool CCryEditDoc::SaveModified()
void CCryEditDoc::OnFileSaveAs()
{
CLevelFileDialog levelFileDialog(false);
levelFileDialog.show();
levelFileDialog.adjustSize();
if (levelFileDialog.exec() == QDialog::Accepted)
{
if (OnSaveDocument(levelFileDialog.GetFileName()))
+20 -16
View File
@@ -9,12 +9,12 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
include(${pal_dir}/platform_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
include(${pal_dir}/platform_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
if(PAL_TRAIT_AZTESTRUNNER_SUPPORTED)
ly_add_target(
NAME AzTestRunner ${PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE}
NAMESPACE AZ
@@ -32,19 +32,23 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
AZ::AzTest
AZ::AzFramework
)
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME AzTestRunner.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE AZ
FILES_CMAKE
aztestrunner_test_files.cmake
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
)
ly_add_target(
NAME AzTestRunner.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE AZ
FILES_CMAKE
aztestrunner_test_files.cmake
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
)
ly_add_googletest(
NAME AZ::AzTestRunner.Tests
)
ly_add_googletest(
NAME AZ::AzTestRunner.Tests
)
endif()
endif()
@@ -9,5 +9,5 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_AZTESTRUNNER_SUPPORTED TRUE)
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE MODULE)
@@ -9,5 +9,5 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_AZTESTRUNNER_SUPPORTED TRUE)
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
@@ -9,5 +9,5 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_AZTESTRUNNER_SUPPORTED TRUE)
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
@@ -9,5 +9,5 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_AZTESTRUNNER_SUPPORTED TRUE)
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
@@ -9,5 +9,5 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_AZTESTRUNNER_SUPPORTED TRUE)
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
@@ -151,7 +151,6 @@ namespace O3DE::ProjectManager
void ProjectButton::ReadySetup()
{
connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); });
connect(m_projectImageLabel->GetBuildButton(), &QPushButton::clicked, [this](){ emit BuildProject(m_projectInfo); });
QMenu* menu = new QMenu(this);
@@ -452,9 +452,9 @@ namespace O3DE::ProjectManager
return result;
}
AZ::Outcome<GemInfo> PythonBindings::GetGemInfo(const QString& path)
AZ::Outcome<GemInfo> PythonBindings::GetGemInfo(const QString& path, const QString& projectPath)
{
GemInfo gemInfo = GemInfoFromPath(pybind11::str(path.toStdString()));
GemInfo gemInfo = GemInfoFromPath(pybind11::str(path.toStdString()), pybind11::str(projectPath.toStdString()));
if (gemInfo.IsValid())
{
return AZ::Success(AZStd::move(gemInfo));
@@ -473,7 +473,7 @@ namespace O3DE::ProjectManager
{
for (auto path : m_manifest.attr("get_engine_gems")())
{
gems.push_back(GemInfoFromPath(path));
gems.push_back(GemInfoFromPath(path, pybind11::none()));
}
});
if (!result.IsSuccess())
@@ -494,7 +494,7 @@ namespace O3DE::ProjectManager
pybind11::str pyProjectPath = projectPath.toStdString();
for (auto path : m_manifest.attr("get_all_gems")(pyProjectPath))
{
gems.push_back(GemInfoFromPath(path));
gems.push_back(GemInfoFromPath(path, pyProjectPath));
}
});
if (!result.IsSuccess())
@@ -632,12 +632,12 @@ namespace O3DE::ProjectManager
}
}
GemInfo PythonBindings::GemInfoFromPath(pybind11::handle path)
GemInfo PythonBindings::GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath)
{
GemInfo gemInfo;
gemInfo.m_path = Py_To_String(path);
auto data = m_manifest.attr("get_gem_json_data")(pybind11::none(), path);
auto data = m_manifest.attr("get_gem_json_data")(pybind11::none(), path, pyProjectPath);
if (pybind11::isinstance<pybind11::dict>(data))
{
try
@@ -782,12 +782,12 @@ namespace O3DE::ProjectManager
});
}
ProjectTemplateInfo PythonBindings::ProjectTemplateInfoFromPath(pybind11::handle path)
ProjectTemplateInfo PythonBindings::ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath)
{
ProjectTemplateInfo templateInfo;
templateInfo.m_path = Py_To_String(pybind11::str(path));
auto data = m_manifest.attr("get_template_json_data")(pybind11::none(), path);
auto data = m_manifest.attr("get_template_json_data")(pybind11::none(), path, pyProjectPath);
if (pybind11::isinstance<pybind11::dict>(data))
{
try
@@ -829,14 +829,15 @@ namespace O3DE::ProjectManager
return templateInfo;
}
AZ::Outcome<QVector<ProjectTemplateInfo>> PythonBindings::GetProjectTemplates()
AZ::Outcome<QVector<ProjectTemplateInfo>> PythonBindings::GetProjectTemplates(const QString& projectPath)
{
QVector<ProjectTemplateInfo> templates;
bool result = ExecuteWithLock([&] {
pybind11::str pyProjectPath = projectPath.toStdString();
for (auto path : m_manifest.attr("get_templates_for_project_creation")())
{
templates.push_back(ProjectTemplateInfoFromPath(path));
templates.push_back(ProjectTemplateInfoFromPath(path, pyProjectPath));
}
});
@@ -39,7 +39,7 @@ namespace O3DE::ProjectManager
bool SetEngineInfo(const EngineInfo& engineInfo) override;
// Gem
AZ::Outcome<GemInfo> GetGemInfo(const QString& path) override;
AZ::Outcome<GemInfo> GetGemInfo(const QString& path, const QString& projectPath = {}) override;
AZ::Outcome<QVector<GemInfo>, AZStd::string> GetEngineGemInfos() override;
AZ::Outcome<QVector<GemInfo>, AZStd::string> GetAllGemInfos(const QString& projectPath) override;
AZ::Outcome<QVector<AZStd::string>, AZStd::string> GetEnabledGemNames(const QString& projectPath) override;
@@ -55,16 +55,16 @@ namespace O3DE::ProjectManager
AZ::Outcome<void, AZStd::string> RemoveGemFromProject(const QString& gemPath, const QString& projectPath) override;
// ProjectTemplate
AZ::Outcome<QVector<ProjectTemplateInfo>> GetProjectTemplates() override;
AZ::Outcome<QVector<ProjectTemplateInfo>> GetProjectTemplates(const QString& projectPath = {}) override;
private:
AZ_DISABLE_COPY_MOVE(PythonBindings);
AZ::Outcome<void, AZStd::string> ExecuteWithLockErrorHandling(AZStd::function<void()> executionCallback);
bool ExecuteWithLock(AZStd::function<void()> executionCallback);
GemInfo GemInfoFromPath(pybind11::handle path);
GemInfo GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
ProjectInfo ProjectInfoFromPath(pybind11::handle path);
ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path);
ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
bool RegisterThisEngine();
bool StartPython();
bool StopPython();
@@ -57,7 +57,7 @@ namespace O3DE::ProjectManager
* @param path the absolute path to the Gem
* @return an outcome with GemInfo on success
*/
virtual AZ::Outcome<GemInfo> GetGemInfo(const QString& path) = 0;
virtual AZ::Outcome<GemInfo> GetGemInfo(const QString& path, const QString& projectPath = {}) = 0;
/**
* Get all available gem infos. This concatenates gems registered by the engine and the project.
@@ -147,7 +147,7 @@ namespace O3DE::ProjectManager
* Get info about all known project templates
* @return an outcome with ProjectTemplateInfos on success
*/
virtual AZ::Outcome<QVector<ProjectTemplateInfo>> GetProjectTemplates() = 0;
virtual AZ::Outcome<QVector<ProjectTemplateInfo>> GetProjectTemplates(const QString& projectPath = {}) = 0;
};
using PythonBindingsInterface = AZ::Interface<IPythonBindings>;
@@ -135,6 +135,12 @@ namespace AZ
{
const RHI::ShaderInputBufferUnboundedArrayIndex index(groupIndex);
auto bufViews = groupData.GetBufferViewUnboundedArray(index);
if (bufViews.empty())
{
// skip empty unbounded arrays
continue;
}
uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferViewUnboundedArray);
descriptorSet.UpdateBufferViews(layoutIndex, bufViews);
}
@@ -144,6 +150,12 @@ namespace AZ
{
const RHI::ShaderInputImageUnboundedArrayIndex index(groupIndex);
auto imgViews = groupData.GetImageViewUnboundedArray(index);
if (imgViews.empty())
{
// skip empty unbounded arrays
continue;
}
uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageViewUnboundedArray);
descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageUnboundeArrayList[groupIndex].m_type);
}
@@ -718,7 +718,8 @@ namespace EditorPythonBindings
for (int arg = 0; arg < args.size(); arg++)
{
argv[arg + 1] = Py_DecodeLocale(args[arg].data(), nullptr);
AZStd::string argString(args[arg]);
argv[arg + 1] = Py_DecodeLocale(argString.c_str(), nullptr);
}
// Tell Python the command-line args.
// Note that this has a side effect of adding the script's path to the set of directories checked for "import" commands.
@@ -693,7 +693,7 @@ namespace ImGui
ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "Left Stick");
ImGui::NextColumn();
ImGui::Bullet();
ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "Mova Mouse Pointer");
ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "Move Mouse Pointer");
ImGui::Separator();
ImGui::NextColumn();
@@ -13,6 +13,7 @@
#include <PhysX_precompiled.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/parallel/scoped_lock.h>
#include <AzFramework/Physics/PhysicsScene.h>
#include <AzFramework/Physics/PhysicsSystem.h>
#include <AzFramework/Physics/SystemBus.h>
@@ -40,6 +41,8 @@ namespace PhysX
} // namespace Internal
// PhysX::Ragdoll
/*static*/ AZStd::mutex Ragdoll::m_sceneEventMutex;
void Ragdoll::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
@@ -114,7 +117,10 @@ namespace PhysX
Ragdoll::~Ragdoll()
{
m_sceneStartSimHandler.Disconnect();
{
AZStd::scoped_lock lock(m_sceneEventMutex);
m_sceneStartSimHandler.Disconnect();
}
m_nodes.clear(); //the nodes destructor will remove the simulated body from the scene.
}
@@ -212,7 +218,13 @@ namespace PhysX
}
}
sceneInterface->RegisterSceneSimulationStartHandler(m_sceneOwner, m_sceneStartSimHandler);
// the handler is also connected in EnableSimulationQueued(),
// which will call this function, so if called from that path dont connect here.
if (!m_sceneStartSimHandler.IsConnected())
{
AZStd::scoped_lock lock(m_sceneEventMutex);
sceneInterface->RegisterSceneSimulationStartHandler(m_sceneOwner, m_sceneStartSimHandler);
}
sceneInterface->EnableSimulationOfBody(m_sceneOwner, m_bodyHandle);
}
@@ -225,6 +237,7 @@ namespace PhysX
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
{
AZStd::scoped_lock lock(m_sceneEventMutex);
sceneInterface->RegisterSceneSimulationStartHandler(m_sceneOwner, m_sceneStartSimHandler);
}
@@ -244,7 +257,10 @@ namespace PhysX
return;
}
m_sceneStartSimHandler.Disconnect();
{
AZStd::scoped_lock lock(m_sceneEventMutex);
m_sceneStartSimHandler.Disconnect();
}
physx::PxScene* pxScene = Internal::GetPxScene(m_sceneOwner);
const size_t numNodes = m_nodes.size();
@@ -12,6 +12,7 @@
#pragma once
#include <AzCore/std/parallel/mutex.h>
#include <AzFramework/Physics/RagdollPhysicsBus.h>
#include <AzFramework/Physics/Ragdoll.h>
#include <AzFramework/Physics/Common/PhysicsEvents.h>
@@ -84,5 +85,6 @@ namespace PhysX
bool m_queuedDisableSimulation = false;
AzPhysics::SceneEvents::OnSceneSimulationStartHandler m_sceneStartSimHandler;
static AZStd::mutex m_sceneEventMutex;
};
} // namespace PhysX
@@ -3356,23 +3356,27 @@ namespace ScriptCanvas
if (executionIf->GetId().m_node->IsIfBranchPrefacedWithBooleanExpression())
{
auto removeChildOutcome = RemoveChild(executionIf->ModParent(), executionIf);
if (!removeChildOutcome.IsSuccess())
ExecutionTreePtr booleanExpression;
{
AddError(executionIf->GetNodeId(), executionIf, ScriptCanvas::ParseErrors::FailedToRemoveChild);
auto removeChildOutcome = RemoveChild(executionIf->ModParent(), executionIf);
if (!removeChildOutcome.IsSuccess())
{
AddError(executionIf->GetNodeId(), executionIf, ScriptCanvas::ParseErrors::FailedToRemoveChild);
}
if (!IsErrorFree())
{
return;
}
const auto indexAndChild = removeChildOutcome.TakeValue();
booleanExpression = CreateChild(executionIf->ModParent(), executionIf->GetId().m_node, executionIf->GetId().m_slot);
executionIf->ModParent()->InsertChild(indexAndChild.first, { indexAndChild.second.m_slot, indexAndChild.second.m_output, booleanExpression });
executionIf->SetParent(booleanExpression);
}
if (!IsErrorFree())
{
return;
}
const auto indexAndChild = removeChildOutcome.TakeValue();
ExecutionTreePtr booleanExpression = CreateChild(executionIf->ModParent(), executionIf->GetId().m_node, executionIf->GetId().m_slot);
executionIf->ModParent()->InsertChild(indexAndChild.first, { indexAndChild.second.m_slot, indexAndChild.second.m_output, booleanExpression });
executionIf->SetParent(booleanExpression);
// make a condition here
auto symbol = CheckLogicalExpressionSymbol(booleanExpression);
if (symbol != Symbol::FunctionCall && symbol != Symbol::Count)
@@ -3402,7 +3406,7 @@ namespace ScriptCanvas
return;
}
const auto indexAndChild2 = removeChildOutcome.TakeValue();
const auto indexAndChild2 = removeChildOutcome2.TakeValue();
// parse if statement internal function
ExecutionTreePtr internalFunction = CreateChild(booleanExpression->ModParent(), booleanExpression->GetId().m_node, booleanExpression->GetId().m_slot);
@@ -4782,7 +4786,7 @@ namespace ScriptCanvas
{
PropertyExtractionPtr extraction = AZStd::make_shared<PropertyExtraction>();
extraction->m_slot = slot;
extraction->m_name = propertyField.first;
extraction->m_name = AZ::ReplaceCppArtifacts(propertyField.first);
execution->AddPropertyExtractionSource(slot, extraction);
}
else
@@ -90,6 +90,11 @@ public:
}
};
TEST_F(ScriptCanvasTestFixture, ParseFunctionIfBranchWithConnectedInput)
{
RunUnitTestGraph("LY_SC_UnitTest_ParseFunctionIfBranchWithConnectedInput");
}
TEST_F(ScriptCanvasTestFixture, UseRawBehaviorProperties)
{
RunUnitTestGraph("LY_SC_UnitTest_UseRawBehaviorProperties");
+12 -1
View File
@@ -162,7 +162,18 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME)
elseif(target_type STREQUAL MODULE_LIBRARY)
set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/${target_library_output_subdirectory}/$<TARGET_FILE_NAME:${TARGET_NAME}>")
elseif(target_type STREQUAL SHARED_LIBRARY)
string(APPEND target_file_contents "set_property(TARGET ${TARGET_NAME} PROPERTY IMPORTED_IMPLIB_$<CONFIG> \"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>\")\n")
string(APPEND target_file_contents
"set_property(TARGET ${TARGET_NAME}
APPEND_STRING PROPERTY IMPORTED_IMPLIB
$<$<CONFIG:$<CONFIG>$<ANGLE-R>:\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>\"$<ANGLE-R>
)
")
string(APPEND target_file_contents
"set_property(TARGET ${TARGET_NAME}
PROPERTY IMPORTED_IMPLIB_$<UPPER_CASE:$<CONFIG>>
\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>\"
)
")
set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/${target_library_output_subdirectory}/$<TARGET_FILE_NAME:${TARGET_NAME}>")
else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY
set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>")
@@ -10,5 +10,5 @@
#
if(CMAKE_GENERATOR MATCHES "Visual Studio 16")
configure_file("${CMAKE_CURRENT_LIST_DIR}/Directory.Build.props" "${CMAKE_CURRENT_BINARY_DIR}/Directory.Build.props" COPYONLY)
configure_file("${CMAKE_CURRENT_LIST_DIR}/Directory.Build.props" "${CMAKE_BINARY_DIR}/Directory.Build.props" COPYONLY)
endif()
-29
View File
@@ -16,35 +16,6 @@ if(NOT PAL_TRAIT_BUILD_TESTS_SUPPORTED)
return()
endif()
################################################################################
# Asset Processing Target
# i.e. Tests depend on AutomatedTesting.Assets
################################################################################
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME)
foreach(project_target_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJECTS)
file(REAL_PATH ${project_path} project_real_path BASE_DIRECTORY ${LY_ROOT_FOLDER})
# With the lock file, asset processing jobs are serialized to avoid race conditions
# on files that are created temporarily in source folders during shader processing.
add_custom_target(${project_target_name}.Assets
COMMENT "Processing ${project_target_name} assets..."
COMMAND "${CMAKE_COMMAND}"
-DLY_LOCK_FILE=$<TARGET_FILE_DIR:AZ::AssetProcessorBatch>/project_assets.lock
-P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake
EXEC_COMMAND $<TARGET_FILE:AZ::AssetProcessorBatch>
--zeroAnalysisMode
--project-path=${project_real_path}
--platforms=${LY_ASSET_DEPLOY_ASSET_TYPE}
)
set_target_properties(${project_target_name}.Assets
PROPERTIES
EXCLUDE_FROM_ALL TRUE
FOLDER ${project_target_name}
)
endforeach()
endif()
################################################################################
# Tests
################################################################################
+79 -21
View File
@@ -40,26 +40,52 @@ def add_gem_dependency(cmake_file: pathlib.Path,
# on a line by basis, see if there already is {gem_name}
# find the first occurrence of a gem, copy its formatting and replace
# the gem name with the new one and append it
# if the gem is already present fail
t_data = []
added = False
line_index_to_append = None
with open(cmake_file, 'r') as s:
start_marker_line_index = None
end_marker_line_index = None
with cmake_file.open('r') as s:
in_gem_list = False
line_index = 0
for line in s:
if line.strip().startswith(enable_gem_start_marker):
line_index_to_append = line_index
if f'{gem_name}' == line.strip():
logger.warning(f'{gem_name} is already enabled in file {str(cmake_file)}.')
return 0
parsed_line = line.strip()
if parsed_line.startswith(enable_gem_start_marker):
# Skip pass the 'set(ENABLED_GEMS' marker just in case their are gems declared on the same line
parsed_line = parsed_line[len(enable_gem_start_marker):]
# Set the flag to indicate that we are in the ENABLED_GEMS variable
in_gem_list = True
start_marker_line_index = line_index
if in_gem_list:
# Since we are inside the ENABLED_GEMS variable determine if the line has the end_marker of ')'
if parsed_line.endswith(enable_gem_end_marker):
# Strip away the line end marker
parsed_line = parsed_line[:-len(enable_gem_end_marker)]
# Set the flag to indicate that we are no longer in the ENABLED_GEMS variable after this line
in_gem_list = False
end_marker_line_index = line_index
# Split the rest of the line on whitespace just in case there are multiple gems in a line
gem_name_list = map(lambda gem_name: gem_name.strip('"'), parsed_line.split())
if gem_name in gem_name_list:
logger.warning(f'{gem_name} is already enabled in file {str(cmake_file)}.')
return 0
t_data.append(line)
line_index += 1
indent = 4
if line_index_to_append:
# Insert the gem after the 'set(ENABLED_GEMS)...` line
t_data.insert(line_index_to_append + 1, f'{" " * indent}{gem_name}\n')
if start_marker_line_index:
# Make sure if there is a enable gem start marker, there is an end marker as well
if not end_marker_line_index:
logger.error(f'The Enable Gem start marker of "{enable_gem_start_marker}" has been found, but not the'
f' Enable Gem end marker of "{enable_gem_end_marker}"')
return 1
# Insert the gem before the ')' end marker
end_marker_partition = list(t_data[end_marker_line_index].rpartition(enable_gem_end_marker))
end_marker_partition[1] = f'{" " * indent}{gem_name}\n' + end_marker_partition[1]
t_data[end_marker_line_index] = ''.join(end_marker_partition)
added = True
# if we didn't add, then create a new set(ENABLED_GEMS) variable
@@ -71,7 +97,7 @@ def add_gem_dependency(cmake_file: pathlib.Path,
t_data.append(f'{enable_gem_end_marker}\n')
# write the cmake
with open(cmake_file, 'w') as s:
with cmake_file.open('w') as s:
s.writelines(t_data)
return 0
@@ -90,12 +116,44 @@ def remove_gem_dependency(cmake_file: pathlib.Path,
# on a line by basis, remove any line with {gem_name}
t_data = []
# Remove the gem from the enabled_gem file by skipping the gem name entry
removed = False
with open(cmake_file, 'r') as s:
with cmake_file.open('r') as s:
in_gem_list = False
for line in s:
if gem_name == line.strip():
removed = True
# Strip whitespace from both ends of the line, but keep track of the leading whitespace
# for indenting the result line
parsed_line = line.lstrip()
indent = line[:-len(parsed_line)]
parsed_line = parsed_line.rstrip()
result_line = indent
if parsed_line.startswith(enable_gem_start_marker):
# Skip pass the 'set(ENABLED_GEMS' marker just in case their are gems declared on the same line
parsed_line = parsed_line[len(enable_gem_start_marker):]
result_line += enable_gem_start_marker
# Set the flag to indicate that we are in the ENABLED_GEMS variable
in_gem_list = True
if in_gem_list:
# Since we are inside the ENABLED_GEMS variable determine if the line has the end_marker of ')'
if parsed_line.endswith(enable_gem_end_marker):
# Strip away the line end marker
parsed_line = parsed_line[:-len(enable_gem_end_marker)]
# Set the flag to indicate that we are no longer in the ENABLED_GEMS variable after this line
in_gem_list = False
# Split the rest of the line on whitespace just in case there are multiple gems in a line
# Strip double quotes surround any gem name
gem_name_list = list(map(lambda gem_name: gem_name.strip('"'), parsed_line.split()))
while gem_name in gem_name_list:
gem_name_list.remove(gem_name)
removed = True
# Append the renaming gems to the line
result_line += ' '.join(gem_name_list)
# If the in_gem_list was flipped to false, that means the currently parsed line contained the
# line end marker, so append that to the result_line
result_line += enable_gem_end_marker if not in_gem_list else ''
t_data.append(result_line + '\n')
else:
t_data.append(line)
@@ -104,14 +162,14 @@ def remove_gem_dependency(cmake_file: pathlib.Path,
return 1
# write the cmake
with open(cmake_file, 'w') as s:
with cmake_file.open('w') as s:
s.writelines(t_data)
return 0
def get_project_gems(project_path: pathlib.Path,
platform: str = 'Common') -> set:
platform: str = 'Common') -> set:
return get_gems_from_cmake_file(get_enabled_gem_cmake_file(project_path=project_path, platform=platform))
@@ -145,7 +203,7 @@ def get_enabled_gems(cmake_file: pathlib.Path) -> set:
# Set the flag to indicate that we are no longer in the ENABLED_GEMS variable after this line
in_gem_list = False
# Split the rest of the line on whitespace just in case there are multiple gems in a line
gem_name_list = line.split()
gem_name_list = list(map(lambda gem_name: gem_name.strip('"'), line.split()))
gem_target_set.update(gem_name_list)
return gem_target_set
@@ -156,7 +214,7 @@ def get_project_gem_paths(project_path: pathlib.Path,
gem_names = get_project_gems(project_path, platform)
gem_paths = set()
for gem_name in gem_names:
gem_paths.add(manifest.get_registered(gem_name=gem_name))
gem_paths.add(manifest.get_registered(gem_name=gem_name, project_path=project_path))
return gem_paths
+2 -2
View File
@@ -64,7 +64,7 @@ def disable_gem_in_project(gem_name: str = None,
# if gem name resolve it into a path
if gem_name and not gem_path:
gem_path = manifest.get_registered(gem_name=gem_name)
gem_path = manifest.get_registered(gem_name=gem_name, project_path=project_path)
if not gem_path:
logger.error(f'Unable to locate gem path from the registered manifest.json files:'
f' {str(pathlib.Path.home() / ".o3de/manifest.json")},'
@@ -78,7 +78,7 @@ def disable_gem_in_project(gem_name: str = None,
# Read gem.json from the gem path
gem_json_data = manifest.get_gem_json_data(gem_path=gem_path)
gem_json_data = manifest.get_gem_json_data(gem_path=gem_path, project_path=project_path)
if not gem_json_data:
logger.error(f'Could not read gem.json content under {gem_path}.')
return 1
+2 -2
View File
@@ -64,7 +64,7 @@ def enable_gem_in_project(gem_name: str = None,
# if gem name resolve it into a path
if gem_name and not gem_path:
gem_path = manifest.get_registered(gem_name=gem_name)
gem_path = manifest.get_registered(gem_name=gem_name, project_path=project_path)
if not gem_path:
logger.error(f'Unable to locate gem path from the registered manifest.json files:'
f' {str(pathlib.Path( "~/.o3de/o3de_manifest.json").expanduser())},'
@@ -78,7 +78,7 @@ def enable_gem_in_project(gem_name: str = None,
return 1
# Read gem.json from the gem path
gem_json_data = manifest.get_gem_json_data(gem_path=gem_path)
gem_json_data = manifest.get_gem_json_data(gem_path=gem_path, project_path=project_path)
if not gem_json_data:
logger.error(f'Could not read gem.json content under {gem_path}.')
return 1
+39 -14
View File
@@ -354,7 +354,7 @@ def get_all_templates(project_path: pathlib.Path = None) -> list:
return list(dict.fromkeys(templates_data))
def get_all_restricted() -> list:
def get_all_restricted(project_path: pathlib.Path = None) -> list:
restricted_data = get_restricted()
restricted_data.extend(get_engine_restricted())
if project_path:
@@ -488,14 +488,14 @@ def get_project_json_data(project_name: str = None,
return None
def get_gem_json_data(gem_name: str = None,
gem_path: str or pathlib.Path = None) -> dict or None:
def get_gem_json_data(gem_name: str = None, gem_path: str or pathlib.Path = None,
project_path: pathlib.Path = None) -> dict or None:
if not gem_name and not gem_path:
logger.error('Must specify either a Gem name or Gem Path.')
return None
if gem_name and not gem_path:
gem_path = get_registered(gem_name=gem_name)
gem_path = get_registered(gem_name=gem_name, project_path=project_path)
if not gem_path:
logger.error(f'Gem Path {gem_path} has not been registered.')
@@ -521,14 +521,14 @@ def get_gem_json_data(gem_name: str = None,
return None
def get_template_json_data(template_name: str = None,
template_path: str or pathlib.Path = None) -> dict or None:
def get_template_json_data(template_name: str = None, template_path: str or pathlib.Path = None,
project_path: pathlib.Path = None) -> dict or None:
if not template_name and not template_path:
logger.error('Must specify either a Template name or Template Path.')
return None
if template_name and not template_path:
template_path = get_registered(template_name=template_name)
template_path = get_registered(template_name=template_name, project_path=project_path)
if not template_path:
logger.error(f'Template Path {template_path} has not been registered.')
@@ -554,14 +554,14 @@ def get_template_json_data(template_name: str = None,
return None
def get_restricted_json_data(restricted_name: str = None,
restricted_path: str or pathlib.Path = None) -> dict or None:
def get_restricted_json_data(restricted_name: str = None, restricted_path: str or pathlib.Path = None,
project_path: pathlib.Path = None) -> dict or None:
if not restricted_name and not restricted_path:
logger.error('Must specify either a Restricted name or Restricted Path.')
return None
if restricted_name and not restricted_path:
restricted_path = get_registered(restricted_name=restricted_name)
restricted_path = get_registered(restricted_name=restricted_name, project_path=project_path)
if not restricted_path:
logger.error(f'Restricted Path {restricted_path} has not been registered.')
@@ -593,7 +593,32 @@ def get_registered(engine_name: str = None,
template_name: str = None,
default_folder: str = None,
repo_name: str = None,
restricted_name: str = None) -> pathlib.Path or None:
restricted_name: str = None,
project_path: pathlib.Path = None) -> pathlib.Path or None:
"""
Looks up a registered entry in either the ~/.o3de/o3de_manifest.json, <this-engine-root>/engine.json
or the <project-path>/project.json (if the project_path parameter is supplied)
:param engine_name: Name of a registered engine to lookup in the ~/.o3de/o3de_manifest.json file
:param project_name: Name of a project to lookup in either the ~/.o3de/o3de_manifest.json or
<this-engine-root>/engine.json file
:param gem_name: Name of a gem to lookup in either the ~/.o3de/o3de_manifest.json, <this-engine-root>/engine.json
or <project-path>/project.json. NOTE: The project_path parameter must be supplied to lookup the registration
with the project.json
:param template_name: Name of a template to lookup in either the ~/.o3de/o3de_manifest.json, <this-engine-root>/engine.json
or <project-path>/project.json. NOTE: The project_path parameter must be supplied to lookup the registration
with the project.json
:param repo_name: Name of a repo to lookup in the ~/.o3de/o3de_manifest.json
:param default_folder: Type of "default" folder to lookup in the ~/.o3de/o3de_manifest.json
Valid values are "engines", "projects", "gems", "templates,", "restricted"
:param restricted_name: Name of a restricted directory object to lookup in either the ~/.o3de/o3de_manifest.json,
<this-engine-root>/engine.json or <project-path>/project.json.
NOTE: The project_path parameter must be supplied to lookup the registration with the project.json
:param project_path: Path to project root, which is used to examined the project.json file in order to
query either gems, templates or restricted directories registered with the project
:return path value associated with the registered object name if found. Otherwise None is returned
"""
json_data = load_o3de_manifest()
# check global first then this engine
@@ -627,7 +652,7 @@ def get_registered(engine_name: str = None,
return project_path
elif isinstance(gem_name, str):
gems = get_all_gems()
gems = get_all_gems(project_path)
for gem_path in gems:
gem_path = pathlib.Path(gem_path).resolve()
gem_json = gem_path / 'gem.json'
@@ -642,7 +667,7 @@ def get_registered(engine_name: str = None,
return gem_path
elif isinstance(template_name, str):
templates = get_all_templates()
templates = get_all_templates(project_path)
for template_path in templates:
template_path = pathlib.Path(template_path).resolve()
template_json = template_path / 'template.json'
@@ -657,7 +682,7 @@ def get_registered(engine_name: str = None,
return template_path
elif isinstance(restricted_name, str):
restricted = get_all_restricted()
restricted = get_all_restricted(project_path)
for restricted_path in restricted:
restricted_path = pathlib.Path(restricted_path).resolve()
restricted_json = restricted_path / 'restricted.json'
+163
View File
@@ -12,6 +12,8 @@
import io
import json
import logging
import unittest.mock
import pytest
import pathlib
from unittest.mock import patch
@@ -67,3 +69,164 @@ class TestGetEnabledGems:
enabled_gems_set = cmake.get_enabled_gems(pathlib.Path('enabled_gems.cmake'))
assert enabled_gems_set == expected_set
class TestAddGemDependency:
@pytest.mark.parametrize(
"enable_gems_cmake_data, expected_set, expected_return", [
pytest.param("""
# Comment
set(ENABLED_GEMS foo bar baz)
""", set(['foo', 'bar', 'baz', 'TestGem']), 0),
pytest.param("""
# Comment
set(ENABLED_GEMS
foo
bar
baz
)
""", set(['foo', 'bar', 'baz', 'TestGem']), 0),
pytest.param("""
# Comment
set(ENABLED_GEMS
foo
bar
baz)
""", set(['foo', 'bar', 'baz', 'TestGem']), 0),
pytest.param("""
# Comment
set(ENABLED_GEMS
foo bar
baz)
""", set(['foo', 'bar', 'baz', 'TestGem']), 0),
pytest.param("""
""", set(['TestGem']), 0),
pytest.param("""
# Comment
set(RANDOM_VARIABLE TestGame, TestProject Test Engine)
set(ENABLED_GEMS HelloWorld IceCream
foo
baz bar
baz baz baz baz baz morebaz lessbaz
)
Random Text
""", set(['HelloWorld', 'IceCream', 'foo', 'bar', 'baz', 'morebaz', 'lessbaz', 'TestGem']),
0),
pytest.param("""
set(ENABLED_GEMS foo bar baz
""", set(['foo', 'bar', 'baz']), 1),
]
)
def test_add_gem_dependency(self, enable_gems_cmake_data, expected_set, expected_return):
enabled_gems_set = set()
add_gem_return = None
class StringBufferIOWrapper(io.StringIO):
def __init__(self):
nonlocal enable_gems_cmake_data
super().__init__(enable_gems_cmake_data)
def __enter__(self):
return super().__enter__()
def __exit__(self, exc_type, exc_val, exc_tb):
nonlocal enable_gems_cmake_data
enable_gems_cmake_data = super().getvalue()
super().__exit__(exc_tb, exc_val, exc_tb)
with patch('pathlib.Path.resolve', return_value=pathlib.Path('enabled_gems.cmake')) as pathlib_is_resolve_mock,\
patch('pathlib.Path.is_file', return_value=True) as pathlib_is_file_mock,\
patch('pathlib.Path.open', side_effect=lambda mode: StringBufferIOWrapper()) as pathlib_open_mock:
add_gem_return = cmake.add_gem_dependency(pathlib.Path('enabled_gems.cmake'), 'TestGem')
enabled_gems_set = cmake.get_enabled_gems(pathlib.Path('enabled_gems.cmake'))
assert add_gem_return == expected_return
assert enabled_gems_set == expected_set
class TestRemoveGemDependency:
@pytest.mark.parametrize(
"enable_gems_cmake_data, expected_set, expected_return", [
pytest.param("""
# Comment
set(ENABLED_GEMS foo bar baz TestGem)
""", set(['foo', 'bar', 'baz']), 0),
pytest.param("""
# Comment
set(ENABLED_GEMS
foo
bar
baz
TestGem
)
""", set(['foo', 'bar', 'baz']), 0),
pytest.param("""
# Comment
set(ENABLED_GEMS
foo
bar
baz
TestGem)
""", set(['foo', 'bar', 'baz']), 0),
pytest.param("""
# Comment
set(ENABLED_GEMS
foo bar
baz TestGem)
""", set(['foo', 'bar', 'baz']), 0),
pytest.param("""
# Comment
set(ENABLED_GEMS
foo
TestGem
bar
TestGem
baz
)
Random Text
""", set(['foo', 'bar', 'baz']),
0),
pytest.param("""
set(ENABLED_GEMS
foo
bar
baz
"TestGem"
)
""", set(['foo', 'bar', 'baz']), 0),
pytest.param("""
""", set(), 1),
pytest.param("""
set(ENABLED_GEMS
foo
bar
baz
)
""", set(['foo', 'bar', 'baz']), 1),
]
)
def test_remove_gem_dependency(self, enable_gems_cmake_data, expected_set, expected_return):
enabled_gems_set = set()
add_gem_return = None
class StringBufferIOWrapper(io.StringIO):
def __init__(self):
nonlocal enable_gems_cmake_data
super().__init__(enable_gems_cmake_data)
def __enter__(self):
return super().__enter__()
def __exit__(self, exc_type, exc_val, exc_tb):
nonlocal enable_gems_cmake_data
enable_gems_cmake_data = super().getvalue()
super().__exit__(exc_tb, exc_val, exc_tb)
with patch('pathlib.Path.resolve', return_value=pathlib.Path('enabled_gems.cmake')) as pathlib_is_resolve_mock,\
patch('pathlib.Path.is_file', return_value=True) as pathlib_is_file_mock,\
patch('pathlib.Path.open', side_effect=lambda mode: StringBufferIOWrapper()) as pathlib_open_mock:
add_gem_return = cmake.remove_gem_dependency(pathlib.Path('enabled_gems.cmake'), 'TestGem')
enabled_gems_set = cmake.get_enabled_gems(pathlib.Path('enabled_gems.cmake'))
assert add_gem_return == expected_return
assert enabled_gems_set == expected_set