From 9041c8c9171cf67ef667656b407db9976da38864 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Thu, 29 Jul 2021 16:58:11 -0700 Subject: [PATCH 01/54] Ensure network autonomy gets set before entity activation on non-dedicated servers -Exposes an AutoActivate flag to INetworkEntityManager and ensured it got respected for all paths -Tweak SpawnDefaultPlayerPrefab to not immediately activate its spawned entity to allow SetAllowAutonomy to be picked up from the net bind component during component activation Signed-off-by: nvsickle --- .../NetworkEntity/INetworkEntityManager.h | 3 ++- .../Code/Source/MultiplayerSystemComponent.cpp | 4 +++- .../Source/NetworkEntity/NetworkEntityManager.cpp | 14 ++++++++++---- .../Source/NetworkEntity/NetworkEntityManager.h | 5 +++-- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h index 1c8894d6c2..c9bb799588 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h @@ -59,7 +59,8 @@ namespace Multiplayer ( const PrefabEntityId& prefabEntryId, NetEntityRole netEntityRole, - const AZ::Transform& transform + const AZ::Transform& transform, + AutoActivate autoActivate = AutoActivate::Activate ) = 0; //! Creates new entities of the given archetype diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 21c7ce80d6..22abd3991b 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -643,6 +643,7 @@ namespace Multiplayer { controlledEntity.GetNetBindComponent()->SetOwningConnectionId(connection->GetConnectionId()); } + controlledEntity.Activate(); if (connection->GetUserData() == nullptr) // Only add user data if the connect event handler has not already done so { @@ -763,6 +764,7 @@ namespace Multiplayer { controlledEntityNetBindComponent->SetAllowAutonomy(true); } + controlledEntity.Activate(); } AZLOG_INFO("Multiplayer operating in %s mode", GetEnumString(m_agentType)); @@ -964,7 +966,7 @@ namespace Multiplayer NetworkEntityHandle MultiplayerSystemComponent::SpawnDefaultPlayerPrefab() { PrefabEntityId playerPrefabEntityId(AZ::Name(static_cast(sv_defaultPlayerSpawnAsset).c_str())); - INetworkEntityManager::EntityList entityList = m_networkEntityManager.CreateEntitiesImmediate(playerPrefabEntityId, NetEntityRole::Authority, AZ::Transform::CreateIdentity()); + INetworkEntityManager::EntityList entityList = m_networkEntityManager.CreateEntitiesImmediate(playerPrefabEntityId, NetEntityRole::Authority, AZ::Transform::CreateIdentity(), Multiplayer::AutoActivate::DoNotActivate); NetworkEntityHandle controlledEntity; if (entityList.size() > 0) diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp index 1460d015fa..6446451369 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp @@ -304,7 +304,7 @@ namespace Multiplayer } INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate( - const AzFramework::Spawnable& spawnable, NetEntityRole netEntityRole) + const AzFramework::Spawnable& spawnable, NetEntityRole netEntityRole, AutoActivate autoActivate) { INetworkEntityManager::EntityList returnList; @@ -354,6 +354,11 @@ namespace Multiplayer const NetEntityId netEntityId = NextId(); netBindComponent->PreInit(clone, prefabEntityId, netEntityId, netEntityRole); + if (autoActivate == AutoActivate::DoNotActivate) + { + clone->SetRuntimeActiveByDefault(false); + } + AzFramework::GameEntityContextRequestBus::Broadcast( &AzFramework::GameEntityContextRequestBus::Events::AddGameEntity, clone); @@ -373,10 +378,11 @@ namespace Multiplayer ( const PrefabEntityId& prefabEntryId, NetEntityRole netEntityRole, - const AZ::Transform& transform + const AZ::Transform& transform, + AutoActivate autoActivate ) { - return CreateEntitiesImmediate(prefabEntryId, NextId(), netEntityRole, AutoActivate::Activate, transform); + return CreateEntitiesImmediate(prefabEntryId, NextId(), netEntityRole, autoActivate, transform); } INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate @@ -409,7 +415,7 @@ namespace Multiplayer if (entityIndex == PrefabEntityId::AllIndices) { - return CreateEntitiesImmediate(*netSpawnable, netEntityRole); + return CreateEntitiesImmediate(*netSpawnable, netEntityRole, autoActivate); } const AzFramework::Spawnable::EntityList& entities = netSpawnable->GetEntities(); diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h index fdd0201b7a..adbf7df8da 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h @@ -42,12 +42,13 @@ namespace Multiplayer HostId GetHostId() const override; ConstNetworkEntityHandle GetEntity(NetEntityId netEntityId) const override; - EntityList CreateEntitiesImmediate(const AzFramework::Spawnable& spawnable, NetEntityRole netEntityRole); + EntityList CreateEntitiesImmediate(const AzFramework::Spawnable& spawnable, NetEntityRole netEntityRole, AutoActivate autoActivate); EntityList CreateEntitiesImmediate ( const PrefabEntityId& prefabEntryId, NetEntityRole netEntityRole, - const AZ::Transform& transform + const AZ::Transform& transform, + AutoActivate autoActivate = AutoActivate::Activate ) override; EntityList CreateEntitiesImmediate ( From 85d4abae83e3f5954a88c9cf21222a940bfbda34 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 12 Aug 2021 09:22:56 -0700 Subject: [PATCH 02/54] Move MultiplayerComponent destructor to cpp (which #includes the controller) so that when it comes time to destroy the unique_ptr it can do so on a complete type. Also, minor spelling error fix Signed-off-by: Gene Walters --- Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h | 2 +- .../Code/Source/AutoGen/AutoComponent_Header.jinja | 4 ++-- .../Code/Source/AutoGen/AutoComponent_Source.jinja | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h index 42fc762769..9c37a0b0ed 100644 --- a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h +++ b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h @@ -1855,7 +1855,7 @@ namespace AZ * { * // do any conversion of caching of the "data" here and forward this to behavior (often the reason for this is that you can't pass everything to behavior * // plus behavior can't really handle all constructs pointer to pointer, rvalues, etc. as they don't make sense for most script environments - * int result = 0; // set the default value for your result if the behavior if there is no implmentation + * int result = 0; // set the default value for your result if the behavior if there is no implementation * // The AZ_EBUS_BEHAVIOR_BINDER defines FN_EventName for each index. You can also cache it yourself (but it's slower), static int cacheIndex = GetFunctionIndex("OnEvent1"); and use that . * CallResult(result, FN_OnEvent1, data); // forward to the binding (there can be none, this is why we need to always have properly set result, when there is one) * return result; // return the result like you will in any normal EBus even with result diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja index 84fdc9ae54..d92ffdc086 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja @@ -445,8 +445,8 @@ namespace {{ Component.attrib['Namespace'] }} static AZStd::unique_ptr AllocateComponentInput(); - {{ ComponentBaseName }}() = default; - ~{{ ComponentBaseName }}() override = default; + {{ ComponentBaseName }}(); + ~{{ ComponentBaseName }}() override; void Init() override; void Activate() override; diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index d2be2f682a..c8ccc537db 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -1491,6 +1491,10 @@ namespace {{ Component.attrib['Namespace'] }} {% endif %} } + {{ ComponentBaseName }}::{{ ComponentBaseName }}() = default; + + {{ ComponentBaseName }}::~{{ ComponentBaseName }}() = default; + void {{ ComponentBaseName }}::Init() { if (m_netBindComponent == nullptr) From f7da64a5183f61bee2a057ee4eb9b82c6c4e8630 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 12 Apr 2021 19:52:01 -0700 Subject: [PATCH 03/54] =?UTF-8?q?=EF=BB=BFAllowing=20to=20build=20with=20A?= =?UTF-8?q?San=20enabled?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Configurations.cmake | 127 +++++++++--------- .../Common/MSVC/Configurations_msvc.cmake | 23 +++- cmake/cmake_files.cmake | 1 + 3 files changed, 83 insertions(+), 68 deletions(-) diff --git a/cmake/Configurations.cmake b/cmake/Configurations.cmake index a580f1c572..693cc23c7d 100644 --- a/cmake/Configurations.cmake +++ b/cmake/Configurations.cmake @@ -20,24 +20,33 @@ include_guard(GLOBAL) # \arg:LINK_STATIC_${CONFIGURATION} # \arg:LINK_NON_STATIC # \arg:LINK_NON_STATIC_${CONFIGURATION} -# \arg:LINK_EXECUTABLE -# \arg:LINK_EXECUTABLE_${CONFIGURATION} +# \arg:LINK_EXE +# \arg:LINK_EXE_${CONFIGURATION} +# \arg:LINK_MODULE +# \arg:LINK_MODULE_${CONFIGURATION} +# \arg:LINK_SHARED +# \arg:LINK_SHARED_${CONFIGURATION} # function(ly_append_configurations_options) set(options) set(oneValueArgs) - set(multiValueArgs + set(multiArgs DEFINES COMPILATION LINK LINK_STATIC LINK_NON_STATIC - LINK_EXECUTABLE + LINK_EXE + LINK_MODULE + LINK_SHARED ) - foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) - string(TOUPPER ${conf} UCONF) - set(multiValueArgs ${multiValueArgs} DEFINES_${UCONF} COMPILATION_${UCONF} LINK_${UCONF} LINK_STATIC_${UCONF} LINK_NON_STATIC_${UCONF} LINK_EXECUTABLE_${UCONF}) + foreach(arg IN LISTS multiArgs) + list(APPEND multiValueArgs ${arg}) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + list(APPEND multiValueArgs ${arg}_${UCONF}) + endforeach() endforeach() cmake_parse_arguments(ly_append_configurations_options "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) @@ -45,48 +54,46 @@ function(ly_append_configurations_options) if(ly_append_configurations_options_DEFINES) add_compile_definitions(${ly_append_configurations_options_DEFINES}) endif() + if(ly_append_configurations_options_COMPILATION) string(REPLACE ";" " " COMPILATION_STR "${ly_append_configurations_options_COMPILATION}") - string(APPEND CMAKE_C_FLAGS " " ${COMPILATION_STR}) - string(APPEND CMAKE_CXX_FLAGS " " ${COMPILATION_STR}) - set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} PARENT_SCOPE) - set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} PARENT_SCOPE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMPILATION_STR}" PARENT_SCOPE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILATION_STR}" PARENT_SCOPE) endif() + if(ly_append_configurations_options_LINK) string(REPLACE ";" " " LINK_STR "${ly_append_configurations_options_LINK}") - string(APPEND LINK_OPTIONS " " ${LINK_STR}) - set(LINK_OPTIONS ${LINK_OPTIONS} PARENT_SCOPE) - - # Not defining these issue warnings, TODO: investigate - set(CMAKE_STATIC_LINKER_FLAGS ${LINK_OPTIONS} PARENT_SCOPE) - set(CMAKE_MODULE_LINKER_FLAGS ${LINK_OPTIONS} PARENT_SCOPE) - set(CMAKE_SHARED_LINKER_FLAGS ${LINK_OPTIONS} PARENT_SCOPE) - set(CMAKE_EXE_LINKER_FLAGS ${LINK_OPTIONS} PARENT_SCOPE) + set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} ${LINK_STR}" PARENT_SCOPE) + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINK_STR}" PARENT_SCOPE) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_STR}" PARENT_SCOPE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINK_OPTIONS}" PARENT_SCOPE) endif() - if(ly_append_configurations_options_LINK_STATIC) - string(REPLACE ";" " " LINK_STATIC_STR "${ly_append_configurations_options_LINK_STATIC}") - string(APPEND LINK_STATIC_OPTIONS " " ${LINK_STATIC_STR}) - set(LINK_STATIC_OPTIONS ${LINK_STATIC_OPTIONS} PARENT_SCOPE) - set(CMAKE_STATIC_LINKER_FLAGS ${LINK_STATIC_OPTIONS} PARENT_SCOPE) + if(ly_append_configurations_options_LINK_STATIC) + string(REPLACE ";" " " LINK_STR "${ly_append_configurations_options_LINK_STATIC}") + set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} ${LINK_STR}" PARENT_SCOPE) endif() if(ly_append_configurations_options_LINK_NON_STATIC) - string(REPLACE ";" " " LINK_NON_STATIC_STR "${ly_append_configurations_options_LINK_NON_STATIC}") - string(APPEND LINK_NON_STATIC_OPTIONS " " ${LINK_NON_STATIC_STR}) - set(LINK_NON_STATIC_OPTIONS ${LINK_NON_STATIC_OPTIONS} PARENT_SCOPE) - - set(CMAKE_MODULE_LINKER_FLAGS ${LINK_NON_STATIC_OPTIONS} PARENT_SCOPE) - set(CMAKE_SHARED_LINKER_FLAGS ${LINK_NON_STATIC_OPTIONS} PARENT_SCOPE) - set(CMAKE_EXE_LINKER_FLAGS ${LINK_NON_STATIC_OPTIONS} PARENT_SCOPE) + string(REPLACE ";" " " LINK_STR "${ly_append_configurations_options_LINK_NON_STATIC}") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINK_STR}" PARENT_SCOPE) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_STR}" PARENT_SCOPE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINK_STR}" PARENT_SCOPE) endif() - if(ly_append_configurations_options_LINK_EXECUTABLE) - string(REPLACE ";" " " LINK_EXECUTABLE_STR "${ly_append_configurations_options_LINK_EXECUTABLE}") - string(APPEND LINK_EXECUTABLE_OPTIONS " " ${LINK_EXECUTABLE_STR}) - set(LINK_EXECUTABLE_OPTIONS ${LINK_EXECUTABLE_OPTIONS} PARENT_SCOPE) + if(ly_append_configurations_options_LINK_EXE) + string(REPLACE ";" " " LINK_STR "${ly_append_configurations_options_LINK_EXE}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINK_STR}" PARENT_SCOPE) + endif() - set(CMAKE_EXE_LINKER_FLAGS ${LINK_EXECUTABLE_OPTIONS} PARENT_SCOPE) + if(ly_append_configurations_options_LINK_MODULE) + string(REPLACE ";" " " LINK_STR "${ly_append_configurations_options_LINK_MODULE}") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINK_STR}" PARENT_SCOPE) + endif() + + if(ly_append_configurations_options_LINK_SHARED) + string(REPLACE ";" " " LINK_STR "${ly_append_configurations_options_LINK_SHARED}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_STR}" PARENT_SCOPE) endif() foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) @@ -100,43 +107,33 @@ function(ly_append_configurations_options) endif() if(ly_append_configurations_options_COMPILATION_${UCONF}) string(REPLACE ";" " " COMPILATION_STR "${ly_append_configurations_options_COMPILATION_${UCONF}}") - string(APPEND CMAKE_C_FLAGS_${UCONF} " " ${COMPILATION_STR}) - string(APPEND CMAKE_CXX_FLAGS_${UCONF} " " ${COMPILATION_STR}) - set(CMAKE_C_FLAGS_${UCONF} ${CMAKE_C_FLAGS_${UCONF}} PARENT_SCOPE) - set(CMAKE_CXX_FLAGS_${UCONF} ${CMAKE_CXX_FLAGS_${UCONF}} PARENT_SCOPE) + set(CMAKE_C_FLAGS_${UCONF} "${CMAKE_C_FLAGS_${UCONF}} ${COMPILATION_STR}" PARENT_SCOPE) + set(CMAKE_CXX_FLAGS_${UCONF} "${CMAKE_CXX_FLAGS_${UCONF}} ${COMPILATION_STR}" PARENT_SCOPE) endif() if(ly_append_configurations_options_LINK_${UCONF}) string(REPLACE ";" " " LINK_STR "${ly_append_configurations_options_LINK_${UCONF}}") - string(APPEND LINK_OPTIONS_${UCONF} " " ${LINK_STR}) - set(LINK_OPTIONS_${UCONF} ${LINK_OPTIONS_${UCONF}} PARENT_SCOPE) - - set(CMAKE_STATIC_LINKER_FLAGS_${UCONF} ${LINK_OPTIONS_${UCONF}} PARENT_SCOPE) - set(CMAKE_MODULE_LINKER_FLAGS_${UCONF} ${LINK_OPTIONS_${UCONF}} PARENT_SCOPE) - set(CMAKE_SHARED_LINKER_FLAGS_${UCONF} ${LINK_OPTIONS_${UCONF}} PARENT_SCOPE) - set(CMAKE_EXE_LINKER_FLAGS_${UCONF} ${LINK_OPTIONS_${UCONF}} PARENT_SCOPE) + set(CMAKE_STATIC_LINKER_FLAGS_${UCONF} "${CMAKE_STATIC_LINKER_FLAGS_${UCONF}} ${LINK_STR}" PARENT_SCOPE) + set(CMAKE_MODULE_LINKER_FLAGS_${UCONF} "${CMAKE_MODULE_LINKER_FLAGS_${UCONF}} ${LINK_STR}" PARENT_SCOPE) + set(CMAKE_SHARED_LINKER_FLAGS_${UCONF} "${CMAKE_SHARED_LINKER_FLAGS_${UCONF}} ${LINK_STR}" PARENT_SCOPE) + set(CMAKE_EXE_LINKER_FLAGS_${UCONF} "${CMAKE_EXE_LINKER_FLAGS_${UCONF}} ${LINK_STR}" PARENT_SCOPE) endif() if(ly_append_configurations_options_LINK_STATIC_${UCONF}) - string(REPLACE ";" " " LINK_STATIC_STR "${ly_append_configurations_options_LINK_STATIC_${UCONF}}") - string(APPEND LINK_STATIC_OPTIONS_${UCONF} " " ${LINK_STATIC_STR}) - set(LINK_STATIC_OPTIONS_${UCONF} ${LINK_STATIC_OPTIONS_${UCONF}} PARENT_SCOPE) - - set(CMAKE_STATIC_LINKER_FLAGS_${UCONF} ${LINK_STATIC_OPTIONS_${UCONF}} PARENT_SCOPE) + string(REPLACE ";" " " LINK_STR "${ly_append_configurations_options_LINK_STATIC_${UCONF}}") + set(CMAKE_STATIC_LINKER_FLAGS_${UCONF} "${CMAKE_STATIC_LINKER_FLAGS_${UCONF}} ${LINK_STR}" PARENT_SCOPE) endif() if(ly_append_configurations_options_LINK_NON_STATIC_${UCONF}) - string(REPLACE ";" " " LINK_NON_STATIC_STR "${ly_append_configurations_options_LINK_NON_STATIC_${UCONF}}") - string(APPEND LINK_NON_STATIC_OPTIONS_${UCONF} " " ${LINK_NON_STATIC_STR}) - set(LINK_NON_STATIC_OPTIONS_${UCONF} ${LINK_NON_STATIC_OPTIONS_${UCONF}} PARENT_SCOPE) - - set(CMAKE_MODULE_LINKER_FLAGS_${UCONF} ${LINK_NON_STATIC_OPTIONS_${UCONF}} PARENT_SCOPE) - set(CMAKE_SHARED_LINKER_FLAGS_${UCONF} ${LINK_NON_STATIC_OPTIONS_${UCONF}} PARENT_SCOPE) - set(CMAKE_EXE_LINKER_FLAGS_${UCONF} ${LINK_NON_STATIC_OPTIONS_${UCONF}} PARENT_SCOPE) + string(REPLACE ";" " " LINK_STR "${ly_append_configurations_options_LINK_NON_STATIC_${UCONF}}") + set(CMAKE_MODULE_LINKER_FLAGS_${UCONF} "${CMAKE_MODULE_LINKER_FLAGS_${UCONF}} ${LINK_STR}" PARENT_SCOPE) + set(CMAKE_SHARED_LINKER_FLAGS_${UCONF} "${CMAKE_SHARED_LINKER_FLAGS_${UCONF}} ${LINK_STR}" PARENT_SCOPE) + set(CMAKE_EXE_LINKER_FLAGS_${UCONF} "${CMAKE_EXE_LINKER_FLAGS_${UCONF}} ${LINK_STR}" PARENT_SCOPE) endif() - if(ly_append_configurations_options_LINK_EXECUTABLE_${UCONF}) - string(REPLACE ";" " " LINK_EXECUTABLE_STR "${ly_append_configurations_options_LINK_EXECUTABLE_${UCONF}}") - string(APPEND LINK_EXECUTABLE_OPTIONS_${UCONF} " " ${LINK_EXECUTABLE_STR}) - set(LINK_EXECUTABLE_OPTIONS_${UCONF} ${LINK_EXECUTABLE_OPTIONS_${UCONF}} PARENT_SCOPE) - - set(CMAKE_EXE_LINKER_FLAGS_${UCONF} ${LINK_EXECUTABLE_OPTIONS_${UCONF}} PARENT_SCOPE) + if(ly_append_configurations_options_LINK_EXE_${UCONF}) + string(REPLACE ";" " " LINK_STR "${ly_append_configurations_options_LINK_EXE_${UCONF}}") + set(CMAKE_EXE_LINKER_FLAGS_${UCONF} "${CMAKE_EXE_LINKER_FLAGS_${UCONF}} ${LINK_STR}" PARENT_SCOPE) + endif() + if(ly_append_configurations_options_LINK_MODULE_${UCONF}) + string(REPLACE ";" " " LINK_STR "${ly_append_configurations_options_LINK_MODULE_${UCONF}}") + set(CMAKE_MODULE_LINKER_FLAGS_${UCONF} "${CMAKE_MODULE_LINKER_FLAGS_${UCONF}} ${LINK_STR}" PARENT_SCOPE) endif() endforeach() diff --git a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake index 118a515e30..c0d0809b0f 100644 --- a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake +++ b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake @@ -64,9 +64,6 @@ ly_append_configurations_options( # It also causes the compiler to place the library name MSVCRTD.lib into the .obj file. /Ob0 # Disables inline expansions /Od # Disables optimization - /RTCsu # Run-Time Error Checks: c Reports when a value is assigned to a smaller data type and results in a data loss (Not supoported by the STL) - # s Enables stack frame run-time error checking - # u Reports when a variable is used without having been initialized COMPILATION_PROFILE /GF # Enable string pooling /Gy # Function level linking @@ -96,6 +93,26 @@ ly_append_configurations_options( /INCREMENTAL:NO ) +set(LY_BUILD_WITH_ADDRESS_SANITIZER FALSE CACHE BOOL "Builds using AddressSanitizer (ASan). Will disable Edit/Continue, Incremental building and Run-Time checks (default = FALSE)") +if(LY_BUILD_WITH_ADDRESS_SANITIZER) + set(LY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG FALSE) + ly_append_configurations_options( + COMPILATION_DEBUG + /fsanitize=address + ) + get_filename_component(link_tools_dir ${CMAKE_LINKER} DIRECTORY) + file(COPY + ${link_tools_dir}/clang_rt.asan_dbg_dynamic-x86_64.dll + DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}) +else() + ly_append_configurations_options( + COMPILATION_DEBUG + /RTCsu # Run-Time Error Checks: c Reports when a value is assigned to a smaller data type and results in a data loss (Not supoported by the STL) + # s Enables stack frame run-time error checking + # u Reports when a variable is used without having been initialized + ) +endif() + set(LY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG FALSE CACHE BOOL "Indicates if incremental linking is used in debug configurations (default = FALSE)") if(LY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG) ly_append_configurations_options( diff --git a/cmake/cmake_files.cmake b/cmake/cmake_files.cmake index aa275b634a..10676b384e 100644 --- a/cmake/cmake_files.cmake +++ b/cmake/cmake_files.cmake @@ -20,6 +20,7 @@ set(FILES Findo3de.cmake Gems.cmake GeneralSettings.cmake + Initialize.cmake Install.cmake LyAutoGen.cmake LYPackage_S3Downloader.cmake From b4f6dc5bff2640fbef603f11099250310f4bd757 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 12 Aug 2021 16:44:01 -0700 Subject: [PATCH 04/54] fixes after merge Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Platform/Common/MSVC/Configurations_msvc.cmake | 2 +- cmake/cmake_files.cmake | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake index c0d0809b0f..891d48ddb2 100644 --- a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake +++ b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake @@ -95,7 +95,7 @@ ly_append_configurations_options( set(LY_BUILD_WITH_ADDRESS_SANITIZER FALSE CACHE BOOL "Builds using AddressSanitizer (ASan). Will disable Edit/Continue, Incremental building and Run-Time checks (default = FALSE)") if(LY_BUILD_WITH_ADDRESS_SANITIZER) - set(LY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG FALSE) + set(LY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG FALSE) ly_append_configurations_options( COMPILATION_DEBUG /fsanitize=address diff --git a/cmake/cmake_files.cmake b/cmake/cmake_files.cmake index 10676b384e..aa275b634a 100644 --- a/cmake/cmake_files.cmake +++ b/cmake/cmake_files.cmake @@ -20,7 +20,6 @@ set(FILES Findo3de.cmake Gems.cmake GeneralSettings.cmake - Initialize.cmake Install.cmake LyAutoGen.cmake LYPackage_S3Downloader.cmake From a087fc06a9bc833aba1eaf42aa8a1eeb5295cc77 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 12 Aug 2021 16:44:25 -0700 Subject: [PATCH 05/54] fixes for ASAn Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/std/string/string_view.h | 5 ++++- Code/Framework/AzCore/Tests/AZStd/String.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/std/string/string_view.h b/Code/Framework/AzCore/AzCore/std/string/string_view.h index 9a98795554..4ded44644f 100644 --- a/Code/Framework/AzCore/AzCore/std/string/string_view.h +++ b/Code/Framework/AzCore/AzCore/std/string/string_view.h @@ -7,7 +7,6 @@ */ #pragma once -#include #include #include @@ -46,6 +45,10 @@ namespace AZStd return npos; } size_t foundIndex = searchIndex + charFindIndex; + if (foundIndex + count > size) + { + return npos; // the rest of the string doesnt fit in the remainder of the data buffer + } if (Traits::compare(&data[foundIndex], ptr, count) == 0) { return foundIndex; diff --git a/Code/Framework/AzCore/Tests/AZStd/String.cpp b/Code/Framework/AzCore/Tests/AZStd/String.cpp index 9dae4a3d3f..a88de48b9b 100644 --- a/Code/Framework/AzCore/Tests/AZStd/String.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/String.cpp @@ -1458,17 +1458,17 @@ namespace UnitTest constexpr double v15 = 0; constexpr const char* v16 = "Hello"; constexpr const wchar_t* v17 = L"Hello"; - constexpr void* v18 = 0; + constexpr void* v18 = nullptr; // This shouldn't give a compile error AZStd::string::format( - "%i %c %uc %c %c %i %i %u %i %lu %li %llu %lli %f %f %s %ls %p", + "%i %c %uc %hc %lc %i %i %u %i %lu %li %llu %lli %f %f %hs %ls %p", v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18); // This shouldn't give a compile error AZStd::wstring::format( - L"%i %c %uc %c %lc %i %i %u %i %lu %li %llu %lli %f %f %s %ls %p", - v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18); + L"%i %c %uc %hc %lc %i %i %u %i %lu %li %llu %lli %f %f %hs %ls %p", + v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18); class WrappedInt { From 89e1b6db255fa4f09ccd2a306d76cd58a70985f4 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 12 Aug 2021 16:44:59 -0700 Subject: [PATCH 06/54] Making allocator use the MallocSchema so we can take full advantage of ASan Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/IO/Path/Path.inl | 1 + .../AzCore/AzCore/Memory/SystemAllocator.cpp | 66 ++++---- Code/Framework/AzCore/CMakeLists.txt | 9 + .../AzFramework/Physics/Common/PhysicsTypes.h | 1 + Code/Legacy/CryCommon/LegacyAllocator.cpp | 79 +++++++++ Code/Legacy/CryCommon/LegacyAllocator.h | 157 ++---------------- Code/Legacy/CryCommon/crycommon_files.cmake | 1 + 7 files changed, 138 insertions(+), 176 deletions(-) create mode 100644 Code/Legacy/CryCommon/LegacyAllocator.cpp diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl index 4e8356b436..ad1d09bc01 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl +++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl @@ -10,6 +10,7 @@ #include #include +#include // extern instantiations of Path templates to prevent implicit instantiations namespace AZ::IO diff --git a/Code/Framework/AzCore/AzCore/Memory/SystemAllocator.cpp b/Code/Framework/AzCore/AzCore/Memory/SystemAllocator.cpp index ada6c8f330..07c919cf00 100644 --- a/Code/Framework/AzCore/AzCore/Memory/SystemAllocator.cpp +++ b/Code/Framework/AzCore/AzCore/Memory/SystemAllocator.cpp @@ -17,15 +17,23 @@ #include -#define AZCORE_SYS_ALLOCATOR_HPPA // If you disable this make sure you start building the heapschema.cpp -//#define AZCORE_SYS_ALLOCATOR_MALLOC +#define AZCORE_SYSTEM_ALLOCATOR_HPHA 1 +#define AZCORE_SYSTEM_ALLOCATOR_MALLOC 2 +#define AZCORE_SYSTEM_ALLOCATOR_HEAP 3 -#ifdef AZCORE_SYS_ALLOCATOR_HPPA -# include -#elif defined(AZCORE_SYS_ALLOCATOR_MALLOC) -#include +#if !defined(AZCORE_SYSTEM_ALLOCATOR) + // define the default + #define AZCORE_SYSTEM_ALLOCATOR AZCORE_SYSTEM_ALLOCATOR_HPHA +#endif + +#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA + #include +#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC + #include +#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP + #include #else -# include + #error "Invalid allocator selected for SystemAllocator" #endif @@ -34,12 +42,12 @@ using namespace AZ; ////////////////////////////////////////////////////////////////////////// // Globals - we use global storage for the first memory schema, since we can't use dynamic memory! static bool g_isSystemSchemaUsed = false; -#ifdef AZCORE_SYS_ALLOCATOR_HPPA -static AZStd::aligned_storage::value>::type g_systemSchema; -#elif defined(AZCORE_SYS_ALLOCATOR_MALLOC) -static AZStd::aligned_storage::value>::type g_systemSchema; -#else -static AZStd::aligned_storage::value>::type g_systemSchema; +#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA + static AZStd::aligned_storage::value>::type g_systemSchema; +#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC + static AZStd::aligned_storage::value>::type g_systemSchema; +#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP + static AZStd::aligned_storage::value>::type g_systemSchema; #endif ////////////////////////////////////////////////////////////////////////// @@ -97,9 +105,9 @@ SystemAllocator::Create(const Descriptor& desc) else { m_isCustom = false; -#ifdef AZCORE_SYS_ALLOCATOR_HPPA - HphaSchema::Descriptor heapDesc; - heapDesc.m_pageSize = desc.m_heap.m_pageSize; +#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA + HphaSchema::Descriptor heapDesc; + heapDesc.m_pageSize = desc.m_heap.m_pageSize; heapDesc.m_poolPageSize = desc.m_heap.m_poolPageSize; AZ_Assert(desc.m_heap.m_numFixedMemoryBlocks <= 1, "We support max1 memory block at the moment!"); if (desc.m_heap.m_numFixedMemoryBlocks > 0) @@ -111,11 +119,10 @@ SystemAllocator::Create(const Descriptor& desc) heapDesc.m_isPoolAllocations = desc.m_heap.m_isPoolAllocations; // Fix SystemAllocator from growing in small chunks heapDesc.m_systemChunkSize = desc.m_heap.m_systemChunkSize; - -#elif defined(AZCORE_SYS_ALLOCATOR_MALLOC) +#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC MallocSchema::Descriptor heapDesc; -#else - HeapSchema::Descriptor heapDesc; +#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP + HeapSchema::Descriptor heapDesc; memcpy(heapDesc.m_memoryBlocks, desc.m_heap.m_memoryBlocks, sizeof(heapDesc.m_memoryBlocks)); memcpy(heapDesc.m_memoryBlocksByteSize, desc.m_heap.m_memoryBlocksByteSize, sizeof(heapDesc.m_memoryBlocksByteSize)); heapDesc.m_numMemoryBlocks = desc.m_heap.m_numMemoryBlocks; @@ -124,11 +131,11 @@ SystemAllocator::Create(const Descriptor& desc) { AZ_Assert(!g_isSystemSchemaUsed, "AZ::SystemAllocator MUST be created first! It's the source of all allocations!"); -#ifdef AZCORE_SYS_ALLOCATOR_HPPA +#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA m_allocator = new(&g_systemSchema)HphaSchema(heapDesc); -#elif defined(AZCORE_SYS_ALLOCATOR_MALLOC) +#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC m_allocator = new(&g_systemSchema)MallocSchema(heapDesc); -#else +#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP m_allocator = new(&g_systemSchema)HeapSchema(heapDesc); #endif g_isSystemSchemaUsed = true; @@ -139,14 +146,13 @@ SystemAllocator::Create(const Descriptor& desc) // this class should be inheriting from SystemAllocator AZ_Assert(AllocatorInstance::IsReady(), "System allocator must be created before any other allocator! They allocate from it."); -#ifdef AZCORE_SYS_ALLOCATOR_HPPA +#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA m_allocator = azcreate(HphaSchema, (heapDesc), SystemAllocator); -#elif defined(AZCORE_SYS_ALLOCATOR_MALLOC) +#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC m_allocator = azcreate(MallocSchema, (heapDesc), SystemAllocator); -#else +#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP m_allocator = azcreate(HeapSchema, (heapDesc), SystemAllocator); #endif - if (m_allocator == NULL) { isReady = false; @@ -178,11 +184,11 @@ SystemAllocator::Destroy() { if ((void*)m_allocator == (void*)&g_systemSchema) { -#ifdef AZCORE_SYS_ALLOCATOR_HPPA +#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA static_cast(m_allocator)->~HphaSchema(); -#elif defined(AZCORE_SYS_ALLOCATOR_MALLOC) +#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC static_cast(m_allocator)->~MallocSchema(); -#else +#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP static_cast(m_allocator)->~HeapSchema(); #endif g_isSystemSchemaUsed = false; diff --git a/Code/Framework/AzCore/CMakeLists.txt b/Code/Framework/AzCore/CMakeLists.txt index ea7cc27af5..e3898ec17e 100644 --- a/Code/Framework/AzCore/CMakeLists.txt +++ b/Code/Framework/AzCore/CMakeLists.txt @@ -54,6 +54,15 @@ ly_add_source_properties( VALUES ${LY_PAL_TOOLS_DEFINES} ) +if(LY_BUILD_WITH_ADDRESS_SANITIZER) + # Default to use Malloc schema so ASan works well + ly_add_source_properties( + SOURCES AzCore/Memory/SystemAllocator.cpp + PROPERTY COMPILE_DEFINITIONS + VALUES AZCORE_SYSTEM_ALLOCATOR=AZCORE_SYSTEM_ALLOCATOR_MALLOC + ) +endif() + ################################################################################ # Tests ################################################################################ diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsTypes.h b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsTypes.h index bb53d6d3dd..e224c0ab22 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsTypes.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsTypes.h @@ -13,6 +13,7 @@ #include #include #include +#include namespace Physics { diff --git a/Code/Legacy/CryCommon/LegacyAllocator.cpp b/Code/Legacy/CryCommon/LegacyAllocator.cpp new file mode 100644 index 0000000000..9c4258530a --- /dev/null +++ b/Code/Legacy/CryCommon/LegacyAllocator.cpp @@ -0,0 +1,79 @@ +/* + * 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. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +namespace AZ +{ + LegacyAllocator::pointer_type LegacyAllocator::Allocate(size_type byteSize, size_type alignment, int flags, const char* name, const char* fileName, int lineNum, unsigned int suppressStackRecord) + { + if (alignment == 0) + { + // Some STL containers, like std::vector, are assuming a specific minimum alignment. seems to have a requirement + // Take a look at _Allocate_manually_vector_aligned in xmemory0 + alignment = sizeof(void*) * 2; + } + + pointer_type ptr = m_schema->Allocate(byteSize, alignment, flags, name, fileName, lineNum, suppressStackRecord); + AZ_PROFILE_MEMORY_ALLOC_EX(AZ::Debug::ProfileCategory::MemoryReserved, fileName, lineNum, ptr, byteSize, name ? name : GetName()); + AZ_MEMORY_PROFILE(ProfileAllocation(ptr, byteSize, alignment, name, fileName, lineNum, suppressStackRecord)); + AZ_Assert(ptr || byteSize == 0, "OOM - Failed to allocate %zu bytes from LegacyAllocator", byteSize); + return ptr; + } + + // DeAllocate with file/line, to track when allocs were freed from Cry + void LegacyAllocator::DeAllocate(pointer_type ptr, [[maybe_unused]] const char* file, [[maybe_unused]] const int line, size_type byteSize, size_type alignment) + { + AZ_PROFILE_MEMORY_FREE_EX(AZ::Debug::ProfileCategory::MemoryReserved, file, line, ptr); + AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, byteSize, alignment, nullptr)); + m_schema->DeAllocate(ptr, byteSize, alignment); + } + + // Realloc with file/line, because Cry uses realloc(nullptr) and realloc(ptr, 0) to mimic malloc/free + LegacyAllocator::pointer_type LegacyAllocator::ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment, [[maybe_unused]] const char* file, [[maybe_unused]] const int line) + { + if (newAlignment == 0) + { + // Some STL containers, like std::vector, are assuming a specific minimum alignment. seems to have a requirement + // Take a look at _Allocate_manually_vector_aligned in xmemory0 + newAlignment = sizeof(void*) * 2; + } + + AZ_MEMORY_PROFILE(ProfileReallocationBegin(ptr, newSize)); + AZ_PROFILE_MEMORY_FREE_EX(AZ::Debug::ProfileCategory::MemoryReserved, file, line, ptr); + pointer_type newPtr = m_schema->ReAllocate(ptr, newSize, newAlignment); + AZ_PROFILE_MEMORY_ALLOC_EX(AZ::Debug::ProfileCategory::MemoryReserved, file, line, newPtr, newSize, "LegacyAllocator Realloc"); + AZ_MEMORY_PROFILE(ProfileReallocationEnd(ptr, newPtr, newSize, newAlignment)); + AZ_Assert(newPtr || newSize == 0, "OOM - Failed to reallocate %zu bytes from LegacyAllocator", newSize); + return newPtr; + } + + void LegacyAllocator::DeAllocate(pointer_type ptr, size_type byteSize, size_type alignment) + { + AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, 0, 0, nullptr)); + Base::DeAllocate(ptr, byteSize, alignment); + } + + LegacyAllocator::pointer_type LegacyAllocator::ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment) + { + if (newAlignment == 0) + { + // Some STL containers, like std::vector, are assuming a specific minimum alignment. seems to have a requirement + // Take a look at _Allocate_manually_vector_aligned in xmemory0 + newAlignment = sizeof(void*) * 2; + } + + AZ_MEMORY_PROFILE(ProfileReallocationBegin(ptr, newSize)); + pointer_type newPtr = Base::ReAllocate(ptr, newSize, newAlignment); + AZ_MEMORY_PROFILE(ProfileReallocationEnd(ptr, newPtr, newSize, newAlignment)); + AZ_Assert(newPtr || newSize == 0, "OOM - Failed to reallocate %zu bytes from LegacyAllocator", newSize); + return newPtr; + } +} diff --git a/Code/Legacy/CryCommon/LegacyAllocator.h b/Code/Legacy/CryCommon/LegacyAllocator.h index 074c183de4..2b1055958b 100644 --- a/Code/Legacy/CryCommon/LegacyAllocator.h +++ b/Code/Legacy/CryCommon/LegacyAllocator.h @@ -11,118 +11,36 @@ #include #include -#define AZCORE_SYS_ALLOCATOR_HPPA -//#define AZCORE_SYS_ALLOCATOR_MALLOC - -#ifdef AZCORE_SYS_ALLOCATOR_HPPA -# include -#elif defined(AZCORE_SYS_ALLOCATOR_MALLOC) -# include -#else -# include -#endif - namespace AZ { - -#ifdef AZCORE_SYS_ALLOCATOR_HPPA - typedef AZ::HphaSchema LegacyAllocatorSchema; -#elif defined(AZCORE_SYS_ALLOCATOR_MALLOC) - typedef AZ::MallocSchema LegacyAllocatorSchema; -#else - typedef AZ::HeapSchema LegacyAllocatorSchema; -#endif - - struct LegacyAllocatorDescriptor - : public LegacyAllocatorSchema::Descriptor - { - LegacyAllocatorDescriptor() - { - // pull 32MB from the OS at a time -#ifdef AZCORE_SYS_ALLOCATOR_HPPA - m_systemChunkSize = 32 * 1024 * 1024; -#endif - } - }; - class LegacyAllocator - : public SimpleSchemaAllocator + : public SimpleSchemaAllocator { public: AZ_TYPE_INFO(LegacyAllocator, "{17FC25A4-92D9-48C5-BB85-7F860FCA2C6F}"); - using Descriptor = LegacyAllocatorDescriptor; - using Base = SimpleSchemaAllocator; + using Descriptor = AZ::HphaSchema::Descriptor; + using Base = SimpleSchemaAllocator; + using pointer_type = typename Base::pointer_type; + using size_type = typename Base::size_type; + using difference_type = typename Base::difference_type; LegacyAllocator() : Base("LegacyAllocator", "Allocator for Legacy CryEngine systems") { } - pointer_type Allocate(size_type byteSize, size_type alignment, int flags = 0, const char* name = 0, const char* fileName = 0, int lineNum = 0, unsigned int suppressStackRecord = 0) override - { - if (alignment == 0) - { - // Some STL containers, like std::vector, are assuming a specific minimum alignment. seems to have a requirement - // Take a look at _Allocate_manually_vector_aligned in xmemory0 - alignment = sizeof(void*) * 2; - } - - pointer_type ptr = m_schema->Allocate(byteSize, alignment, flags, name, fileName, lineNum, suppressStackRecord); - AZ_PROFILE_MEMORY_ALLOC_EX(AZ::Debug::ProfileCategory::MemoryReserved, fileName, lineNum, ptr, byteSize, name ? name : GetName()); - AZ_MEMORY_PROFILE(ProfileAllocation(ptr, byteSize, alignment, name, fileName, lineNum, suppressStackRecord)); - AZ_Assert(ptr || byteSize == 0, "OOM - Failed to allocate %zu bytes from LegacyAllocator", byteSize); - return ptr; - } + pointer_type Allocate(size_type byteSize, size_type alignment, int flags = 0, const char* name = 0, const char* fileName = 0, int lineNum = 0, unsigned int suppressStackRecord = 0) override; // DeAllocate with file/line, to track when allocs were freed from Cry - void DeAllocate(pointer_type ptr, [[maybe_unused]] const char* file, [[maybe_unused]] const int line, size_type byteSize = 0, size_type alignment = 0) - { - AZ_PROFILE_MEMORY_FREE_EX(AZ::Debug::ProfileCategory::MemoryReserved, file, line, ptr); - AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, byteSize, alignment, nullptr)); - m_schema->DeAllocate(ptr, byteSize, alignment); - } + void DeAllocate(pointer_type ptr, const char* file, const int line, size_type byteSize = 0, size_type alignment = 0); // Realloc with file/line, because Cry uses realloc(nullptr) and realloc(ptr, 0) to mimic malloc/free - pointer_type ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment, [[maybe_unused]] const char* file, [[maybe_unused]] const int line) - { - if (newAlignment == 0) - { - // Some STL containers, like std::vector, are assuming a specific minimum alignment. seems to have a requirement - // Take a look at _Allocate_manually_vector_aligned in xmemory0 - newAlignment = sizeof(void*) * 2; - } + pointer_type ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment, const char* file, const int line); - AZ_MEMORY_PROFILE(ProfileReallocationBegin(ptr, newSize)); - AZ_PROFILE_MEMORY_FREE_EX(AZ::Debug::ProfileCategory::MemoryReserved, file, line, ptr); - pointer_type newPtr = m_schema->ReAllocate(ptr, newSize, newAlignment); - AZ_PROFILE_MEMORY_ALLOC_EX(AZ::Debug::ProfileCategory::MemoryReserved, file, line, newPtr, newSize, "LegacyAllocator Realloc"); - AZ_MEMORY_PROFILE(ProfileReallocationEnd(ptr, newPtr, newSize, newAlignment)); - AZ_Assert(newPtr || newSize == 0, "OOM - Failed to reallocate %zu bytes from LegacyAllocator", newSize); - return newPtr; - } + void DeAllocate(pointer_type ptr, size_type byteSize = 0, size_type alignment = 0) override; - void DeAllocate(pointer_type ptr, size_type byteSize = 0, size_type alignment = 0) override - { - AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, 0, 0, nullptr)); - Base::DeAllocate(ptr, byteSize, alignment); - } - - pointer_type ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment) override - { - if (newAlignment == 0) - { - // Some STL containers, like std::vector, are assuming a specific minimum alignment. seems to have a requirement - // Take a look at _Allocate_manually_vector_aligned in xmemory0 - newAlignment = sizeof(void*) * 2; - } - - AZ_MEMORY_PROFILE(ProfileReallocationBegin(ptr, newSize)); - pointer_type newPtr = Base::ReAllocate(ptr, newSize, newAlignment); - AZ_MEMORY_PROFILE(ProfileReallocationEnd(ptr, newPtr, newSize, newAlignment)); - AZ_Assert(newPtr || newSize == 0, "OOM - Failed to reallocate %zu bytes from LegacyAllocator", newSize); - return newPtr; - } + pointer_type ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment) override; }; using StdLegacyAllocator = AZStdAlloc; @@ -133,57 +51,4 @@ namespace AZ class AllocatorInstance : public Internal::AllocatorInstanceBase { }; - -#if defined(AZ_PLATFORM_PROVO) || defined(AZ_PLATFORM_JASPER) - struct GlobalAllocatorDescriptor - : public AZ::HphaSchema::Descriptor - { - GlobalAllocatorDescriptor() - { - // pull 1MB from the OS at a time - m_systemChunkSize = 1024 * 1024; - } - }; - - class GlobalAllocator - : public SimpleSchemaAllocator - { - public: - AZ_TYPE_INFO(GlobalAllocator, "{BC7861DA-AF7F-4FFD-A2F5-BAD89BDD77FD}"); - - using Descriptor = GlobalAllocatorDescriptor; - using Base = SimpleSchemaAllocator; - - GlobalAllocator() - : Base("GlobalAllocator", "Allocator for untracked new/delete/malloc/free") - { - } - - //--------------------------------------------------------------------- - // IAllocatorAllocate - //--------------------------------------------------------------------- - pointer_type Allocate(size_type byteSize, size_type alignment, int flags = 0, const char* name = 0, const char* fileName = 0, int lineNum = 0, unsigned int suppressStackRecord = 0) override - { - // Note: We cannot put the asserts in the AllocateBase class because various allocators depend on allocations failing from some heap classes. - pointer_type ptr = Base::Allocate(byteSize, alignment, flags, name, fileName, lineNum, suppressStackRecord); - AZ_Assert(ptr, "OOM - Failed to allocate %zu bytes from GlobalAllocator", byteSize); - return ptr; - } - - pointer_type ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment) override - { - pointer_type newPtr = Base::ReAllocate(ptr, newSize, newAlignment); - AZ_Assert(newPtr, "OOM - Failed to reallocate %zu bytes from GlobalAllocator", newSize); - return newPtr; - } - - }; - - // Specialize for the GlobalAllocator to provide one per module that does not use the - // environment for its storage - template <> - class AllocatorInstance : public Internal::AllocatorInstanceBase> - { - }; -#endif } diff --git a/Code/Legacy/CryCommon/crycommon_files.cmake b/Code/Legacy/CryCommon/crycommon_files.cmake index 8d33b85eff..d3613baed6 100644 --- a/Code/Legacy/CryCommon/crycommon_files.cmake +++ b/Code/Legacy/CryCommon/crycommon_files.cmake @@ -92,6 +92,7 @@ set(FILES CryVersion.h FrameProfiler.h HeapAllocator.h + LegacyAllocator.cpp LegacyAllocator.h MetaUtils.h MiniQueue.h From b26107e98df688e1d411c397bdbb6e696d633d45 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 13 Aug 2021 10:07:35 -0700 Subject: [PATCH 07/54] Fix for NameDictionary Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../AzCore/AzCore/Name/NameDictionary.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp index c04ae0ea5e..4c4d6b31e8 100644 --- a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp +++ b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp @@ -185,8 +185,25 @@ namespace AZ return; } + // Get the hash before locking since another thread could be deleting the object within the lock + Internal::NameData::Hash hash = nameData->GetHash(); + AZStd::unique_lock lock(m_sharedMutex); + auto dictIt = m_dictionary.find(hash); + if (dictIt == m_dictionary.end()) + { + // This check is to safeguard around the following scenario + // T1, gets into TryReleaseName + // T2 gets into MakeName, acquires the lock, returns a new Name that increments the counter + // T2 deletes the Name decrements the counter, gets into TryReleaseName + // T1 gets the lock, goes to the compare_exchange if and has a counter of 0, deletes + // Then T2 continues, gets the lock and crashes because nameData was deleted + return; + } + + nameData = dictIt->second; // restore the pointer in case the intrusive ptr was already assigned by other thread + // Check m_hashCollision again inside the m_sharedMutex because a new collision could have happened // on another thread before taking the lock. if (nameData->m_hashCollision) From c67a9f3d12e619abc8e4f919bf424f4cfd409e5c Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 16 Aug 2021 17:13:43 -0500 Subject: [PATCH 08/54] Updated material component request bus to better support script canvas Change all name parameters to use standard string so that they could be headed in in script canvas nodes and RPE Added explicitly type functions for getting and saving property overrides Signed-off-by: Guthrie Adams --- .../Material/MaterialComponentBus.h | 54 ++++- .../Material/MaterialComponentController.cpp | 187 +++++++++++++++++- .../Material/MaterialComponentController.h | 30 ++- 3 files changed, 254 insertions(+), 17 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h index 234ea99066..01c87fa2fb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h @@ -41,12 +41,56 @@ namespace AZ virtual const AZ::Data::AssetId GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const = 0; //! Clear material override virtual void ClearMaterialOverride(const MaterialAssignmentId& materialAssignmentId) = 0; - //! Set a material property value override - virtual void SetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const Name& propertyName, const AZStd::any& propertyValue) = 0; - //! Get a material property value override - virtual AZStd::any GetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const Name& propertyName) const = 0; + //! Set a material property override value wrapped by an AZStd::any + virtual void SetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::any& value) = 0; + //! Set a material property override value to a bool + virtual void SetPropertyOverrideBool(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const bool& value) = 0; + //! Set a material property override value to a integer + virtual void SetPropertyOverrideInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const int32_t& value) = 0; + //! Set a material property override value to a unsigned integer + virtual void SetPropertyOverrideUInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const uint32_t& value) = 0; + //! Set a material property override value to a float + virtual void SetPropertyOverrideFloat(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const float& value) = 0; + //! Set a material property override value to a Vector2 + virtual void SetPropertyOverrideVector2(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector2& value) = 0; + //! Set a material property override value to a Vector3 + virtual void SetPropertyOverrideVector3(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector3& value) = 0; + //! Set a material property override value to a Vector4 + virtual void SetPropertyOverrideVector4(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector4& value) = 0; + //! Set a material property override value to a color + virtual void SetPropertyOverrideColor(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Color& value) = 0; + //! Set a material property override value to an image asset + virtual void SetPropertyOverrideImageAsset(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Data::Asset& value) = 0; + //! Set a material property override value to an image instance + virtual void SetPropertyOverrideImageInstance(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Data::Instance& value) = 0; + //! Set a material property override value to a string + virtual void SetPropertyOverrideString(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::string& value) = 0; + //! Get a material property override value wrapped by an AZStd::any + virtual AZStd::any GetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0; + //! Get a material property override value as a bool + virtual bool GetPropertyOverrideBool(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0; + //! Get a material property override value as an integer + virtual int32_t GetPropertyOverrideInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0; + //! Get a material property override value as an unsigned integer + virtual uint32_t GetPropertyOverrideUInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0; + //! Get a material property override value as a float + virtual float GetPropertyOverrideFloat(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0; + //! Get a material property override value as a Vector2 + virtual AZ::Vector2 GetPropertyOverrideVector2(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0; + //! Get a material property override value as a Vector3 + virtual AZ::Vector3 GetPropertyOverrideVector3(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0; + //! Get a material property override value as a Vector4 + virtual AZ::Vector4 GetPropertyOverrideVector4(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0; + //! Get a material property override value as a Color + virtual AZ::Color GetPropertyOverrideColor(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0; + //! Get a material property override value as an image asset + virtual AZ::Data::Asset GetPropertyOverrideImageAsset(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0; + //! Get a material property override value as an image instance + virtual AZ::Data::Instance GetPropertyOverrideImageInstance(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0; + //! Get a material property override value as a string + virtual AZStd::string GetPropertyOverrideString(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0; //! Clear property override for a specific material assignment - virtual void ClearPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const Name& propertyName) = 0; + virtual void ClearPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) = 0; //! Clear property overrides for a specific material assignment virtual void ClearPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) = 0; //! Clear all property overrides diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index e39f5cfad5..91ac73a209 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -44,7 +44,29 @@ namespace AZ ->Event("GetMaterialOverride", &MaterialComponentRequestBus::Events::GetMaterialOverride) ->Event("ClearMaterialOverride", &MaterialComponentRequestBus::Events::ClearMaterialOverride) ->Event("SetPropertyOverride", &MaterialComponentRequestBus::Events::SetPropertyOverride) + ->Event("SetPropertyOverrideBool", &MaterialComponentRequestBus::Events::SetPropertyOverrideBool) + ->Event("SetPropertyOverrideInt32", &MaterialComponentRequestBus::Events::SetPropertyOverrideInt32) + ->Event("SetPropertyOverrideUInt32", &MaterialComponentRequestBus::Events::SetPropertyOverrideUInt32) + ->Event("SetPropertyOverrideFloat", &MaterialComponentRequestBus::Events::SetPropertyOverrideFloat) + ->Event("SetPropertyOverrideVector2", &MaterialComponentRequestBus::Events::SetPropertyOverrideVector2) + ->Event("SetPropertyOverrideVector3", &MaterialComponentRequestBus::Events::SetPropertyOverrideVector3) + ->Event("SetPropertyOverrideVector4", &MaterialComponentRequestBus::Events::SetPropertyOverrideVector4) + ->Event("SetPropertyOverrideColor", &MaterialComponentRequestBus::Events::SetPropertyOverrideColor) + ->Event("SetPropertyOverrideImageAsset", &MaterialComponentRequestBus::Events::SetPropertyOverrideImageAsset) + ->Event("SetPropertyOverrideImageInstance", &MaterialComponentRequestBus::Events::SetPropertyOverrideImageInstance) + ->Event("SetPropertyOverrideString", &MaterialComponentRequestBus::Events::SetPropertyOverrideString) ->Event("GetPropertyOverride", &MaterialComponentRequestBus::Events::GetPropertyOverride) + ->Event("GetPropertyOverrideBool", &MaterialComponentRequestBus::Events::GetPropertyOverrideBool) + ->Event("GetPropertyOverrideInt32", &MaterialComponentRequestBus::Events::GetPropertyOverrideInt32) + ->Event("GetPropertyOverrideUInt32", &MaterialComponentRequestBus::Events::GetPropertyOverrideUInt32) + ->Event("GetPropertyOverrideFloat", &MaterialComponentRequestBus::Events::GetPropertyOverrideFloat) + ->Event("GetPropertyOverrideVector2", &MaterialComponentRequestBus::Events::GetPropertyOverrideVector2) + ->Event("GetPropertyOverrideVector3", &MaterialComponentRequestBus::Events::GetPropertyOverrideVector3) + ->Event("GetPropertyOverrideVector4", &MaterialComponentRequestBus::Events::GetPropertyOverrideVector4) + ->Event("GetPropertyOverrideColor", &MaterialComponentRequestBus::Events::GetPropertyOverrideColor) + ->Event("GetPropertyOverrideImageAsset", &MaterialComponentRequestBus::Events::GetPropertyOverrideImageAsset) + ->Event("GetPropertyOverrideImageInstance", &MaterialComponentRequestBus::Events::GetPropertyOverrideImageInstance) + ->Event("GetPropertyOverrideString", &MaterialComponentRequestBus::Events::GetPropertyOverrideString) ->Event("ClearPropertyOverride", &MaterialComponentRequestBus::Events::ClearPropertyOverride) ->Event("ClearPropertyOverrides", &MaterialComponentRequestBus::Events::ClearPropertyOverrides) ->Event("ClearAllPropertyOverrides", &MaterialComponentRequestBus::Events::ClearAllPropertyOverrides) @@ -331,27 +353,97 @@ namespace AZ } } - void MaterialComponentController::SetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const Name& propertyName, const AZStd::any& propertyValue) + void MaterialComponentController::SetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::any& value) { auto& materialAssignment = m_configuration.m_materials[materialAssignmentId]; // When applying property overrides for the first time, new instance needs to be created in case the current instance is already used somewhere else to keep overrides local if (materialAssignment.m_propertyOverrides.empty()) { - materialAssignment.m_propertyOverrides[propertyName] = propertyValue; + materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value; materialAssignment.RebuildInstance(); QueueMaterialUpdateNotification(); } else { - materialAssignment.m_propertyOverrides[propertyName] = propertyValue; + materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value; } QueuePropertyChanges(materialAssignmentId); MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited, m_configuration.m_materials); } - AZStd::any MaterialComponentController::GetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const Name& propertyName) const + void MaterialComponentController::SetPropertyOverrideBool( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const bool& value) + { + SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value)); + } + + void MaterialComponentController::SetPropertyOverrideInt32( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const int32_t& value) + { + SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value)); + } + + void MaterialComponentController::SetPropertyOverrideUInt32( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const uint32_t& value) + { + SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value)); + } + + void MaterialComponentController::SetPropertyOverrideFloat( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const float& value) + { + SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value)); + } + + void MaterialComponentController::SetPropertyOverrideVector2( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector2& value) + { + SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value)); + } + + void MaterialComponentController::SetPropertyOverrideVector3( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector3& value) + { + SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value)); + } + + void MaterialComponentController::SetPropertyOverrideVector4( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector4& value) + { + SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value)); + } + + void MaterialComponentController::SetPropertyOverrideColor( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Color& value) + { + SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value)); + } + + void MaterialComponentController::SetPropertyOverrideImageAsset( + const MaterialAssignmentId& materialAssignmentId, + const AZStd::string& propertyName, + const AZ::Data::Asset& value) + { + SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value)); + } + + void MaterialComponentController::SetPropertyOverrideImageInstance( + const MaterialAssignmentId& materialAssignmentId, + const AZStd::string& propertyName, + const AZ::Data::Instance& value) + { + SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value)); + } + + void MaterialComponentController::SetPropertyOverrideString( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::string& value) + { + SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value)); + } + + AZStd::any MaterialComponentController::GetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const { const auto materialIt = m_configuration.m_materials.find(materialAssignmentId); if (materialIt == m_configuration.m_materials.end()) @@ -360,17 +452,94 @@ namespace AZ return {}; } - const auto propertyIt = materialIt->second.m_propertyOverrides.find(propertyName); + const auto propertyIt = materialIt->second.m_propertyOverrides.find(AZ::Name(propertyName)); if (propertyIt == materialIt->second.m_propertyOverrides.end()) { - AZ_Error("MaterialComponentController", false, "Property not found: %s.", propertyName.GetCStr()); + AZ_Error("MaterialComponentController", false, "Property not found: %s.", propertyName.c_str()); return {}; } return propertyIt->second; } - void MaterialComponentController::ClearPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const Name& propertyName) + bool MaterialComponentController::GetPropertyOverrideBool( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const + { + const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName); + return !value.empty() && value.is() ? AZStd::any_cast(value) : false; + } + + int32_t MaterialComponentController::GetPropertyOverrideInt32( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const + { + const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName); + return !value.empty() && value.is() ? AZStd::any_cast(value) : 0; + } + + uint32_t MaterialComponentController::GetPropertyOverrideUInt32( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const + { + const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName); + return !value.empty() && value.is() ? AZStd::any_cast(value) : 0; + } + + float MaterialComponentController::GetPropertyOverrideFloat( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const + { + const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName); + return !value.empty() && value.is() ? AZStd::any_cast(value) : 0.0f; + } + + AZ::Vector2 MaterialComponentController::GetPropertyOverrideVector2( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const + { + const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName); + return !value.empty() && value.is() ? AZStd::any_cast(value) : AZ::Vector2::CreateZero(); + } + + AZ::Vector3 MaterialComponentController::GetPropertyOverrideVector3( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const + { + const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName); + return !value.empty() && value.is() ? AZStd::any_cast(value) : AZ::Vector3::CreateZero(); + } + + AZ::Vector4 MaterialComponentController::GetPropertyOverrideVector4( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const + { + const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName); + return !value.empty() && value.is() ? AZStd::any_cast(value) : AZ::Vector4::CreateZero(); + } + + AZ::Color MaterialComponentController::GetPropertyOverrideColor( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const + { + const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName); + return !value.empty() && value.is() ? AZStd::any_cast(value) : AZ::Color::CreateZero(); + } + + AZ::Data::Asset MaterialComponentController::GetPropertyOverrideImageAsset( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const + { + const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName); + return !value.empty() && value.is>() ? AZStd::any_cast>(value) : AZ::Data::Asset(); + } + + AZ::Data::Instance MaterialComponentController::GetPropertyOverrideImageInstance( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const + { + const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName); + return !value.empty() && value.is>() ? AZStd::any_cast>(value) : AZ::Data::Instance(); + } + + AZStd::string MaterialComponentController::GetPropertyOverrideString( + const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const + { + const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName); + return !value.empty() && value.is() ? AZStd::any_cast(value) : AZStd::string(); + } + + void MaterialComponentController::ClearPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) { auto materialIt = m_configuration.m_materials.find(materialAssignmentId); if (materialIt == m_configuration.m_materials.end()) @@ -379,10 +548,10 @@ namespace AZ return; } - auto propertyIt = materialIt->second.m_propertyOverrides.find(propertyName); + auto propertyIt = materialIt->second.m_propertyOverrides.find(AZ::Name(propertyName)); if (propertyIt == materialIt->second.m_propertyOverrides.end()) { - AZ_Error("MaterialComponentController", false, "Property not found: %s.", propertyName.GetCStr()); + AZ_Error("MaterialComponentController", false, "Property not found: %s.", propertyName.c_str()); return; } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h index de7f991d60..8866493998 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h @@ -57,9 +57,33 @@ namespace AZ const AZ::Data::AssetId GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const override; void ClearMaterialOverride(const MaterialAssignmentId& materialAssignmentId) override; - void SetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const Name& propertyName, const AZStd::any& propertyValue) override; - AZStd::any GetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const Name& propertyName) const override; - void ClearPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const Name& propertyName) override; + void SetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::any& value) override; + void SetPropertyOverrideBool(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const bool& value) override; + void SetPropertyOverrideInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const int32_t& value) override; + void SetPropertyOverrideUInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const uint32_t& value) override; + void SetPropertyOverrideFloat(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const float& value) override; + void SetPropertyOverrideVector2(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector2& value) override; + void SetPropertyOverrideVector3(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector3& value) override; + void SetPropertyOverrideVector4(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector4& value) override; + void SetPropertyOverrideColor(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Color& value) override; + void SetPropertyOverrideImageAsset(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Data::Asset& value) override; + void SetPropertyOverrideImageInstance(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Data::Instance& value) override; + void SetPropertyOverrideString(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::string& value) override; + + AZStd::any GetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override; + bool GetPropertyOverrideBool(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override; + int32_t GetPropertyOverrideInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override; + uint32_t GetPropertyOverrideUInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override; + float GetPropertyOverrideFloat(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override; + AZ::Vector2 GetPropertyOverrideVector2(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override; + AZ::Vector3 GetPropertyOverrideVector3(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override; + AZ::Vector4 GetPropertyOverrideVector4(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override; + AZ::Color GetPropertyOverrideColor(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override; + AZ::Data::Asset GetPropertyOverrideImageAsset(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override; + AZ::Data::Instance GetPropertyOverrideImageInstance(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override; + AZStd::string GetPropertyOverrideString(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override; + + void ClearPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) override; void ClearPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) override; void ClearAllPropertyOverrides() override; MaterialPropertyOverrideMap GetPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) const override; From 7da5b032e77536e6a03353b5e9c750ae986aecc0 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 16 Aug 2021 17:41:51 -0500 Subject: [PATCH 09/54] updated test scripts Signed-off-by: Guthrie Adams --- .../Common/Assets/Scripts/material_find_overrides_demo.lua | 6 +++--- .../Assets/Scripts/material_property_overrides_demo.lua | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Scripts/material_find_overrides_demo.lua b/Gems/Atom/Feature/Common/Assets/Scripts/material_find_overrides_demo.lua index dda3974043..41df35e355 100644 --- a/Gems/Atom/Feature/Common/Assets/Scripts/material_find_overrides_demo.lua +++ b/Gems/Atom/Feature/Common/Assets/Scripts/material_find_overrides_demo.lua @@ -66,20 +66,20 @@ function FindMaterialAssignmentTest:OnActivate() end function FindMaterialAssignmentTest:UpdateFactor(assignmentId) - local propertyName = Name("baseColor.factor") + local propertyName = "baseColor.factor" local propertyValue = math.random() MaterialComponentRequestBus.Event.SetPropertyOverride(self.entityId, assignmentId, propertyName, propertyValue); end function FindMaterialAssignmentTest:UpdateColor(assignmentId, color) - local propertyName = Name("baseColor.color") + local propertyName = "baseColor.color" local propertyValue = color MaterialComponentRequestBus.Event.SetPropertyOverride(self.entityId, assignmentId, propertyName, propertyValue); end function FindMaterialAssignmentTest:UpdateTexture(assignmentId) if (#self.Properties.Textures > 0) then - local propertyName = Name("baseColor.textureMap") + local propertyName = "baseColor.textureMap" local textureName = self.Properties.Textures[ math.random( #self.Properties.Textures ) ] Debug.Log(textureName) local textureAssetId = AssetCatalogRequestBus.Broadcast.GetAssetIdByPath(textureName, Uuid(), false) diff --git a/Gems/Atom/Feature/Common/Assets/Scripts/material_property_overrides_demo.lua b/Gems/Atom/Feature/Common/Assets/Scripts/material_property_overrides_demo.lua index 685fd8310b..0495dccbc0 100644 --- a/Gems/Atom/Feature/Common/Assets/Scripts/material_property_overrides_demo.lua +++ b/Gems/Atom/Feature/Common/Assets/Scripts/material_property_overrides_demo.lua @@ -64,20 +64,20 @@ function PropertyOverrideTest:OnActivate() end function PropertyOverrideTest:UpdateFactor(assignmentId) - local propertyName = Name("baseColor.factor") + local propertyName = "baseColor.factor" local propertyValue = math.random() MaterialComponentRequestBus.Event.SetPropertyOverride(self.entityId, assignmentId, propertyName, propertyValue); end function PropertyOverrideTest:UpdateColor(assignmentId, color) - local propertyName = Name("baseColor.color") + local propertyName = "baseColor.color" local propertyValue = color MaterialComponentRequestBus.Event.SetPropertyOverride(self.entityId, assignmentId, propertyName, propertyValue); end function PropertyOverrideTest:UpdateTexture(assignmentId) if (#self.Properties.Textures > 0) then - local propertyName = Name("baseColor.textureMap") + local propertyName = "baseColor.textureMap" local textureName = self.Properties.Textures[ math.random( #self.Properties.Textures ) ] Debug.Log(textureName) local textureAssetId = AssetCatalogRequestBus.Broadcast.GetAssetIdByPath(textureName, Uuid(), false) From 7be2b0b6c37165104b80b6248370af61d6b33386 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Tue, 17 Aug 2021 11:49:51 -0700 Subject: [PATCH 10/54] Fix for a leaky test Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Name/Name.h | 6 ++++ .../Framework/AzCore/Tests/Name/NameTests.cpp | 31 ++++++++++++++----- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Name/Name.h b/Code/Framework/AzCore/AzCore/Name/Name.h index 46a9b5b7cc..16179c9cde 100644 --- a/Code/Framework/AzCore/AzCore/Name/Name.h +++ b/Code/Framework/AzCore/AzCore/Name/Name.h @@ -10,6 +10,11 @@ #include +namespace UnitTest +{ + class NameTest; +} + namespace AZ { class NameDictionary; @@ -29,6 +34,7 @@ namespace AZ class Name { friend NameDictionary; + friend UnitTest::NameTest; public: using Hash = Internal::NameData::Hash; diff --git a/Code/Framework/AzCore/Tests/Name/NameTests.cpp b/Code/Framework/AzCore/Tests/Name/NameTests.cpp index 3b6310b1de..a46c1724f6 100644 --- a/Code/Framework/AzCore/Tests/Name/NameTests.cpp +++ b/Code/Framework/AzCore/Tests/Name/NameTests.cpp @@ -171,7 +171,17 @@ namespace UnitTest azsnprintf(buffer, RandomStringBufferSize, "%d", m_random.GetRandom()); return buffer; } - + + AZ::Internal::NameData* GetNameData(AZ::Name& name) + { + return name.m_data.get(); + } + + void FreeMemoryFromNameData(AZ::Internal::NameData* nameData) + { + delete nameData; + } + AZ::SimpleLcgRandom m_random; }; @@ -488,13 +498,20 @@ namespace UnitTest TEST_F(NameTest, ReportLeakedNames) { - AZ::Name leakedName{"hello"}; - AZ_TEST_START_TRACE_SUPPRESSION; - AZ::NameDictionary::Destroy(); - AZ_TEST_STOP_TRACE_SUPPRESSION(1); + AZ::Internal::NameData* leakedNameData = nullptr; + { + AZ::Name leakedName{ "hello" }; + AZ_TEST_START_TRACE_SUPPRESSION; + AZ::NameDictionary::Destroy(); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); - // Create the dictionary again to avoid error in TearDown() - AZ::NameDictionary::Create(); + leakedNameData = GetNameData(leakedName); + + // Create the dictionary again to avoid crash when the intrusive_ptr in Name tries to access NameDictionary to free it + AZ::NameDictionary::Create(); + } + + FreeMemoryFromNameData(leakedNameData); // free it to avoid memory system reporting the leak } TEST_F(NameTest, NullTerminatedTest) From 8ebaf1084057306fcbbcf247a4d1009cfb4a5b96 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Tue, 17 Aug 2021 14:04:26 -0500 Subject: [PATCH 11/54] AtomTools: added status message helper functions Signed-off-by: Guthrie Adams --- .../Window/AtomToolsMainWindow.h | 5 ++- .../Source/Window/AtomToolsMainWindow.cpp | 21 ++++++++-- .../Source/Window/MaterialEditorWindow.cpp | 42 ++++++------------- .../Window/ShaderManagementConsoleWindow.cpp | 41 ++++++------------ 4 files changed, 48 insertions(+), 61 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h index 751b30a907..2a304c9a8c 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h @@ -52,8 +52,11 @@ namespace AtomToolsFramework virtual void SelectPreviousTab(); virtual void SelectNextTab(); + void SetStatusMessage(const QString& message); + void SetStatusWarning(const QString& message); + void SetStatusError(const QString& message); + AzQtComponents::FancyDocking* m_advancedDockManager = nullptr; - QMenuBar* m_menuBar = nullptr; AzQtComponents::TabWidget* m_tabWidget = nullptr; QLabel* m_statusMessage = nullptr; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp index e869e0eb98..cd7d49d8d3 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp @@ -110,9 +110,9 @@ namespace AtomToolsFramework void AtomToolsMainWindow::CreateMenu() { - m_menuBar = new QMenuBar(this); - m_menuBar->setObjectName("MenuBar"); - setMenuBar(m_menuBar); + auto menuBar = new QMenuBar(this); + menuBar->setObjectName("MenuBar"); + setMenuBar(menuBar); } void AtomToolsMainWindow::CreateTabBar() @@ -246,4 +246,19 @@ namespace AtomToolsFramework m_tabWidget->setCurrentIndex((m_tabWidget->currentIndex() + 1) % m_tabWidget->count()); } } + + void AtomToolsMainWindow::SetStatusMessage(const QString& message) + { + m_statusMessage->setText(QString("%1").arg(message)); + } + + void AtomToolsMainWindow::SetStatusWarning(const QString& message) + { + m_statusMessage->setText(QString("%1").arg(message)); + } + + void AtomToolsMainWindow::SetStatusError(const QString& message) + { + m_statusMessage->setText(QString("%1").arg(message)); + } } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp index ca938c3745..a32f81f78e 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp @@ -237,18 +237,14 @@ namespace MaterialEditor const QString documentPath = GetDocumentPath(documentId); if (!documentPath.isEmpty()) { - const QString status = QString("Document opened: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusMessage(tr("Document opened: %1").arg(documentPath)); } } void MaterialEditorWindow::OnDocumentClosed(const AZ::Uuid& documentId) { RemoveTabForDocumentId(documentId); - - const QString documentPath = GetDocumentPath(documentId); - const QString status = QString("Document closed: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); } void MaterialEditorWindow::OnDocumentModified(const AZ::Uuid& documentId) @@ -284,10 +280,7 @@ namespace MaterialEditor AZStd::string filename; AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - - const QString documentPath = GetDocumentPath(documentId); - const QString status = QString("Document saved: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusMessage(tr("Document saved: %1").arg(GetDocumentPath(documentId))); } void MaterialEditorWindow::CreateMenu() @@ -295,7 +288,7 @@ namespace MaterialEditor Base::CreateMenu(); // Generating the main menu manually because it's easier and we will have some dynamic or data driven entries - m_menuFile = m_menuBar->addMenu("&File"); + m_menuFile = menuBar()->addMenu("&File"); m_actionNew = m_menuFile->addAction("&New...", [this]() { CreateMaterialDialog createDialog(this); @@ -330,9 +323,7 @@ namespace MaterialEditor AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId); if (!result) { - const QString documentPath = GetDocumentPath(documentId); - const QString status = QString("Document save failed: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); } }, QKeySequence::Save); @@ -345,8 +336,7 @@ namespace MaterialEditor documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); if (!result) { - const QString status = QString("Document save failed: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); } }, QKeySequence::SaveAs); @@ -359,8 +349,7 @@ namespace MaterialEditor documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); if (!result) { - const QString status = QString("Document save failed: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); } }); @@ -369,8 +358,7 @@ namespace MaterialEditor AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments); if (!result) { - const QString status = QString("Document save all failed."); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusError(tr("Document save all failed")); } }); @@ -406,7 +394,7 @@ namespace MaterialEditor close(); }, QKeySequence::Quit); - m_menuEdit = m_menuBar->addMenu("&Edit"); + m_menuEdit = menuBar()->addMenu("&Edit"); m_actionUndo = m_menuEdit->addAction("&Undo", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); @@ -414,9 +402,7 @@ namespace MaterialEditor AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Undo); if (!result) { - const QString documentPath = GetDocumentPath(documentId); - const QString status = QString("Document undo failed: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusError(tr("Document undo failed: %1").arg(GetDocumentPath(documentId))); } }, QKeySequence::Undo); @@ -426,9 +412,7 @@ namespace MaterialEditor AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Redo); if (!result) { - const QString documentPath = GetDocumentPath(documentId); - const QString status = QString("Document redo failed: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusError(tr("Document redo failed: %1").arg(GetDocumentPath(documentId))); } }, QKeySequence::Redo); @@ -440,7 +424,7 @@ namespace MaterialEditor }, QKeySequence::Preferences); m_actionSettings->setEnabled(true); - m_menuView = m_menuBar->addMenu("&View"); + m_menuView = menuBar()->addMenu("&View"); m_actionAssetBrowser = m_menuView->addAction("&Asset Browser", [this]() { const AZStd::string label = "Asset Browser"; @@ -480,7 +464,7 @@ namespace MaterialEditor SelectNextTab(); }, Qt::CTRL | Qt::Key_Tab); //QKeySequence::NextChild works as expected but mirroring Previous - m_menuHelp = m_menuBar->addMenu("&Help"); + m_menuHelp = menuBar()->addMenu("&Help"); m_actionHelp = m_menuHelp->addAction("&Help...", [this]() { HelpDialog dialog(this); diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp index 0b4802640b..6354f8beba 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp @@ -149,18 +149,14 @@ namespace ShaderManagementConsole const QString documentPath = GetDocumentPath(documentId); if (!documentPath.isEmpty()) { - const QString status = QString("Document opened: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusMessage(tr("Document opened: %1").arg(documentPath)); } } void ShaderManagementConsoleWindow::OnDocumentClosed(const AZ::Uuid& documentId) { RemoveTabForDocumentId(documentId); - - const QString documentPath = GetDocumentPath(documentId); - const QString status = QString("Document closed: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); } void ShaderManagementConsoleWindow::OnDocumentModified(const AZ::Uuid& documentId) @@ -196,10 +192,7 @@ namespace ShaderManagementConsole AZStd::string filename; AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - - const QString documentPath = GetDocumentPath(documentId); - const QString status = QString("Document saved: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusMessage(tr("Document saved: %1").arg(GetDocumentPath(documentId))); } void ShaderManagementConsoleWindow::CreateMenu() @@ -207,7 +200,7 @@ namespace ShaderManagementConsole Base::CreateMenu(); // Generating the main menu manually because it's easier and we will have some dynamic or data driven entries - m_menuFile = m_menuBar->addMenu("&File"); + m_menuFile = menuBar()->addMenu("&File"); m_actionOpen = m_menuFile->addAction("&Open...", [this]() { const AZStd::vector assetTypes = { @@ -230,9 +223,7 @@ namespace ShaderManagementConsole AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId); if (!result) { - const QString documentPath = GetDocumentPath(documentId); - const QString status = QString("Document save failed: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); } }, QKeySequence::Save); @@ -245,8 +236,7 @@ namespace ShaderManagementConsole documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); if (!result) { - const QString status = QString("Document save failed: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); } }, QKeySequence::SaveAs); @@ -255,8 +245,7 @@ namespace ShaderManagementConsole AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments); if (!result) { - const QString status = QString("Document save all failed."); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusError(tr("Document save all failed")); } }); @@ -278,7 +267,7 @@ namespace ShaderManagementConsole m_menuFile->addSeparator(); - m_menuFile->addAction("Run Python...", [this]() { + m_menuFile->addAction("Run &Python...", [this]() { const QString script = QFileDialog::getOpenFileName(this, "Run Script", QString(), QString("*.py")); if (!script.isEmpty()) { @@ -292,7 +281,7 @@ namespace ShaderManagementConsole close(); }, QKeySequence::Quit); - m_menuEdit = m_menuBar->addMenu("&Edit"); + m_menuEdit = menuBar()->addMenu("&Edit"); m_actionUndo = m_menuEdit->addAction("&Undo", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); @@ -300,9 +289,7 @@ namespace ShaderManagementConsole AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Undo); if (!result) { - const QString documentPath = GetDocumentPath(documentId); - const QString status = QString("Document undo failed: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusError(tr("Document undo failed: %1").arg(GetDocumentPath(documentId))); } }, QKeySequence::Undo); @@ -312,9 +299,7 @@ namespace ShaderManagementConsole AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Redo); if (!result) { - const QString documentPath = GetDocumentPath(documentId); - const QString status = QString("Document redo failed: %1").arg(documentPath); - m_statusMessage->setText(QString("%1").arg(status)); + SetStatusError(tr("Document redo failed: %1").arg(GetDocumentPath(documentId))); } }, QKeySequence::Redo); @@ -324,7 +309,7 @@ namespace ShaderManagementConsole }, QKeySequence::Preferences); m_actionSettings->setEnabled(false); - m_menuView = m_menuBar->addMenu("&View"); + m_menuView = menuBar()->addMenu("&View"); m_actionAssetBrowser = m_menuView->addAction("&Asset Browser", [this]() { const AZStd::string label = "Asset Browser"; @@ -347,7 +332,7 @@ namespace ShaderManagementConsole SelectNextTab(); }, Qt::CTRL | Qt::Key_Tab); //QKeySequence::NextChild works as expected but mirroring Previous - m_menuHelp = m_menuBar->addMenu("&Help"); + m_menuHelp = menuBar()->addMenu("&Help"); m_actionHelp = m_menuHelp->addAction("&Help...", [this]() { }); From e29479552b3f892f76bc82b3386ad91965024b5d Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Tue, 17 Aug 2021 15:53:14 -0700 Subject: [PATCH 12/54] alignment fix Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzCore/Tests/Math/SfmtTests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzCore/Tests/Math/SfmtTests.cpp b/Code/Framework/AzCore/Tests/Math/SfmtTests.cpp index f40246b8e9..397e8bd24f 100644 --- a/Code/Framework/AzCore/Tests/Math/SfmtTests.cpp +++ b/Code/Framework/AzCore/Tests/Math/SfmtTests.cpp @@ -27,8 +27,8 @@ namespace UnitTest void SetUp() override { AllocatorsFixture::SetUp(); - array1 = (AZ::u64*)azmalloc(sizeof(AZ::u64) * 2 * (BLOCK_SIZE / 4), AZStd::alignment_of::value); - array2 = (AZ::u64*)azmalloc(sizeof(AZ::u64) * 2 * (10000 / 4), AZStd::alignment_of::value); + array1 = (AZ::u64*)azmalloc(sizeof(AZ::u64) * 2 * (BLOCK_SIZE / 4), AZStd::alignment_of::value); + array2 = (AZ::u64*)azmalloc(sizeof(AZ::u64) * 2 * (10000 / 4), AZStd::alignment_of::value); } void TearDown() override From 4adf5c051e73df2b5dfdd8ebb0d92a9ad4c15843 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Tue, 17 Aug 2021 16:16:19 -0700 Subject: [PATCH 13/54] more NameTest fixes, AzCore passing ASan Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzCore/Tests/Name/NameTests.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzCore/Tests/Name/NameTests.cpp b/Code/Framework/AzCore/Tests/Name/NameTests.cpp index a46c1724f6..34b0950aea 100644 --- a/Code/Framework/AzCore/Tests/Name/NameTests.cpp +++ b/Code/Framework/AzCore/Tests/Name/NameTests.cpp @@ -604,7 +604,8 @@ namespace UnitTest AZ::NameDictionary::Create(); // 3 threads per name effectively makes two readers and one writer (the first to run will write in the dictionary) - RunConcurrencyTest(AZ_TRAIT_UNIT_TEST_NAME_COUNT, 3); + // Using AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2 since the following line generates 3000 threads and that triggers ASan failures + RunConcurrencyTest(AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2, 3); } TEST_F(NameTest, ConcurrencyDataTest_EachThreadCreatesOneName_HighCollisions) @@ -614,7 +615,8 @@ namespace UnitTest AZ::NameDictionary::Create(); // 3 threads per name effectively makes two readers and one writer (the first to run will write in the dictionary) - RunConcurrencyTest(AZ_TRAIT_UNIT_TEST_NAME_COUNT, 3); + // Using AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2 since the following line generates 3000 threads and that triggers ASan failures + RunConcurrencyTest(AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2, 3); } TEST_F(NameTest, ConcurrencyDataTest_EachThreadRepeatedlyCreatesAndReleasesOneName_NoCollision) From a49e07c8e9451f1d028a84aed5e2f76c73466e1f Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Tue, 17 Aug 2021 16:20:39 -0700 Subject: [PATCH 14/54] improving comment Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzCore/Tests/Name/NameTests.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzCore/Tests/Name/NameTests.cpp b/Code/Framework/AzCore/Tests/Name/NameTests.cpp index 34b0950aea..c0dc37715f 100644 --- a/Code/Framework/AzCore/Tests/Name/NameTests.cpp +++ b/Code/Framework/AzCore/Tests/Name/NameTests.cpp @@ -604,7 +604,8 @@ namespace UnitTest AZ::NameDictionary::Create(); // 3 threads per name effectively makes two readers and one writer (the first to run will write in the dictionary) - // Using AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2 since the following line generates 3000 threads and that triggers ASan failures + // Using AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2 since the following line generates 3000 threads and that triggers ASan failures, + // likely because of https://devblogs.microsoft.com/oldnewthing/20050729-14/?p=34773 RunConcurrencyTest(AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2, 3); } @@ -615,7 +616,8 @@ namespace UnitTest AZ::NameDictionary::Create(); // 3 threads per name effectively makes two readers and one writer (the first to run will write in the dictionary) - // Using AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2 since the following line generates 3000 threads and that triggers ASan failures + // Using AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2 since the following line generates 3000 threads and that triggers ASan failures, + // likely because of https://devblogs.microsoft.com/oldnewthing/20050729-14/?p=34773 RunConcurrencyTest(AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2, 3); } From ea01904ecf33043ea44fc3f58a2f710e90aa7c0c Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Tue, 17 Aug 2021 17:40:49 -0700 Subject: [PATCH 15/54] PR comments Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Legacy/CryCommon/LegacyAllocator.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Code/Legacy/CryCommon/LegacyAllocator.cpp b/Code/Legacy/CryCommon/LegacyAllocator.cpp index 9c4258530a..76c4712bd3 100644 --- a/Code/Legacy/CryCommon/LegacyAllocator.cpp +++ b/Code/Legacy/CryCommon/LegacyAllocator.cpp @@ -6,8 +6,6 @@ * */ -#pragma once - #include namespace AZ From 1d7f690e06a06f58cec23d3a8fc5377a14a6dfff Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Tue, 17 Aug 2021 18:02:49 -0700 Subject: [PATCH 16/54] missing header includes Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Plugins/EditorCommon/DrawingPrimitives/TimeSlider.cpp | 2 ++ Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp | 1 + Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ShaderSemantic.h | 1 + Gems/Atom/RHI/Code/Include/Atom/RHI/DispatchItem.h | 1 + .../Code/Source/Debug/MultiplayerDebugByteReporter.cpp | 2 ++ Gems/MultiplayerCompression/Code/Source/LZ4Compressor.h | 1 + .../Generation/Components/MeshOptimizer/MeshBuilderSubMesh.cpp | 1 + 7 files changed, 9 insertions(+) diff --git a/Code/Editor/Plugins/EditorCommon/DrawingPrimitives/TimeSlider.cpp b/Code/Editor/Plugins/EditorCommon/DrawingPrimitives/TimeSlider.cpp index 4774520d0c..291723ff6b 100644 --- a/Code/Editor/Plugins/EditorCommon/DrawingPrimitives/TimeSlider.cpp +++ b/Code/Editor/Plugins/EditorCommon/DrawingPrimitives/TimeSlider.cpp @@ -12,6 +12,8 @@ #include #include +#include + namespace DrawingPrimitives { void DrawTimeSlider(QPainter& painter, const QPalette& palette, const STimeSliderOptions& options) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index a15dffdc94..3781106bdc 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -8,6 +8,7 @@ #include #include +#include namespace O3DE::ProjectManager { diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ShaderSemantic.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ShaderSemantic.h index da791bddfb..ee6e0feeb6 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ShaderSemantic.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ShaderSemantic.h @@ -9,6 +9,7 @@ #include #include +#include namespace AZ { diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/DispatchItem.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/DispatchItem.h index 93ff1e85b7..72f190dcc8 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/DispatchItem.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/DispatchItem.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace AZ { diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp index 45305e3b39..7f904479d1 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp @@ -8,6 +8,8 @@ #include "MultiplayerDebugByteReporter.h" +#include + #include // for std::setfill #include #include diff --git a/Gems/MultiplayerCompression/Code/Source/LZ4Compressor.h b/Gems/MultiplayerCompression/Code/Source/LZ4Compressor.h index fc0c9e1089..640cf03ee4 100644 --- a/Gems/MultiplayerCompression/Code/Source/LZ4Compressor.h +++ b/Gems/MultiplayerCompression/Code/Source/LZ4Compressor.h @@ -10,6 +10,7 @@ #include #include +#include namespace MultiplayerCompression { diff --git a/Gems/SceneProcessing/Code/Source/Generation/Components/MeshOptimizer/MeshBuilderSubMesh.cpp b/Gems/SceneProcessing/Code/Source/Generation/Components/MeshOptimizer/MeshBuilderSubMesh.cpp index 170549a25d..c10a8fb2ed 100644 --- a/Gems/SceneProcessing/Code/Source/Generation/Components/MeshOptimizer/MeshBuilderSubMesh.cpp +++ b/Gems/SceneProcessing/Code/Source/Generation/Components/MeshOptimizer/MeshBuilderSubMesh.cpp @@ -7,6 +7,7 @@ */ #include +#include #include "MeshBuilder.h" #include "MeshBuilderSkinningInfo.h" #include "MeshBuilderSubMesh.h" From ac7be2fb5a69f9a2517cf7d14545951995e830e5 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Tue, 17 Aug 2021 18:29:24 -0700 Subject: [PATCH 17/54] PR observation about another race condition Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../AzCore/AzCore/Name/Internal/NameData.cpp | 5 ++++- Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp | 12 ++---------- Code/Framework/AzCore/AzCore/Name/NameDictionary.h | 2 +- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Name/Internal/NameData.cpp b/Code/Framework/AzCore/AzCore/Name/Internal/NameData.cpp index cfbd640762..0086e68c6d 100644 --- a/Code/Framework/AzCore/AzCore/Name/Internal/NameData.cpp +++ b/Code/Framework/AzCore/AzCore/Name/Internal/NameData.cpp @@ -36,10 +36,13 @@ namespace AZ void NameData::release() { + // this could be released after we decrement the counter, therefore we will + // base the release on the hash which is stable + Hash hash = m_hash; AZ_Assert(m_useCount > 0, "m_useCount is already 0!"); if (m_useCount.fetch_sub(1) == 1) { - AZ::NameDictionary::Instance().TryReleaseName(this); + AZ::NameDictionary::Instance().TryReleaseName(hash); } } } diff --git a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp index 4c4d6b31e8..6f8672bb92 100644 --- a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp +++ b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp @@ -166,7 +166,7 @@ namespace AZ } } - void NameDictionary::TryReleaseName(Internal::NameData* nameData) + void NameDictionary::TryReleaseName(Name::Hash hash) { // Note that we don't remove NameData from the dictionary if it has been involved in a collision. // This avoids specific edge cases where a Name object could get an incorrect hash value. Consider @@ -179,14 +179,6 @@ namespace AZ // the dictionary *again*, this time with hash value 1000. Name objects pointing to the original // entry and Name objects pointing to the new entry will fail comparison operations. - // Early exit to avoid locking the mutex unnecessarily. - if (nameData->m_hashCollision) - { - return; - } - - // Get the hash before locking since another thread could be deleting the object within the lock - Internal::NameData::Hash hash = nameData->GetHash(); AZStd::unique_lock lock(m_sharedMutex); @@ -202,7 +194,7 @@ namespace AZ return; } - nameData = dictIt->second; // restore the pointer in case the intrusive ptr was already assigned by other thread + Internal::NameData* nameData = dictIt->second; // restore the pointer in case the intrusive ptr was already assigned by other thread // Check m_hashCollision again inside the m_sharedMutex because a new collision could have happened // on another thread before taking the lock. diff --git a/Code/Framework/AzCore/AzCore/Name/NameDictionary.h b/Code/Framework/AzCore/AzCore/Name/NameDictionary.h index 7d4ffe80f6..fa13dbd682 100644 --- a/Code/Framework/AzCore/AzCore/Name/NameDictionary.h +++ b/Code/Framework/AzCore/AzCore/Name/NameDictionary.h @@ -83,7 +83,7 @@ namespace AZ // Attempts to release the name from the dictionary, but checks to make sure // a reference wasn't taken by another thread. - void TryReleaseName(Internal::NameData* data); + void TryReleaseName(Name::Hash hash); ////////////////////////////////////////////////////////////////////////// From dd80a3ebae87d2ffce5a077764937064f34227d2 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 18 Aug 2021 11:09:14 -0700 Subject: [PATCH 18/54] Linux and non-unity build fixes Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Debug/IEventLogger.h | 1 + .../AzCore/AzCore/IO/ByteContainerStream.h | 1 + Code/Framework/AzCore/AzCore/IO/GenericStreams.cpp | 1 + .../Android/AzCore/AzCore_Traits_Android.h | 13 +++++++++++++ .../Platform/Linux/AzCore/AzCore_Traits_Linux.h | 14 ++++++++++++++ .../AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h | 14 ++++++++++++++ .../Windows/AzCore/AzCore_Traits_Windows.h | 14 ++++++++++++++ .../AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h | 14 ++++++++++++++ Code/Framework/AzCore/Tests/AZStd/String.cpp | 4 ++-- Code/Framework/AzCore/Tests/Math/SfmtTests.cpp | 1 + Code/Legacy/CryCommon/LegacyAllocator.cpp | 6 +++--- .../Include/Atom/Feature/Utils/IndexableList.h | 1 + .../Include/Atom/RHI.Reflect/CpuTimingStatistics.h | 1 + .../MysticQt/Source/KeyboardShortcutManager.cpp | 1 + 14 files changed, 81 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Debug/IEventLogger.h b/Code/Framework/AzCore/AzCore/Debug/IEventLogger.h index a11b411ded..f5bca5fba6 100644 --- a/Code/Framework/AzCore/AzCore/Debug/IEventLogger.h +++ b/Code/Framework/AzCore/AzCore/Debug/IEventLogger.h @@ -13,6 +13,7 @@ #include #include #include +#include namespace AZ::Debug { diff --git a/Code/Framework/AzCore/AzCore/IO/ByteContainerStream.h b/Code/Framework/AzCore/AzCore/IO/ByteContainerStream.h index 17f72b9012..d198f47e00 100644 --- a/Code/Framework/AzCore/AzCore/IO/ByteContainerStream.h +++ b/Code/Framework/AzCore/AzCore/IO/ByteContainerStream.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace AZ { diff --git a/Code/Framework/AzCore/AzCore/IO/GenericStreams.cpp b/Code/Framework/AzCore/AzCore/IO/GenericStreams.cpp index b3ab808711..e7ccf4c83a 100644 --- a/Code/Framework/AzCore/AzCore/IO/GenericStreams.cpp +++ b/Code/Framework/AzCore/AzCore/IO/GenericStreams.cpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace AZ::IO { diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h b/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h index 1b67f3b720..495c8d5f2c 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h +++ b/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h @@ -109,6 +109,19 @@ #define AZ_TRAIT_USE_ERRNO_T_TYPEDEF 1 #define AZ_TRAIT_USE_POSIX_TEMP_FOLDER 0 +// wchar_t/char formatting +// Reason: https://docs.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-160 +// The Z type character, and the behavior of the c, C, s, and S type characters when they're used with the printf and wprintf functions, +// are Microsoft extensions. The ISO C standard uses c and s consistently for narrow characters and strings, and C and S for wide characters +// and strings, in all formatting functions. +#define AZ_TRAIT_FORMAT_STRING_PRINTF_CHAR "%c" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_WCHAR "%C" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_CHAR "%c" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_WCHAR "%C" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_STRING "%s" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_WSTRING "%S" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_STRING "%s" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_WSTRING "%S" // Legacy traits ... #define AZ_TRAIT_LEGACY_CRYCOMMON_USE_WINDOWS_STUBS 1 #define AZ_TRAIT_LEGACY_CRYPAK_UNIX_LIKE_FILE_SYSTEM 1 diff --git a/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h b/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h index d36be0f61a..6ba369e86d 100644 --- a/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h +++ b/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h @@ -109,6 +109,20 @@ #define AZ_TRAIT_USE_ERRNO_T_TYPEDEF 1 #define AZ_TRAIT_USE_POSIX_TEMP_FOLDER 1 +// wchar_t/char formatting +// Reason: https://docs.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-160 +// The Z type character, and the behavior of the c, C, s, and S type characters when they're used with the printf and wprintf functions, +// are Microsoft extensions. The ISO C standard uses c and s consistently for narrow characters and strings, and C and S for wide characters +// and strings, in all formatting functions. +#define AZ_TRAIT_FORMAT_STRING_PRINTF_CHAR "%c" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_WCHAR "%C" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_CHAR "%c" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_WCHAR "%C" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_STRING "%s" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_WSTRING "%S" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_STRING "%s" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_WSTRING "%S" + // Legacy traits ... #define AZ_TRAIT_LEGACY_CRYCOMMON_USE_WINDOWS_STUBS 1 #define AZ_TRAIT_LEGACY_CRYPAK_UNIX_LIKE_FILE_SYSTEM 1 diff --git a/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h b/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h index b449cac072..a41b5c6baa 100644 --- a/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h +++ b/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h @@ -109,6 +109,20 @@ #define AZ_TRAIT_USE_ERRNO_T_TYPEDEF 0 #define AZ_TRAIT_USE_POSIX_TEMP_FOLDER 1 +// wchar_t/char formatting +// Reason: https://docs.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-160 +// The Z type character, and the behavior of the c, C, s, and S type characters when they're used with the printf and wprintf functions, +// are Microsoft extensions. The ISO C standard uses c and s consistently for narrow characters and strings, and C and S for wide characters +// and strings, in all formatting functions. +#define AZ_TRAIT_FORMAT_STRING_PRINTF_CHAR "%c" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_WCHAR "%C" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_CHAR "%c" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_WCHAR "%C" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_STRING "%s" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_WSTRING "%S" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_STRING "%s" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_WSTRING "%S" + // Legacy traits ... #define AZ_TRAIT_LEGACY_CRYCOMMON_USE_WINDOWS_STUBS 1 #define AZ_TRAIT_LEGACY_CRYPAK_UNIX_LIKE_FILE_SYSTEM 1 diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h b/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h index e9a06740a0..2f9fcefdbd 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h @@ -109,6 +109,20 @@ #define AZ_TRAIT_USE_ERRNO_T_TYPEDEF 0 #define AZ_TRAIT_USE_POSIX_TEMP_FOLDER 0 +// wchar_t/char formatting +// Reason: https://docs.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-160 +// The Z type character, and the behavior of the c, C, s, and S type characters when they're used with the printf and wprintf functions, +// are Microsoft extensions. The ISO C standard uses c and s consistently for narrow characters and strings, and C and S for wide characters +// and strings, in all formatting functions. +#define AZ_TRAIT_FORMAT_STRING_PRINTF_CHAR "%c" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_WCHAR "%C" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_CHAR "%C" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_WCHAR "%c" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_STRING "%s" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_WSTRING "%S" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_STRING "%S" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_WSTRING "%s" + // Legacy traits ... #define AZ_TRAIT_LEGACY_CRYCOMMON_USE_WINDOWS_STUBS 0 #define AZ_TRAIT_LEGACY_CRYPAK_UNIX_LIKE_FILE_SYSTEM 0 diff --git a/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h b/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h index 56bc747c09..d53f4b057e 100644 --- a/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h +++ b/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h @@ -110,6 +110,20 @@ #define AZ_TRAIT_USE_ERRNO_T_TYPEDEF 0 #define AZ_TRAIT_USE_POSIX_TEMP_FOLDER 0 +// wchar_t/char formatting +// Reason: https://docs.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-160 +// The Z type character, and the behavior of the c, C, s, and S type characters when they're used with the printf and wprintf functions, +// are Microsoft extensions. The ISO C standard uses c and s consistently for narrow characters and strings, and C and S for wide characters +// and strings, in all formatting functions. +#define AZ_TRAIT_FORMAT_STRING_PRINTF_CHAR "%c" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_WCHAR "%C" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_CHAR "%c" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_WCHAR "%C" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_STRING "%s" +#define AZ_TRAIT_FORMAT_STRING_PRINTF_WSTRING "%S" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_STRING "%s" +#define AZ_TRAIT_FORMAT_STRING_WPRINTF_WSTRING "%S" + // Legacy traits ... #define AZ_TRAIT_LEGACY_CRYCOMMON_USE_WINDOWS_STUBS 1 #define AZ_TRAIT_LEGACY_CRYPAK_UNIX_LIKE_FILE_SYSTEM 1 diff --git a/Code/Framework/AzCore/Tests/AZStd/String.cpp b/Code/Framework/AzCore/Tests/AZStd/String.cpp index a88de48b9b..0ff12a352c 100644 --- a/Code/Framework/AzCore/Tests/AZStd/String.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/String.cpp @@ -1462,12 +1462,12 @@ namespace UnitTest // This shouldn't give a compile error AZStd::string::format( - "%i %c %uc %hc %lc %i %i %u %i %lu %li %llu %lli %f %f %hs %ls %p", + "%i %c %uc " AZ_TRAIT_FORMAT_STRING_PRINTF_CHAR AZ_TRAIT_FORMAT_STRING_PRINTF_WCHAR " %i %i %u %i %lu %li %llu %lli %f %f " AZ_TRAIT_FORMAT_STRING_PRINTF_STRING AZ_TRAIT_FORMAT_STRING_PRINTF_WSTRING " %p", v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18); // This shouldn't give a compile error AZStd::wstring::format( - L"%i %c %uc %hc %lc %i %i %u %i %lu %li %llu %lli %f %f %hs %ls %p", + L"%i %c %uc " AZ_TRAIT_FORMAT_STRING_WPRINTF_CHAR AZ_TRAIT_FORMAT_STRING_WPRINTF_WCHAR " %i %i %u %i %lu %li %llu %lli %f %f " AZ_TRAIT_FORMAT_STRING_WPRINTF_STRING AZ_TRAIT_FORMAT_STRING_WPRINTF_WSTRING " %p", v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18); class WrappedInt diff --git a/Code/Framework/AzCore/Tests/Math/SfmtTests.cpp b/Code/Framework/AzCore/Tests/Math/SfmtTests.cpp index 397e8bd24f..73fdd6e2fc 100644 --- a/Code/Framework/AzCore/Tests/Math/SfmtTests.cpp +++ b/Code/Framework/AzCore/Tests/Math/SfmtTests.cpp @@ -8,6 +8,7 @@ #include #include +#include using namespace AZ; diff --git a/Code/Legacy/CryCommon/LegacyAllocator.cpp b/Code/Legacy/CryCommon/LegacyAllocator.cpp index 76c4712bd3..d4f66d4c42 100644 --- a/Code/Legacy/CryCommon/LegacyAllocator.cpp +++ b/Code/Legacy/CryCommon/LegacyAllocator.cpp @@ -14,7 +14,7 @@ namespace AZ { if (alignment == 0) { - // Some STL containers, like std::vector, are assuming a specific minimum alignment. seems to have a requirement + // Some STL containers, like std::vector, seem to have a requirement where a specific minimum alignment will be chosen when the alignment is set to 0 // Take a look at _Allocate_manually_vector_aligned in xmemory0 alignment = sizeof(void*) * 2; } @@ -39,7 +39,7 @@ namespace AZ { if (newAlignment == 0) { - // Some STL containers, like std::vector, are assuming a specific minimum alignment. seems to have a requirement + // Some STL containers, like std::vector, seem to have a requirement where a specific minimum alignment will be chosen when the alignment is set to 0 // Take a look at _Allocate_manually_vector_aligned in xmemory0 newAlignment = sizeof(void*) * 2; } @@ -63,7 +63,7 @@ namespace AZ { if (newAlignment == 0) { - // Some STL containers, like std::vector, are assuming a specific minimum alignment. seems to have a requirement + // Some STL containers, like std::vector, seem to have a requirement where a specific minimum alignment will be chosen when the alignment is set to 0 // Take a look at _Allocate_manually_vector_aligned in xmemory0 newAlignment = sizeof(void*) * 2; } diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexableList.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexableList.h index fbc524314a..aae229ac9d 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexableList.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexableList.h @@ -9,6 +9,7 @@ #pragma once #include +#include namespace AZ { diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/CpuTimingStatistics.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/CpuTimingStatistics.h index 99751bbde7..2ab23def08 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/CpuTimingStatistics.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/CpuTimingStatistics.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace AZ { diff --git a/Gems/EMotionFX/Code/MysticQt/Source/KeyboardShortcutManager.cpp b/Gems/EMotionFX/Code/MysticQt/Source/KeyboardShortcutManager.cpp index 6b381bf9d8..ffedae5a99 100644 --- a/Gems/EMotionFX/Code/MysticQt/Source/KeyboardShortcutManager.cpp +++ b/Gems/EMotionFX/Code/MysticQt/Source/KeyboardShortcutManager.cpp @@ -10,6 +10,7 @@ #include "KeyboardShortcutManager.h" #include #include +#include #include #include From 716275b8da19f9617bcdee583138fe1605c06290 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Wed, 18 Aug 2021 11:41:09 -0700 Subject: [PATCH 19/54] Fix type error with Server to Authority RPC generation Signed-off-by: puvvadar --- .../Code/Source/AutoGen/AutoComponent_Source.jinja | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index 56ab828ffe..5eb0ba8ed0 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -1544,8 +1544,8 @@ namespace {{ Component.attrib['Namespace'] }} {{ DefineNetworkPropertyGets(Component, 'Authority', 'Client', true, ComponentBaseName)|indent(4) }} {{ DefineNetworkPropertyGets(Component, 'Autonomous', 'Authority', true, ComponentBaseName)|indent(4) }} {{ DefineArchetypePropertyGets(Component, ClassType, ComponentBaseName)|indent(4) -}} -{{ DefineRpcInvocations(Component, ComponentBaseName, 'Server', 'Authority', false)|indent(4) -}} -{{ DefineRpcInvocations(Component, ComponentBaseName, 'Server', 'Authority', true)|indent(4) }} +{{ DefineRpcInvocations(Component, ControllerBaseName, 'Server', 'Authority', false)|indent(4) -}} +{{ DefineRpcInvocations(Component, ControllerBaseName, 'Server', 'Authority', true)|indent(4) }} void {{ ComponentBaseName }}::SetOwningConnectionId([[maybe_unused]] AzNetworking::ConnectionId connectionId) { From 32d01f6abd9aeb8fc11bdd543a220b00a79811a5 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Wed, 18 Aug 2021 14:31:05 -0700 Subject: [PATCH 20/54] Further fixes to Server to Authority RPC generation Signed-off-by: puvvadar --- .../Code/Source/AutoGen/AutoComponent_Header.jinja | 4 +--- .../Code/Source/AutoGen/AutoComponent_Source.jinja | 8 ++++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja index 84fdc9ae54..cff4c57e98 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja @@ -132,7 +132,7 @@ void {{ PropertyName }}({{ ', '.join(paramDefines) }}); #} {% macro DeclareRpcInvocations(Component, Section, HandleOn, ProctectedSection) %} {% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, Section, HandleOn) %} -{% if Property.attrib['IsPublic']|booleanTrue == ProctectedSection %} +{% if Property.attrib['IsPublic']|booleanTrue != ProctectedSection %} {{ DeclareRpcInvocation(Property, HandleOn) -}} {% endif %} {% endcall %} @@ -386,8 +386,6 @@ namespace {{ Component.attrib['Namespace'] }} {{ DeclareNetworkPropertyAccessors(Component, 'Autonomous', 'Authority', false)|indent(8) -}} {{ DeclareNetworkPropertyAccessors(Component, 'Autonomous', 'Authority', true)|indent(8) -}} {{ DeclareArchetypePropertyGetters(Component)|indent(8) -}} - {{ DeclareRpcInvocations(Component, 'Server', 'Authority', false)|indent(8) -}} - {{ DeclareRpcInvocations(Component, 'Server', 'Authority', true)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Client', 'Authority', false)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Client', 'Authority', true)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Autonomous', 'Authority', false)|indent(8) -}} diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index 5eb0ba8ed0..e56c54455c 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -318,7 +318,11 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(par constexpr AzNetworking::ReliabilityType isReliable = Multiplayer::ReliabilityType::Unreliable; {% endif %} +{% if InvokeFrom == 'Server' and HandleOn == 'Authority' %} + const Multiplayer::NetComponentId netComponentId = GetNetComponentId(); +{% else %} const Multiplayer::NetComponentId netComponentId = GetParent().GetNetComponentId(); +{% endif %} Multiplayer::NetworkEntityRpcMessage rpcMessage(Multiplayer::RpcDeliveryType::{{ InvokeFrom }}To{{ HandleOn }}, GetNetEntityId(), netComponentId, rpcId, isReliable); {% if paramNames|count > 0 %} {{ UpperFirst(Component.attrib['Name']) }}Internal::{{ UpperFirst(Property.attrib['Name']) }}RpcStruct rpcStruct({{ ', '.join(paramNames) }}); @@ -1544,8 +1548,8 @@ namespace {{ Component.attrib['Namespace'] }} {{ DefineNetworkPropertyGets(Component, 'Authority', 'Client', true, ComponentBaseName)|indent(4) }} {{ DefineNetworkPropertyGets(Component, 'Autonomous', 'Authority', true, ComponentBaseName)|indent(4) }} {{ DefineArchetypePropertyGets(Component, ClassType, ComponentBaseName)|indent(4) -}} -{{ DefineRpcInvocations(Component, ControllerBaseName, 'Server', 'Authority', false)|indent(4) -}} -{{ DefineRpcInvocations(Component, ControllerBaseName, 'Server', 'Authority', true)|indent(4) }} +{{ DefineRpcInvocations(Component, ComponentBaseName, 'Server', 'Authority', false)|indent(4) -}} +{{ DefineRpcInvocations(Component, ComponentBaseName, 'Server', 'Authority', true)|indent(4) }} void {{ ComponentBaseName }}::SetOwningConnectionId([[maybe_unused]] AzNetworking::ConnectionId connectionId) { From 4b3ce6738fab46fd3134b7a9b3a1b5f967dc7a84 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 18 Aug 2021 17:41:15 -0500 Subject: [PATCH 21/54] AtomTools: fix multiple material editor processes launching Atom tools launch or check for the existence of a local server in order to prevent multiple application processes from running. These checks were being done far too late, after initialization and asset processing, leaving time for multiple processes to start before the server or checks. Zombie processes could start and run indefinitely without user interaction because the event loop was being entered despite the request to exit the application early. These changes launch the server and checks immediately after the application object is constructed and exit before any other work is done if the application will not be run. Signed-off-by: Guthrie Adams --- .../Application/AtomToolsApplication.h | 4 +- .../Application/AtomToolsApplication.cpp | 81 +++++++------------ .../Tools/MaterialEditor/Code/Source/main.cpp | 7 +- .../Code/Source/main.cpp | 11 ++- 4 files changed, 43 insertions(+), 60 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h index 3639606f03..6421c877b0 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h @@ -46,6 +46,8 @@ namespace AtomToolsFramework AtomToolsApplication(int* argc, char*** argv); ~AtomToolsApplication(); + virtual bool LaunchLocalServer(); + ////////////////////////////////////////////////////////////////////////// // AzFramework::Application void CreateReflectionManager() override; @@ -106,8 +108,6 @@ namespace AtomToolsFramework virtual void UnloadSettings(); virtual void CompileCriticalAssets(); virtual void ProcessCommandLine(const AZ::CommandLine& commandLine); - virtual bool LaunchDiscoveryService(); - virtual void StartInternal(); static void PyIdleWaitFrames(uint32_t frames); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp index efd3fec0e8..4cc98a15aa 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp @@ -152,7 +152,33 @@ namespace AtomToolsFramework Base::StartCommon(systemEntity); - StartInternal(); + m_traceLogger.PrepareLogFile(GetBuildTargetName() + ".log"); + + AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusConnect(); + AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast( + &AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized); + + AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@assets@/assetcatalog.xml"); + + AZ::RPI::RPISystemInterface::Get()->InitializeSystemAssets(); + + LoadSettings(); + + AtomToolsMainWindowNotificationBus::Handler::BusConnect(); + + AtomToolsMainWindowFactoryRequestBus::Broadcast(&AtomToolsMainWindowFactoryRequestBus::Handler::CreateMainWindow); + + auto editorPythonEventsInterface = AZ::Interface::Get(); + if (editorPythonEventsInterface) + { + // The PythonSystemComponent does not call StartPython to allow for lazy python initialization, so start it here + // The PythonSystemComponent will call StopPython when it deactivates, so we do not need our own corresponding call to + // StopPython + editorPythonEventsInterface->StartPython(); + } + + // Delay execution of commands and scripts post initialization + QTimer::singleShot(0, [this]() { ProcessCommandLine(m_commandLine); }); m_timer.start(); } @@ -334,7 +360,7 @@ namespace AtomToolsFramework } } - bool AtomToolsApplication::LaunchDiscoveryService() + bool AtomToolsApplication::LaunchLocalServer() { // Determine if this is the first launch of the tool by attempting to connect to a running server if (m_socket.Connect(QApplication::applicationName())) @@ -376,7 +402,7 @@ namespace AtomToolsFramework { AZ::CommandLine commandLine; commandLine.Parse(tokens); - ProcessCommandLine(commandLine); + QTimer::singleShot(0, [this, commandLine]() { ProcessCommandLine(commandLine); }); } } }); @@ -390,55 +416,6 @@ namespace AtomToolsFramework return true; } - void AtomToolsApplication::StartInternal() - { - if (WasExitMainLoopRequested()) - { - return; - } - - AZStd::string fileName = GetBuildTargetName() + ".log"; - - m_traceLogger.PrepareLogFile(fileName.c_str()); - - if (!LaunchDiscoveryService()) - { - ExitMainLoop(); - return; - } - - AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusConnect(); - AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast( - &AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized); - - AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@assets@/assetcatalog.xml"); - - AZ::RPI::RPISystemInterface::Get()->InitializeSystemAssets(); - - LoadSettings(); - - AtomToolsMainWindowNotificationBus::Handler::BusConnect(); - - AtomToolsMainWindowFactoryRequestBus::Broadcast(&AtomToolsMainWindowFactoryRequestBus::Handler::CreateMainWindow); - - auto editorPythonEventsInterface = AZ::Interface::Get(); - if (editorPythonEventsInterface) - { - // The PythonSystemComponent does not call StartPython to allow for lazy python initialization, so start it here - // The PythonSystemComponent will call StopPython when it deactivates, so we do not need our own corresponding call to - // StopPython - editorPythonEventsInterface->StartPython(); - } - - // Delay execution of commands and scripts post initialization - QTimer::singleShot( - 0, - [this]() - { - ProcessCommandLine(m_commandLine); - }); - } - bool AtomToolsApplication::GetAssetDatabaseLocation(AZStd::string& result) { AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp index 47432ed83c..de29c27b71 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp @@ -28,9 +28,12 @@ int main(int argc, char** argv) AzQtComponents::AzQtApplication::InitializeDpiScaling(); MaterialEditor::MaterialEditorApplication app(&argc, &argv); + if (!app.LaunchLocalServer()) + { + return 0; + } - auto globalEventFilter = new AzQtComponents::GlobalEventFilter(&app); - app.installEventFilter(globalEventFilter); + app.installEventFilter(new AzQtComponents::GlobalEventFilter(&app)); AZ::IO::FixedMaxPath engineRootPath; if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp index d6f017eee8..cf3f25cf6c 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp @@ -28,6 +28,12 @@ int main(int argc, char** argv) AzQtComponents::AzQtApplication::InitializeDpiScaling(); ShaderManagementConsole::ShaderManagementConsoleApplication app(&argc, &argv); + if (!app.LaunchLocalServer()) + { + return 0; + } + + app.installEventFilter(new AzQtComponents::GlobalEventFilter(&app)); AZ::IO::FixedMaxPath engineRootPath; if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) @@ -35,13 +41,10 @@ int main(int argc, char** argv) settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); } - auto globalEventFilter = new AzQtComponents::GlobalEventFilter(&app); - app.installEventFilter(globalEventFilter); - AzQtComponents::StyleManager styleManager(&app); styleManager.initialize(&app, engineRootPath); - app.Start({}); + app.Start(AZ::ComponentApplication::Descriptor{}); app.exec(); app.Stop(); return 0; From cb7108e336d53449ccf87a759f80f6520b4a0ca5 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 18 Aug 2021 17:51:43 -0700 Subject: [PATCH 22/54] Addresses comments around AZ_TRAIT_UNIT_TEST_NAME_COUNT from PR Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp | 4 ++-- Code/Framework/AzCore/Tests/Name/NameTests.cpp | 12 ++++-------- .../AzTest/Platform/Android/AzTest_Traits_Android.h | 1 - .../AzTest/Platform/Linux/AzTest_Traits_Linux.h | 1 - .../AzTest/AzTest/Platform/Mac/AzTest_Traits_Mac.h | 1 - .../AzTest/Platform/Windows/AzTest_Traits_Windows.h | 1 - .../AzTest/AzTest/Platform/iOS/AzTest_Traits_iOS.h | 1 - 7 files changed, 6 insertions(+), 15 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp index 6f8672bb92..cf85e0f4e0 100644 --- a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp +++ b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp @@ -194,9 +194,9 @@ namespace AZ return; } - Internal::NameData* nameData = dictIt->second; // restore the pointer in case the intrusive ptr was already assigned by other thread + Internal::NameData* nameData = dictIt->second; - // Check m_hashCollision again inside the m_sharedMutex because a new collision could have happened + // Check m_hashCollision inside the m_sharedMutex because a new collision could have happened // on another thread before taking the lock. if (nameData->m_hashCollision) { diff --git a/Code/Framework/AzCore/Tests/Name/NameTests.cpp b/Code/Framework/AzCore/Tests/Name/NameTests.cpp index c0dc37715f..3db77ac4c4 100644 --- a/Code/Framework/AzCore/Tests/Name/NameTests.cpp +++ b/Code/Framework/AzCore/Tests/Name/NameTests.cpp @@ -604,9 +604,7 @@ namespace UnitTest AZ::NameDictionary::Create(); // 3 threads per name effectively makes two readers and one writer (the first to run will write in the dictionary) - // Using AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2 since the following line generates 3000 threads and that triggers ASan failures, - // likely because of https://devblogs.microsoft.com/oldnewthing/20050729-14/?p=34773 - RunConcurrencyTest(AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2, 3); + RunConcurrencyTest(AZStd::thread::hardware_concurrency(), 3); } TEST_F(NameTest, ConcurrencyDataTest_EachThreadCreatesOneName_HighCollisions) @@ -616,9 +614,7 @@ namespace UnitTest AZ::NameDictionary::Create(); // 3 threads per name effectively makes two readers and one writer (the first to run will write in the dictionary) - // Using AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2 since the following line generates 3000 threads and that triggers ASan failures, - // likely because of https://devblogs.microsoft.com/oldnewthing/20050729-14/?p=34773 - RunConcurrencyTest(AZ_TRAIT_UNIT_TEST_NAME_COUNT / 2, 3); + RunConcurrencyTest(AZStd::thread::hardware_concurrency() / 2, 3); } TEST_F(NameTest, ConcurrencyDataTest_EachThreadRepeatedlyCreatesAndReleasesOneName_NoCollision) @@ -645,7 +641,7 @@ namespace UnitTest TEST_F(NameTest, DISABLED_NameVsStringPerf_Creation) { - constexpr int CreateCount = AZ_TRAIT_UNIT_TEST_NAME_COUNT; + constexpr int CreateCount = 1000; char buffer[RandomStringBufferSize]; @@ -654,7 +650,7 @@ namespace UnitTest AZStd::sys_time_t stringTime; { - const size_t dictionaryNoiseSize = AZ_TRAIT_UNIT_TEST_NAME_COUNT; + const size_t dictionaryNoiseSize = 1000; AZStd::vector existingNames; existingNames.reserve(dictionaryNoiseSize); diff --git a/Code/Framework/AzTest/AzTest/Platform/Android/AzTest_Traits_Android.h b/Code/Framework/AzTest/AzTest/Platform/Android/AzTest_Traits_Android.h index b210fb9b62..a8b4b3cc8c 100644 --- a/Code/Framework/AzTest/AzTest/Platform/Android/AzTest_Traits_Android.h +++ b/Code/Framework/AzTest/AzTest/Platform/Android/AzTest_Traits_Android.h @@ -12,7 +12,6 @@ #define AZ_TRAIT_UNIT_TEST_ASSET_MANAGER_TEST_DEFAULT_TIMEOUT_SECS 5 #define AZ_TRAIT_UNIT_TEST_ENTITY_ID_GEN_TEST_COUNT 10000 #define AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT 100000 -#define AZ_TRAIT_UNIT_TEST_NAME_COUNT 1000 #define AZ_TRAIT_TEST_APPEND_ROOT_FOLDER_TO_PATH true diff --git a/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h b/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h index 8b8d87a5b9..d9b48b7835 100644 --- a/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h +++ b/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h @@ -12,7 +12,6 @@ #define AZ_TRAIT_UNIT_TEST_ASSET_MANAGER_TEST_DEFAULT_TIMEOUT_SECS 5 #define AZ_TRAIT_UNIT_TEST_ENTITY_ID_GEN_TEST_COUNT 10000 #define AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT 100000 -#define AZ_TRAIT_UNIT_TEST_NAME_COUNT 1000 #define AZ_TRAIT_DISABLE_ALL_SAVE_DATA_TESTS true diff --git a/Code/Framework/AzTest/AzTest/Platform/Mac/AzTest_Traits_Mac.h b/Code/Framework/AzTest/AzTest/Platform/Mac/AzTest_Traits_Mac.h index a43c62ac98..69dd592a2b 100644 --- a/Code/Framework/AzTest/AzTest/Platform/Mac/AzTest_Traits_Mac.h +++ b/Code/Framework/AzTest/AzTest/Platform/Mac/AzTest_Traits_Mac.h @@ -12,7 +12,6 @@ #define AZ_TRAIT_UNIT_TEST_ASSET_MANAGER_TEST_DEFAULT_TIMEOUT_SECS 5 #define AZ_TRAIT_UNIT_TEST_ENTITY_ID_GEN_TEST_COUNT 10000 #define AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT 100000 -#define AZ_TRAIT_UNIT_TEST_NAME_COUNT 1000 #define AZ_TRAIT_DISABLE_ASSET_JOB_PARALLEL_TESTS true #define AZ_TRAIT_DISABLE_ASSET_MANAGER_FLOOD_TEST true diff --git a/Code/Framework/AzTest/AzTest/Platform/Windows/AzTest_Traits_Windows.h b/Code/Framework/AzTest/AzTest/Platform/Windows/AzTest_Traits_Windows.h index 3721d8891a..a11b8586f4 100644 --- a/Code/Framework/AzTest/AzTest/Platform/Windows/AzTest_Traits_Windows.h +++ b/Code/Framework/AzTest/AzTest/Platform/Windows/AzTest_Traits_Windows.h @@ -13,4 +13,3 @@ #define AZ_TRAIT_UNIT_TEST_ASSET_MANAGER_TEST_DEFAULT_TIMEOUT_SECS 5 #define AZ_TRAIT_UNIT_TEST_ENTITY_ID_GEN_TEST_COUNT 10000 #define AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT 100000 -#define AZ_TRAIT_UNIT_TEST_NAME_COUNT 1000 diff --git a/Code/Framework/AzTest/AzTest/Platform/iOS/AzTest_Traits_iOS.h b/Code/Framework/AzTest/AzTest/Platform/iOS/AzTest_Traits_iOS.h index a43c62ac98..69dd592a2b 100644 --- a/Code/Framework/AzTest/AzTest/Platform/iOS/AzTest_Traits_iOS.h +++ b/Code/Framework/AzTest/AzTest/Platform/iOS/AzTest_Traits_iOS.h @@ -12,7 +12,6 @@ #define AZ_TRAIT_UNIT_TEST_ASSET_MANAGER_TEST_DEFAULT_TIMEOUT_SECS 5 #define AZ_TRAIT_UNIT_TEST_ENTITY_ID_GEN_TEST_COUNT 10000 #define AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT 100000 -#define AZ_TRAIT_UNIT_TEST_NAME_COUNT 1000 #define AZ_TRAIT_DISABLE_ASSET_JOB_PARALLEL_TESTS true #define AZ_TRAIT_DISABLE_ASSET_MANAGER_FLOOD_TEST true From 92a46c705edf35d84b5b95d61295080970e5ce2d Mon Sep 17 00:00:00 2001 From: pereslav Date: Thu, 19 Aug 2021 16:57:32 +0100 Subject: [PATCH 23/54] Added the ability to look up a Net Entity ID for a given AZ Entity ID Signed-off-by: pereslav --- .../NetworkEntity/INetworkEntityManager.h | 5 ++++ .../NetworkEntity/NetworkEntityManager.cpp | 5 ++++ .../NetworkEntity/NetworkEntityManager.h | 1 + .../NetworkEntity/NetworkEntityTracker.cpp | 23 ++++++++++++++++++- .../NetworkEntity/NetworkEntityTracker.h | 4 ++++ .../NetworkEntity/NetworkEntityTracker.inl | 1 + 6 files changed, 38 insertions(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h index 1c8894d6c2..991aef4d38 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h @@ -89,6 +89,11 @@ namespace Multiplayer //! @return the total number of entities tracked by this INetworkEntityManager instance virtual uint32_t GetEntityCount() const = 0; + //! Returns the Net Entity ID for a given AZ Entity ID. + //! @param entityId the AZ Entity ID + //! @return the Net Entity ID + virtual NetEntityId GetNetEntityIdById(const AZ::EntityId& entityId) const = 0; + //! Adds the provided entity to the internal entity map identified by the provided netEntityId. //! @param netEntityId the identifier to use for the added entity //! @param entity the entity to add to the internal entity map diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp index cff05b9151..05373bbeee 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp @@ -73,6 +73,11 @@ namespace Multiplayer return m_networkEntityTracker.Get(netEntityId); } + NetEntityId NetworkEntityManager::GetNetEntityIdById(const AZ::EntityId& entityId) const + { + return m_networkEntityTracker.Get(entityId); + } + uint32_t NetworkEntityManager::GetEntityCount() const { return static_cast(m_networkEntityTracker.size()); diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h index fdd0201b7a..97db532916 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h @@ -41,6 +41,7 @@ namespace Multiplayer MultiplayerComponentRegistry* GetMultiplayerComponentRegistry() override; HostId GetHostId() const override; ConstNetworkEntityHandle GetEntity(NetEntityId netEntityId) const override; + NetEntityId GetNetEntityIdById(const AZ::EntityId& entityId) const override; EntityList CreateEntitiesImmediate(const AzFramework::Spawnable& spawnable, NetEntityRole netEntityRole); EntityList CreateEntitiesImmediate diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp index a70dd74bf9..e31907461b 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp @@ -18,6 +18,7 @@ namespace Multiplayer ++m_addChangeDirty; AZ_Assert(m_entityMap.end() == m_entityMap.find(netEntityId), "Attempting to add the same entity to the entity map multiple times"); m_entityMap[netEntityId] = entity; + m_netEntityIdMap[entity->GetId()] = netEntityId; } NetworkEntityHandle NetworkEntityTracker::Get(NetEntityId netEntityId) @@ -32,6 +33,16 @@ namespace Multiplayer return ConstNetworkEntityHandle(entity, netEntityId, this); } + NetEntityId NetworkEntityTracker::Get(const AZ::EntityId& entityId) const + { + auto found = m_netEntityIdMap.find(entityId); + if (found != m_netEntityIdMap.end()) + { + return found->second; + } + return Multiplayer::InvalidNetEntityId; + } + bool NetworkEntityTracker::Exists(NetEntityId netEntityId) const { return (m_entityMap.find(netEntityId) != m_entityMap.end()); @@ -50,12 +61,22 @@ namespace Multiplayer void NetworkEntityTracker::erase(NetEntityId netEntityId) { ++m_deleteChangeDirty; - m_entityMap.erase(netEntityId); + + auto found = m_entityMap.find(netEntityId); + if (found != m_entityMap.end()) + { + m_netEntityIdMap.erase(found->second->GetId()); + m_entityMap.erase(found); + } } NetworkEntityTracker::EntityMap::iterator NetworkEntityTracker::erase(EntityMap::iterator iter) { ++m_deleteChangeDirty; + if (iter != m_entityMap.end()) + { + m_netEntityIdMap.erase(iter->second->GetId()); + } return m_entityMap.erase(iter); } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h index 7ff2d1da24..09238acaee 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h @@ -22,6 +22,7 @@ namespace Multiplayer public: using EntityMap = AZStd::unordered_map; + using NetEntityIdMap = AZStd::unordered_map; using iterator = EntityMap::iterator; using const_iterator = EntityMap::const_iterator; @@ -36,6 +37,8 @@ namespace Multiplayer NetworkEntityHandle Get(NetEntityId netEntityId); ConstNetworkEntityHandle Get(NetEntityId netEntityId) const; + NetEntityId Get(const AZ::EntityId& entityId) const; + //! Returns true if the netEntityId exists. bool Exists(NetEntityId netEntityId) const; @@ -74,6 +77,7 @@ namespace Multiplayer private: EntityMap m_entityMap; + NetEntityIdMap m_netEntityIdMap; uint32_t m_deleteChangeDirty = 0; uint32_t m_addChangeDirty = 0; }; diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.inl b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.inl index c22fbb0da2..44098336be 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.inl +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.inl @@ -48,6 +48,7 @@ namespace Multiplayer inline void NetworkEntityTracker::clear() { m_entityMap.clear(); + m_netEntityIdMap.clear(); } inline uint32_t NetworkEntityTracker::GetChangeDirty(const AZ::Entity* entity) const From dcde3f3e36800fcc73909ab753ad4c6163d04bac Mon Sep 17 00:00:00 2001 From: John Date: Thu, 19 Aug 2021 18:18:45 +0100 Subject: [PATCH 24/54] Add extra logging for CHANGE_ID and COMMIT_ID. Signed-off-by: John --- scripts/build/Jenkins/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index e45b7075f0..3d8c32f0f3 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -619,7 +619,7 @@ try { } pipelineProperties.add(disableConcurrentBuilds()) - echo "Running repository: \"${repositoryName}\", pipeline: \"${pipelineName}\", branch: \"${branchName}\"..." + echo "Running repository: \"${repositoryName}\", pipeline: \"${pipelineName}\", branch: \"${branchName}\", CHANGE_ID: \"${env.CHANGE_ID}\", GIT_COMMMIT: \"${scm.GIT_COMMIT}\"..." CheckoutBootstrapScripts(branchName) From 1861cf48527f56f9aaf4a61beaaffab5be8522d8 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Thu, 19 Aug 2021 13:11:34 -0500 Subject: [PATCH 25/54] Allow Tag components to be added to UI elements. Signed-off-by: Chris Galvan --- Gems/LmbrCentral/Code/Source/Scripting/EditorTagComponent.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/LmbrCentral/Code/Source/Scripting/EditorTagComponent.cpp b/Gems/LmbrCentral/Code/Source/Scripting/EditorTagComponent.cpp index 251f0203b4..fa98601a11 100644 --- a/Gems/LmbrCentral/Code/Source/Scripting/EditorTagComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Scripting/EditorTagComponent.cpp @@ -33,6 +33,7 @@ namespace LmbrCentral editContext->Class("Tag", "The Tag component allows you to apply one or more labels to an entity") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("UI", 0x27ff46b0)) ->Attribute(AZ::Edit::Attributes::Category, "Gameplay") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Tag.svg") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Tag.svg") From 24a83087114af6a8c4c585de6cb6a2009d0335de Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Thu, 19 Aug 2021 13:44:12 -0500 Subject: [PATCH 26/54] Include the category name when performing search in the component palette. Signed-off-by: Chris Galvan --- .../UI/ComponentPalette/ComponentPaletteWidget.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteWidget.cpp index 67598f9fca..3218bd402b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteWidget.cpp @@ -204,12 +204,11 @@ namespace AzToolsFramework } } - for (const auto& categoryPair : componentDataTable) + for (const auto& [categoryName, componentMap] : componentDataTable) { - auto categoryItemItr = categoryItemMap.find(categoryPair.first + "/"); + auto categoryItemItr = categoryItemMap.find(categoryName + "/"); auto parentItem = categoryItemItr != categoryItemMap.end() ? categoryItemItr->second : m_componentModel->invisibleRootItem(); - const auto& componentMap = categoryPair.second; for (const auto& componentPair : componentMap) { auto componentClass = componentPair.second; @@ -217,7 +216,8 @@ namespace AzToolsFramework const QString& componentIconName = componentIconTable[componentClass]; auto deprecatedInfo = deprecatedList.find(componentClass->m_typeId); bool componentIsDeprecated = deprecatedInfo != deprecatedList.end(); - if ((!applyRegExFilter || componentName.contains(m_searchRegExp)) && (!componentIsDeprecated || !deprecatedInfo->second.m_hideComponent)) + if ((!applyRegExFilter || categoryName.contains(m_searchRegExp) || componentName.contains(m_searchRegExp)) + && (!componentIsDeprecated || !deprecatedInfo->second.m_hideComponent)) { //count the number of components on selected entities that match this type auto componentCount = AZStd::count_if(allComponentsOnSelectedEntities.begin(), allComponentsOnSelectedEntities.end(), [componentClass](const AZ::Component* component) { From bef2e1400cf5d9bf7769721cb5388ab1ca421f55 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Thu, 19 Aug 2021 13:39:08 -0700 Subject: [PATCH 27/54] Add check for Client invocation in jinja Signed-off-by: puvvadar --- Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index e56c54455c..8010d1bfc2 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -318,7 +318,7 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(par constexpr AzNetworking::ReliabilityType isReliable = Multiplayer::ReliabilityType::Unreliable; {% endif %} -{% if InvokeFrom == 'Server' and HandleOn == 'Authority' %} +{% if (InvokeFrom == 'Server' or InvokeFrom =="Client") and HandleOn == 'Authority' %} const Multiplayer::NetComponentId netComponentId = GetNetComponentId(); {% else %} const Multiplayer::NetComponentId netComponentId = GetParent().GetNetComponentId(); From f7831be7ce5005f375b360eaecebec0999449d77 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 19 Aug 2021 15:55:22 -0500 Subject: [PATCH 28/54] Adding missing AssetManager_private.h header to cmake (#3030) Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/azcore_files.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index d106b5b12f..1ea86c7b93 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -25,6 +25,7 @@ set(FILES Asset/AssetJsonSerializer.h Asset/AssetManager.cpp Asset/AssetManager.h + Asset/AssetManager_private.h Asset/AssetManagerBus.h Asset/AssetManagerComponent.cpp Asset/AssetManagerComponent.h From c93a18ab82817aa036bfb01403e852b3bd088b5d Mon Sep 17 00:00:00 2001 From: Junbo Liang <68558268+junbo75@users.noreply.github.com> Date: Thu, 19 Aug 2021 14:05:25 -0700 Subject: [PATCH 29/54] Update the AWS automation tests to use existing CloudFormation stacks (#3092) --- .../Gem/PythonTests/AWS/README.md | 26 ++ .../aws_metrics_automation_test.py | 106 ++++---- .../Windows/aws_metrics/aws_metrics_utils.py | 27 +- .../aws_metrics/aws_metrics_waiters.py | 5 +- .../PythonTests/AWS/Windows/cdk/__init__.py | 7 - .../PythonTests/AWS/Windows/cdk/cdk_utils.py | 248 ------------------ .../aws_client_auth_automation_test.py | 61 +++-- .../core/test_aws_resource_interaction.py | 32 ++- .../AWS/Windows/resource_mappings/__init__.py | 6 - .../Gem/PythonTests/AWS/common/constants.py | 19 ++ .../resource_mappings.py | 14 +- .../Gem/PythonTests/AWS/conftest.py | 59 +---- Gems/AWSCore/cdk/app.py | 2 +- .../cdk/aws_metrics/batch_analytics.py | 8 +- .../cdk/aws_metrics/data_lake_integration.py | 10 +- .../aws_metrics/real_time_data_processing.py | 2 +- scripts/build/Platform/Windows/pipeline.json | 8 +- 17 files changed, 195 insertions(+), 445 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/AWS/README.md delete mode 100644 AutomatedTesting/Gem/PythonTests/AWS/Windows/cdk/__init__.py delete mode 100644 AutomatedTesting/Gem/PythonTests/AWS/Windows/cdk/cdk_utils.py delete mode 100644 AutomatedTesting/Gem/PythonTests/AWS/Windows/resource_mappings/__init__.py create mode 100644 AutomatedTesting/Gem/PythonTests/AWS/common/constants.py rename AutomatedTesting/Gem/PythonTests/AWS/{Windows/resource_mappings => common}/resource_mappings.py (90%) diff --git a/AutomatedTesting/Gem/PythonTests/AWS/README.md b/AutomatedTesting/Gem/PythonTests/AWS/README.md new file mode 100644 index 0000000000..8b5e65d6d7 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/AWS/README.md @@ -0,0 +1,26 @@ +# AWS Gem Automation Tests + +## Prerequisites +1. Build the O3DE Editor and AutomatedTesting.GameLauncher in Profile. +2. AWS CLI is installed and configured following [Configuration and Credential File Settings](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html). +3. [AWS Cloud Development Kit (CDK)](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html#getting_started_install) is installed. + +## Deploy CDK Applications +1. Go to the AWS IAM console and create an IAM role called o3de-automation-tests which adds your own account as as a trusted entity and uses the "AdministratorAccess" permissions policy. +2. Copy {engine_root}\scripts\build\Platform\Windows\deploy_cdk_applications.cmd to your engine root folder. +3. Open a Command Prompt window at the engine root and set the following environment variables: + Set O3DE_AWS_PROJECT_NAME=AWSAUTO + Set O3DE_AWS_DEPLOY_REGION=us-east-1 + Set ASSUME_ROLE_ARN="arn:aws:iam::{your_aws_account_id}:role/o3de-automation-tests" + Set COMMIT_ID=HEAD +4. Deploy the CDK applications for AWS gems by running deploy_cdk_applications.cmd in the same Command Prompt window. +5. Edit AWS\common\constants.py to replace the assume role ARN with your own: + arn:aws:iam::{your_aws_account_id}:role/o3de-automation-tests + +## Run Automation Tests +### CLI +Open a Command Prompt window at the engine root and run the following CLI command: +python\python.cmd -m pytest {path_to_the_test_file} --build-directory {directory_to_the_profile_build} + +### Pycharm +You can also run any specific automation test directly from Pycharm by providing the "--build-directory" argument in the Run Configuration. \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py index cd8858e7f2..061db991cf 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py @@ -9,18 +9,18 @@ import logging import os import pytest import typing - from datetime import datetime + import ly_test_tools.log.log_monitor +from AWS.common import constants +from .aws_metrics_custom_thread import AWSMetricsThread + # fixture imports from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor from .aws_metrics_utils import aws_metrics_utils -from .aws_metrics_custom_thread import AWSMetricsThread AWS_METRICS_FEATURE_NAME = 'AWSMetrics' -GAME_LOG_NAME = 'Game.log' -CONTEXT_VARIABLE = ['-c', 'batch_processing=true'] logger = logging.getLogger(__name__) @@ -36,7 +36,7 @@ def setup(launcher: pytest.fixture, asset_processor.start() asset_processor.wait_for_idle() - file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), GAME_LOG_NAME) + file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), constants.GAME_LOG_NAME) # Initialize the log monitor. log_monitor = ly_test_tools.log.log_monitor.LogMonitor(launcher=launcher, log_file_path=file_to_monitor) @@ -73,23 +73,26 @@ def monitor_metrics_submission(log_monitor: pytest.fixture) -> None: f'unexpected_lines values: {unexpected_lines}') -def query_metrics_from_s3(aws_metrics_utils: pytest.fixture, stack_name: str) -> None: +def query_metrics_from_s3(aws_metrics_utils: pytest.fixture, resource_mappings: pytest.fixture, stack_name: str) -> None: """ Verify that the metrics events are delivered to the S3 bucket and can be queried. - aws_metrics_utils: aws_metrics_utils fixture. - stack_name: name of the CloudFormation stack. + :param aws_metrics_utils: aws_metrics_utils fixture. + :param resource_mappings: resource_mappings fixture. + :param stack_name: name of the CloudFormation stack. """ - analytics_bucket_name = aws_metrics_utils.get_analytics_bucket_name(stack_name) - aws_metrics_utils.verify_s3_delivery(analytics_bucket_name) + aws_metrics_utils.verify_s3_delivery( + resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsBucketName') + ) logger.info('Metrics are sent to S3.') - aws_metrics_utils.run_glue_crawler(f'{stack_name}-EventsCrawler') + aws_metrics_utils.run_glue_crawler( + resource_mappings.get_resource_name_id('AWSMetrics.EventsCrawlerName')) + + # Remove the events_json table if exists so that the sample query can create a table with the same name. + aws_metrics_utils.delete_table(f'{stack_name}-eventsdatabase', 'events_json') aws_metrics_utils.run_named_queries(f'{stack_name}-AthenaWorkGroup') logger.info('Query metrics from S3 successfully.') - # Empty the S3 bucket. S3 buckets can only be deleted successfully when it doesn't contain any object. - aws_metrics_utils.empty_batch_analytics_bucket(analytics_bucket_name) - def verify_operational_metrics(aws_metrics_utils: pytest.fixture, stack_name: str, start_time: datetime) -> None: """ @@ -102,7 +105,7 @@ def verify_operational_metrics(aws_metrics_utils: pytest.fixture, stack_name: st 'AWS/Lambda', 'Invocations', [{'Name': 'FunctionName', - 'Value': f'{stack_name}-AnalyticsProcessingLambdaName'}], + 'Value': f'{stack_name}-AnalyticsProcessingLambda'}], start_time) logger.info('AnalyticsProcessingLambda metrics are sent to CloudWatch.') @@ -115,50 +118,59 @@ def verify_operational_metrics(aws_metrics_utils: pytest.fixture, stack_name: st logger.info('EventsProcessingLambda metrics are sent to CloudWatch.') -def start_kinesis_analytics_application(aws_metrics_utils: pytest.fixture, stack_name: str) -> None: +def update_kinesis_analytics_application_status(aws_metrics_utils: pytest.fixture, + resource_mappings: pytest.fixture, start_application: bool) -> None: """ - Start the Kinesis analytics application for real-time analytics. - aws_metrics_utils: aws_metrics_utils fixture. - stack_name: name of the CloudFormation stack. + Update the Kinesis analytics application to start or stop it. + :param aws_metrics_utils: aws_metrics_utils fixture. + :param resource_mappings: resource_mappings fixture. + :param start_application: whether to start or stop the application. """ - analytics_application_name = f'{stack_name}-AnalyticsApplication' - aws_metrics_utils.start_kinesis_data_analytics_application(analytics_application_name) + if start_application: + aws_metrics_utils.start_kinesis_data_analytics_application( + resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsApplicationName')) + else: + aws_metrics_utils.stop_kinesis_data_analytics_application( + resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsApplicationName')) @pytest.mark.SUITE_periodic @pytest.mark.usefixtures('automatic_process_killer') -@pytest.mark.parametrize('project', ['AutomatedTesting']) -@pytest.mark.parametrize('level', ['AWS/Metrics']) -@pytest.mark.parametrize('feature_name', [AWS_METRICS_FEATURE_NAME]) -@pytest.mark.usefixtures('resource_mappings') -@pytest.mark.parametrize('resource_mappings_filename', ['default_aws_resource_mappings.json']) @pytest.mark.usefixtures('aws_credentials') +@pytest.mark.usefixtures('resource_mappings') +@pytest.mark.parametrize('assume_role_arn', [constants.ASSUME_ROLE_ARN]) +@pytest.mark.parametrize('feature_name', [AWS_METRICS_FEATURE_NAME]) +@pytest.mark.parametrize('level', ['AWS/Metrics']) @pytest.mark.parametrize('profile_name', ['AWSAutomationTest']) -@pytest.mark.parametrize('region_name', ['us-west-2']) -@pytest.mark.parametrize('assume_role_arn', ['arn:aws:iam::645075835648:role/o3de-automation-tests']) -@pytest.mark.usefixtures('cdk') -@pytest.mark.parametrize('session_name', ['o3de-Automation-session']) -@pytest.mark.parametrize('deployment_params', [CONTEXT_VARIABLE]) +@pytest.mark.parametrize('project', ['AutomatedTesting']) +@pytest.mark.parametrize('region_name', [constants.AWS_REGION]) +@pytest.mark.parametrize('resource_mappings_filename', [constants.AWS_RESOURCE_MAPPING_FILE_NAME]) +@pytest.mark.parametrize('session_name', [constants.SESSION_NAME]) +@pytest.mark.parametrize('stacks', [[f'{constants.AWS_PROJECT_NAME}-{AWS_METRICS_FEATURE_NAME}-{constants.AWS_REGION}']]) class TestAWSMetricsWindows(object): """ Test class to verify the real-time and batch analytics for metrics. """ - - @pytest.mark.parametrize('destroy_stacks_on_teardown', [False]) def test_realtime_and_batch_analytics(self, level: str, launcher: pytest.fixture, asset_processor: pytest.fixture, workspace: pytest.fixture, aws_utils: pytest.fixture, - cdk: pytest.fixture, + resource_mappings: pytest.fixture, + stacks: typing.List, aws_metrics_utils: pytest.fixture): """ Verify that the metrics events are sent to CloudWatch and S3 for analytics. """ # Start Kinesis analytics application on a separate thread to avoid blocking the test. - kinesis_analytics_application_thread = AWSMetricsThread(target=start_kinesis_analytics_application, - args=(aws_metrics_utils, cdk.stacks[0])) + kinesis_analytics_application_thread = AWSMetricsThread(target=update_kinesis_analytics_application_status, + args=(aws_metrics_utils, resource_mappings, True)) kinesis_analytics_application_thread.start() + + # Clear the analytics bucket objects before sending new metrics. + aws_metrics_utils.empty_bucket( + resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsBucketName')) + log_monitor = setup(launcher, asset_processor) # Kinesis analytics application needs to be in the running state before we start the game launcher. @@ -177,18 +189,22 @@ class TestAWSMetricsWindows(object): start_time) logger.info('Real-time metrics are sent to CloudWatch.') - # Run time-consuming verifications on separate threads to avoid blocking the test. - verification_threads = list() - verification_threads.append( - AWSMetricsThread(target=query_metrics_from_s3, args=(aws_metrics_utils, cdk.stacks[0]))) - verification_threads.append( - AWSMetricsThread(target=verify_operational_metrics, args=(aws_metrics_utils, cdk.stacks[0], start_time))) - for thread in verification_threads: + # Run time-consuming operations on separate threads to avoid blocking the test. + operational_threads = list() + operational_threads.append( + AWSMetricsThread(target=query_metrics_from_s3, + args=(aws_metrics_utils, resource_mappings, stacks[0]))) + operational_threads.append( + AWSMetricsThread(target=verify_operational_metrics, + args=(aws_metrics_utils, stacks[0], start_time))) + operational_threads.append( + AWSMetricsThread(target=update_kinesis_analytics_application_status, + args=(aws_metrics_utils, resource_mappings, False))) + for thread in operational_threads: thread.start() - for thread in verification_threads: + for thread in operational_threads: thread.join() - @pytest.mark.parametrize('destroy_stacks_on_teardown', [True]) def test_unauthorized_user_request_rejected(self, level: str, launcher: pytest.fixture, diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_utils.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_utils.py index 97cd563651..e7eb486d02 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_utils.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_utils.py @@ -198,7 +198,7 @@ class AWSMetricsUtils: assert state == 'SUCCEEDED', f'Failed to run the named query {named_query.get("Name", {})}' - def empty_batch_analytics_bucket(self, bucket_name: str) -> None: + def empty_bucket(self, bucket_name: str) -> None: """ Empty the S3 bucket following: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/migrations3.html @@ -211,25 +211,18 @@ class AWSMetricsUtils: for key in bucket.objects.all(): key.delete() - def get_analytics_bucket_name(self, stack_name: str) -> str: + def delete_table(self, database_name: str, table_name: str) -> None: """ - Get the name of the deployed S3 bucket. - :param stack_name: Name of the CloudFormation stack. - :return: Name of the deployed S3 bucket. + Delete an existing Glue table. + + :param database_name: Name of the Glue database. + :param table_name: Name of the table to delete. """ - - client = self._aws_util.client('cloudformation') - - response = client.describe_stack_resources( - StackName=stack_name + client = self._aws_util.client('glue') + client.delete_table( + DatabaseName=database_name, + Name=table_name ) - resources = response.get('StackResources', []) - - for resource in resources: - if resource.get('ResourceType') == 'AWS::S3::Bucket': - return resource.get('PhysicalResourceId', '') - - return '' @pytest.fixture(scope='function') diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_waiters.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_waiters.py index abfeaec076..46070a3a64 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_waiters.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_waiters.py @@ -45,7 +45,8 @@ class KinesisAnalyticsApplicationUpdatedWaiter(CustomWaiter): class GlueCrawlerReadyWaiter(CustomWaiter): """ Subclass of the base custom waiter class. - Wait for the Glue crawler to finish its processing. + Wait for the Glue crawler to finish its processing. Return when the crawler is in the "Stopping" status + to avoid wasting too much time in the automation tests on its shutdown process. """ def __init__(self, client: botocore.client): """ @@ -57,7 +58,7 @@ class GlueCrawlerReadyWaiter(CustomWaiter): 'GlueCrawlerReady', 'GetCrawler', 'Crawler.State', - {'READY': WaitState.SUCCESS}, + {'STOPPING': WaitState.SUCCESS}, client) def wait(self, crawler_name): diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/cdk/__init__.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/cdk/__init__.py deleted file mode 100644 index bbcbcf1807..0000000000 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/cdk/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/cdk/cdk_utils.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/cdk/cdk_utils.py deleted file mode 100644 index 3643c3bb36..0000000000 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/cdk/cdk_utils.py +++ /dev/null @@ -1,248 +0,0 @@ -""" -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. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - -import os -import pytest -import boto3 -import uuid -import logging -import subprocess -import botocore - -import ly_test_tools.environment.process_utils as process_utils -from typing import List - -BOOTSTRAP_STACK_NAME = 'CDKToolkit' -BOOTSTRAP_STAGING_BUCKET_LOGIC_ID = 'StagingBucket' - -logger = logging.getLogger(__name__) - - -class Cdk: - """ - Cdk class that provides methods to run cdk application commands. - Expects system to have NodeJS, AWS CLI and CDK installed globally and have their paths setup as env variables. - """ - - def __init__(self): - self._cdk_env = '' - self._stacks = [] - self._cdk_path = os.path.dirname(os.path.realpath(__file__)) - self._session = '' - - cdk_npm_latest_version_cmd = ['npm', 'view', 'aws-cdk', 'version'] - - output = process_utils.check_output( - cdk_npm_latest_version_cmd, - cwd=self._cdk_path, - shell=True) - cdk_npm_latest_version = output.split()[0] - - cdk_version_cmd = ['cdk', 'version'] - output = process_utils.check_output( - cdk_version_cmd, - cwd=self._cdk_path, - shell=True) - cdk_version = output.split()[0] - logger.info(f'Current CDK version {cdk_version}') - - if cdk_version != cdk_npm_latest_version: - try: - logger.info(f'Updating CDK to latest') - # uninstall and reinstall cdk in case npm has been updated. - output = process_utils.check_output( - 'npm uninstall -g aws-cdk', - cwd=self._cdk_path, - shell=True) - - logger.info(f'Uninstall CDK output: {output}') - - output = process_utils.check_output( - 'npm install -g aws-cdk@latest', - cwd=self._cdk_path, - shell=True) - - logger.info(f'Install CDK output: {output}') - except subprocess.CalledProcessError as error: - logger.warning(f'Failed reinstalling latest CDK on npm' - f'\nError:{error.stderr}') - - def setup(self, cdk_path: str, project: str, account_id: str, - workspace: pytest.fixture, session: boto3.session.Session): - """ - :param cdk_path: Path where cdk app.py is stored. - :param project: Project name used for cdk project name env variable. - :param account_id: AWS account id to use with cdk application. - :param workspace: ly_test_tools workspace fixture. - :param session: Current boto3 session, provides credentials and region. - """ - self._cdk_env = os.environ.copy() - unique_id = uuid.uuid4().hex[-4:] - self._cdk_env['O3DE_AWS_PROJECT_NAME'] = project[:4] + unique_id if len(project) > 4 else project + unique_id - self._cdk_env['O3DE_AWS_DEPLOY_REGION'] = session.region_name - self._cdk_env['O3DE_AWS_DEPLOY_ACCOUNT'] = account_id - self._cdk_env['PATH'] = f'{workspace.paths.engine_root()}\\python;' + self._cdk_env['PATH'] - - credentials = session.get_credentials().get_frozen_credentials() - self._cdk_env['AWS_ACCESS_KEY_ID'] = credentials.access_key - self._cdk_env['AWS_SECRET_ACCESS_KEY'] = credentials.secret_key - self._cdk_env['AWS_SESSION_TOKEN'] = credentials.token - self._cdk_path = cdk_path - - self._session = session - - output = process_utils.check_output( - 'python -m pip install -r requirements.txt', - cwd=self._cdk_path, - env=self._cdk_env, - shell=True) - - logger.info(f'Installing cdk python dependencies: {output}') - - self.bootstrap() - - def bootstrap(self) -> None: - """ - Deploy the bootstrap stack. - """ - try: - bootstrap_cmd = ['cdk', 'bootstrap', - f'aws://{self._cdk_env["O3DE_AWS_DEPLOY_ACCOUNT"]}/{self._cdk_env["O3DE_AWS_DEPLOY_REGION"]}'] - - process_utils.check_call( - bootstrap_cmd, - cwd=self._cdk_path, - env=self._cdk_env, - shell=True) - except botocore.exceptions.ClientError as clientError: - logger.warning(f'Failed creating Bootstrap stack {BOOTSTRAP_STACK_NAME} not found. ' - f'\nError:{clientError["Error"]["Message"]}') - - def list(self, deployment_params: List[str] = None) -> List[str]: - """ - lists cdk stack names. - :param deployment_params: Deployment parameters like --all can be passed in this way. - :return List of cdk stack names. - """ - if not self._cdk_path: - return [] - - list_cdk_application_cmd = ['cdk', 'list'] - if deployment_params: - list_cdk_application_cmd.extend(deployment_params) - - output = process_utils.check_output( - list_cdk_application_cmd, - cwd=self._cdk_path, - env=self._cdk_env, - shell=True) - - return output.splitlines() - - def synthesize(self, deployment_params: List[str] = None) -> None: - """ - Synthesizes all cdk stacks. - :param deployment_params: Deployment parameters like --all can be passed in this way. - """ - if not self._cdk_path: - return - - synth_cdk_application_cmd = ['cdk', 'synth'] - if deployment_params: - synth_cdk_application_cmd.extend(deployment_params) - - process_utils.check_output( - synth_cdk_application_cmd, - cwd=self._cdk_path, - env=self._cdk_env, - shell=True) - - def deploy(self, deployment_params: List[str] = None) -> List[str]: - """ - Deploys all the CDK stacks. - :param deployment_params: Deployment parameters like --all can be passed in this way. - :return List of deployed stack arns. - """ - if not self._cdk_path: - return [] - - deploy_cdk_application_cmd = ['cdk', 'deploy', '--require-approval', 'never'] - if deployment_params: - deploy_cdk_application_cmd.extend(deployment_params) - - output = process_utils.check_output( - deploy_cdk_application_cmd, - cwd=self._cdk_path, - env=self._cdk_env, - shell=True) - - for line in output.splitlines(): - line_sections = line.split('/') - assert len(line_sections), 3 - self._stacks.append(line.split('/')[-2]) - - return self._stacks - - def destroy(self, deployment_params: List[str] = None) -> None: - """ - Destroys the cdk application. - :param deployment_params: Deployment parameters like --all can be passed in this way. - """ - - logger.info(f'CDK Path {self._cdk_path}') - destroy_cdk_application_cmd = ['cdk', 'destroy', '-f'] - if deployment_params: - destroy_cdk_application_cmd.extend(deployment_params) - - try: - process_utils.check_output( - destroy_cdk_application_cmd, - cwd=self._cdk_path, - env=self._cdk_env, - shell=True) - - except subprocess.CalledProcessError as e: - logger.error(e.output) - raise e - - self._stacks = [] - - def remove_bootstrap_stack(self) -> None: - """ - Remove the CDK bootstrap stack. - :param aws_utils: aws_utils fixture. - """ - # Check if the bootstrap stack exists. - response = self._session.client('cloudformation').describe_stacks( - StackName=BOOTSTRAP_STACK_NAME - ) - stacks = response.get('Stacks', []) - if not stacks or len(stacks) is 0: - return - - # Clear the bootstrap staging bucket before deleting the bootstrap stack. - response = self._session.client('cloudformation').describe_stack_resource( - StackName=BOOTSTRAP_STACK_NAME, - LogicalResourceId=BOOTSTRAP_STAGING_BUCKET_LOGIC_ID - ) - - staging_bucket_name = response.get('StackResourceDetail', {}).get('PhysicalResourceId', '') - if staging_bucket_name: - s3 = self._session.resource('s3') - bucket = s3.Bucket(staging_bucket_name) - for key in bucket.objects.all(): - key.delete() - - # Delete the bootstrap stack. - # Should not need to delete the stack if S3 bucket can be cleaned. - # self._session.client('cloudformation').delete_stack( - # StackName=BOOTSTRAP_STACK_NAME - # ) - - @property - def stacks(self): - return self._stacks diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/aws_client_auth_automation_test.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/aws_client_auth_automation_test.py index bdd1eea469..b56d3f88f5 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/aws_client_auth_automation_test.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/aws_client_auth_automation_test.py @@ -4,45 +4,42 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import pytest -import os + import logging +import os +import pytest + import ly_test_tools.log.log_monitor +from AWS.common import constants + # fixture imports from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor -AWS_PROJECT_NAME = 'AWS-AutomationTest' AWS_CLIENT_AUTH_FEATURE_NAME = 'AWSClientAuth' -AWS_CLIENT_AUTH_DEFAULT_PROFILE_NAME = 'default' - -GAME_LOG_NAME = 'Game.log' logger = logging.getLogger(__name__) @pytest.mark.SUITE_periodic -@pytest.mark.usefixtures('automatic_process_killer') @pytest.mark.usefixtures('asset_processor') -@pytest.mark.usefixtures('workspace') -@pytest.mark.parametrize('project', ['AutomatedTesting']) -@pytest.mark.usefixtures('cdk') -@pytest.mark.parametrize('feature_name', [AWS_CLIENT_AUTH_FEATURE_NAME]) -@pytest.mark.usefixtures('resource_mappings') -@pytest.mark.parametrize('resource_mappings_filename', ['default_aws_resource_mappings.json']) +@pytest.mark.usefixtures('automatic_process_killer') @pytest.mark.usefixtures('aws_utils') -@pytest.mark.parametrize('region_name', ['us-west-2']) -@pytest.mark.parametrize('assume_role_arn', ['arn:aws:iam::645075835648:role/o3de-automation-tests']) -@pytest.mark.parametrize('session_name', ['o3de-Automation-session']) -@pytest.mark.usefixtures('cdk') -@pytest.mark.parametrize('deployment_params', [[]]) +@pytest.mark.usefixtures('workspace') +@pytest.mark.parametrize('assume_role_arn', [constants.ASSUME_ROLE_ARN]) +@pytest.mark.parametrize('feature_name', [AWS_CLIENT_AUTH_FEATURE_NAME]) +@pytest.mark.parametrize('project', ['AutomatedTesting']) +@pytest.mark.usefixtures('resource_mappings') +@pytest.mark.parametrize('resource_mappings_filename', [constants.AWS_RESOURCE_MAPPING_FILE_NAME]) +@pytest.mark.parametrize('region_name', [constants.AWS_REGION]) +@pytest.mark.parametrize('session_name', [constants.SESSION_NAME]) +@pytest.mark.parametrize('stacks', [[f'{constants.AWS_PROJECT_NAME}-{AWS_CLIENT_AUTH_FEATURE_NAME}-Stack-{constants.AWS_REGION}']]) class TestAWSClientAuthWindows(object): """ Test class to verify AWS Client Auth gem features on Windows. """ @pytest.mark.parametrize('level', ['AWS/ClientAuth']) - @pytest.mark.parametrize('destroy_stacks_on_teardown', [False]) def test_anonymous_credentials(self, level: str, launcher: pytest.fixture, @@ -53,14 +50,14 @@ class TestAWSClientAuthWindows(object): """ Test to verify AWS Cognito Identity pool anonymous authorization. - Setup: Deploys cdk and updates resource mapping file. + Setup: Updates resource mapping file using existing CloudFormation stacks. Tests: Getting credentials when no credentials are configured Verification: Log monitor looks for success credentials log. """ asset_processor.start() asset_processor.wait_for_idle() - file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), GAME_LOG_NAME) + file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), constants.GAME_LOG_NAME) log_monitor = ly_test_tools.log.log_monitor.LogMonitor(launcher=launcher, log_file_path=file_to_monitor) launcher.args = ['+LoadLevel', level] @@ -74,10 +71,8 @@ class TestAWSClientAuthWindows(object): ) assert result, 'Anonymous credentials fetched successfully.' - @pytest.mark.parametrize('destroy_stacks_on_teardown', [True]) def test_password_signin_credentials(self, launcher: pytest.fixture, - cdk: pytest.fixture, resource_mappings: pytest.fixture, workspace: pytest.fixture, asset_processor: pytest.fixture, @@ -86,16 +81,29 @@ class TestAWSClientAuthWindows(object): """ Test to verify AWS Cognito IDP Password sign in and Cognito Identity pool authenticated authorization. - Setup: Deploys cdk and updates resource mapping file. + Setup: Updates resource mapping file using existing CloudFormation stacks. Tests: Sign up new test user, admin confirm the user, sign in and get aws credentials. Verification: Log monitor looks for success credentials log. """ asset_processor.start() asset_processor.wait_for_idle() - file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), GAME_LOG_NAME) + file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), constants.GAME_LOG_NAME) log_monitor = ly_test_tools.log.log_monitor.LogMonitor(launcher=launcher, log_file_path=file_to_monitor) + cognito_idp = aws_utils.client('cognito-idp') + user_pool_id = resource_mappings.get_resource_name_id(f'{AWS_CLIENT_AUTH_FEATURE_NAME}.CognitoUserPoolId') + logger.info(f'UserPoolId:{user_pool_id}') + + # Remove the user if already exists + try: + cognito_idp.admin_delete_user( + UserPoolId=user_pool_id, + Username='test1' + ) + except cognito_idp.exceptions.UserNotFoundException: + pass + launcher.args = ['+LoadLevel', 'AWS/ClientAuthPasswordSignUp'] launcher.args.extend(['-rhi=null']) @@ -109,9 +117,6 @@ class TestAWSClientAuthWindows(object): launcher.stop() - cognito_idp = aws_utils.client('cognito-idp') - user_pool_id = resource_mappings.get_resource_name_id(f'{AWS_CLIENT_AUTH_FEATURE_NAME}.CognitoUserPoolId') - print(f'UserPoolId:{user_pool_id}') cognito_idp.admin_confirm_sign_up( UserPoolId=user_pool_id, Username='test1' diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py index 55f06660e8..529151f3f6 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py @@ -5,10 +5,11 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os import logging -import typing +import os import shutil +import typing +from botocore.exceptions import ClientError import pytest import ly_test_tools @@ -16,16 +17,15 @@ import ly_test_tools.log.log_monitor import ly_test_tools.environment.process_utils as process_utils import ly_test_tools.o3de.asset_processor_utils as asset_processor_utils -from botocore.exceptions import ClientError +from AWS.common import constants + +# fixture imports from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor AWS_CORE_FEATURE_NAME = 'AWSCore' -AWS_RESOURCE_MAPPING_FILE_NAME = 'default_aws_resource_mappings.json' process_utils.kill_processes_named("o3de", ignore_extensions=True) # Kill ProjectManager windows -GAME_LOG_NAME = 'Game.log' - logger = logging.getLogger(__name__) @@ -46,7 +46,7 @@ def setup(launcher: pytest.fixture, asset_processor: pytest.fixture) -> typing.T asset_processor.start() asset_processor.wait_for_idle() - file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), GAME_LOG_NAME) + file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), constants.GAME_LOG_NAME) log_monitor = ly_test_tools.log.log_monitor.LogMonitor(launcher=launcher, log_file_path=file_to_monitor) return log_monitor, s3_download_dir @@ -58,7 +58,7 @@ def write_test_data_to_dynamodb_table(resource_mappings: pytest.fixture, aws_uti :param resource_mappings: resource_mappings fixture. :param aws_utils: aws_utils fixture. """ - table_name = resource_mappings.get_resource_name_id("AWSCore.ExampleDynamoTableOutput") + table_name = resource_mappings.get_resource_name_id(f'{AWS_CORE_FEATURE_NAME}.ExampleDynamoTableOutput') try: aws_utils.client('dynamodb').put_item( TableName=table_name, @@ -77,21 +77,19 @@ def write_test_data_to_dynamodb_table(resource_mappings: pytest.fixture, aws_uti @pytest.mark.SUITE_periodic @pytest.mark.usefixtures('automatic_process_killer') @pytest.mark.usefixtures('asset_processor') -@pytest.mark.usefixtures('cdk') @pytest.mark.parametrize('feature_name', [AWS_CORE_FEATURE_NAME]) -@pytest.mark.parametrize('region_name', ['us-west-2']) -@pytest.mark.parametrize('assume_role_arn', ['arn:aws:iam::645075835648:role/o3de-automation-tests']) -@pytest.mark.parametrize('session_name', ['o3de-Automation-session']) +@pytest.mark.parametrize('region_name', [constants.AWS_REGION]) +@pytest.mark.parametrize('assume_role_arn', [constants.ASSUME_ROLE_ARN]) +@pytest.mark.parametrize('session_name', [constants.SESSION_NAME]) @pytest.mark.usefixtures('workspace') @pytest.mark.parametrize('project', ['AutomatedTesting']) @pytest.mark.parametrize('level', ['AWS/Core']) @pytest.mark.usefixtures('resource_mappings') -@pytest.mark.parametrize('resource_mappings_filename', [AWS_RESOURCE_MAPPING_FILE_NAME]) +@pytest.mark.parametrize('resource_mappings_filename', [constants.AWS_RESOURCE_MAPPING_FILE_NAME]) +@pytest.mark.parametrize('stacks', [[f'{constants.AWS_PROJECT_NAME}-{AWS_CORE_FEATURE_NAME}', + f'{constants.AWS_PROJECT_NAME}-{AWS_CORE_FEATURE_NAME}-Example-{constants.AWS_REGION}']]) @pytest.mark.usefixtures('aws_credentials') @pytest.mark.parametrize('profile_name', ['AWSAutomationTest']) -@pytest.mark.usefixtures('cdk') -@pytest.mark.parametrize('deployment_params', [['--all']]) -@pytest.mark.parametrize('destroy_stacks_on_teardown', [True]) class TestAWSCoreAWSResourceInteraction(object): """ Test class to verify the scripting behavior for the AWSCore gem. @@ -119,7 +117,7 @@ class TestAWSCoreAWSResourceInteraction(object): expected_lines: typing.List[str], unexpected_lines: typing.List[str]): """ - Setup: Deploys cdk and updates resource mapping file. + Setup: Updates resource mapping file using existing CloudFormation stacks. Tests: Interact with AWS S3, DynamoDB and Lambda services. Verification: Script canvas nodes can communicate with AWS services successfully. """ diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/resource_mappings/__init__.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/resource_mappings/__init__.py deleted file mode 100644 index e01850f919..0000000000 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/resource_mappings/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -""" -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. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/AWS/common/constants.py b/AutomatedTesting/Gem/PythonTests/AWS/common/constants.py new file mode 100644 index 0000000000..be143547a7 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/AWS/common/constants.py @@ -0,0 +1,19 @@ +""" +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. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +# ARN of the IAM role to assume for retrieving temporary AWS credentials +ASSUME_ROLE_ARN = 'arn:aws:iam::645075835648:role/o3de-automation-tests' +# Name of the AWS project deployed by the CDK applications +AWS_PROJECT_NAME = 'AWSAUTO' +# Region for the existing CloudFormation stacks used by the automation tests +AWS_REGION = 'us-east-1' +# Name of the default resource mapping config file used by the automation tests +AWS_RESOURCE_MAPPING_FILE_NAME = 'default_aws_resource_mappings.json' +# Name of the game launcher log +GAME_LOG_NAME = 'Game.log' +# Name of the IAM role session for retrieving temporary AWS credentials +SESSION_NAME = 'o3de-Automation-session' diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/resource_mappings/resource_mappings.py b/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py similarity index 90% rename from AutomatedTesting/Gem/PythonTests/AWS/Windows/resource_mappings/resource_mappings.py rename to AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py index fd679de99d..5f01ecdbf8 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/resource_mappings/resource_mappings.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py @@ -6,9 +6,9 @@ SPDX-License-Identifier: Apache-2.0 OR MIT """ import os -import pytest import json import logging +from AWS.common import constants logger = logging.getLogger(__name__) @@ -22,18 +22,14 @@ class ResourceMappings: ResourceMappings class that handles writing Cloud formation outputs to resource mappings json file in a project. """ - def __init__(self, file_path: str, region: str, feature_name: str, account_id: str, workspace: pytest.fixture, - cloud_formation_client): + def __init__(self, file_path: str, region: str, feature_name: str, account_id: str, cloud_formation_client): """ :param file_path: Path for the resource mapping file. :param region: Region value for the resource mapping file. :param feature_name: Feature gem name to use to append name to mappings key. :param account_id: AWS account id value for the resource mapping file. - :param workspace: ly_test_tools workspace fixture. :param cloud_formation_client: AWS cloud formation client. """ - self._cdk_env = os.environ.copy() - self._cdk_env['PATH'] = f'{workspace.paths.engine_root()}\\python;' + self._cdk_env['PATH'] self._resource_mapping_file_path = file_path self._region = region self._feature_name = feature_name @@ -44,7 +40,7 @@ class ResourceMappings: f'Invalid resource mapping file path {self._resource_mapping_file_path}' self._client = cloud_formation_client - def populate_output_keys(self, stacks=[]) -> None: + def populate_output_keys(self, stacks=None) -> None: """ Calls describe stacks on cloud formation service and persists outputs to resource mappings file. :param stacks List of stack arns to describe and populate resource mappings with. @@ -58,7 +54,7 @@ class ResourceMappings: self._write_resource_mappings(stacks[0].get('Outputs', [])) - def _write_resource_mappings(self, outputs, append_feature_name = True) -> None: + def _write_resource_mappings(self, outputs, append_feature_name=True) -> None: with open(self._resource_mapping_file_path) as file_content: resource_mappings = json.load(file_content) @@ -91,7 +87,7 @@ class ResourceMappings: resource_mappings = json.load(file_content) resource_mappings[AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY] = '' - resource_mappings[AWS_RESOURCE_MAPPINGS_REGION_KEY] = 'us-west-2' + resource_mappings[AWS_RESOURCE_MAPPINGS_REGION_KEY] = constants.AWS_REGION # Append new mappings. resource_mappings[AWS_RESOURCE_MAPPINGS_KEY] = resource_mappings.get(AWS_RESOURCE_MAPPINGS_KEY, {}) diff --git a/AutomatedTesting/Gem/PythonTests/AWS/conftest.py b/AutomatedTesting/Gem/PythonTests/AWS/conftest.py index 6ad495ab66..df65aa7a5c 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/conftest.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/conftest.py @@ -11,8 +11,7 @@ import typing from AWS.common.aws_utils import AwsUtils from AWS.common.aws_credentials import AwsCredentials -from AWS.Windows.cdk.cdk_utils import Cdk -from AWS.Windows.resource_mappings.resource_mappings import ResourceMappings +from AWS.common.resource_mappings import ResourceMappings logger = logging.getLogger(__name__) @@ -52,6 +51,7 @@ def resource_mappings( project: str, feature_name: str, resource_mappings_filename: str, + stacks: typing.List, workspace: pytest.fixture, aws_utils: pytest.fixture) -> ResourceMappings: """ @@ -61,6 +61,7 @@ def resource_mappings( :param project: Project to find resource mapping file. :param feature_name: AWS Gem name that is prepended to resource mapping keys. :param resource_mappings_filename: Name of resource mapping file. + :param stacks: List of stack names to describe and populate resource mappings with. :param workspace: ly_test_tools workspace fixture. :param aws_utils: AWS utils fixture. :return: ResourceMappings class object. @@ -70,8 +71,8 @@ def resource_mappings( logger.info(f'Resource mapping path : {path}') logger.info(f'Resource mapping resolved path : {abspath(path)}') resource_mappings_obj = ResourceMappings(abspath(path), aws_utils.assume_session().region_name, feature_name, - aws_utils.assume_account_id(), workspace, - aws_utils.client('cloudformation')) + aws_utils.assume_account_id(), aws_utils.client('cloudformation')) + resource_mappings_obj.populate_output_keys(stacks) def teardown(): resource_mappings_obj.clear_output_keys() @@ -81,56 +82,6 @@ def resource_mappings( return resource_mappings_obj -@pytest.fixture(scope='function') -def cdk( - request: pytest.fixture, - project: str, - feature_name: str, - workspace: pytest.fixture, - aws_utils: pytest.fixture, - resource_mappings: pytest.fixture, - deployment_params: typing.List[str], - destroy_stacks_on_teardown: bool) -> Cdk: - """ - Fixture for setting up a Cdk - :param request: _pytest.fixtures.SubRequest class that handles getting - a pytest fixture from a pytest function/fixture. - :param project: Project name used for cdk project name env variable. - :param feature_name: Feature gem name to expect cdk folder in. - :param workspace: ly_test_tools workspace fixture. - :param aws_utils: aws_utils fixture. - :param resource_mappings: resource_mappings fixture. - :param deployment_params: Parameters for the CDK application deployment. - :param destroy_stacks_on_teardown: option to control calling destroy ot the end of test. - :return Cdk class object. - """ - - cdk_path = f'{workspace.paths.engine_root()}/Gems/{feature_name}/cdk' - logger.info(f'CDK Path {cdk_path}') - - if pytest.cdk_obj is None: - pytest.cdk_obj = Cdk() - pytest.cdk_obj.setup(cdk_path, project, aws_utils.assume_account_id(), workspace, aws_utils.assume_session()) - - stacks = pytest.cdk_obj.deploy(deployment_params=deployment_params) - - logger.info(f'Cdk stack names:\n{stacks}') - resource_mappings.populate_output_keys(stacks) - - def teardown(): - if destroy_stacks_on_teardown: - pytest.cdk_obj.destroy(deployment_params=deployment_params) - # Enable after https://github.com/aws/aws-cdk/issues/986 is fixed. - # Until then clean the bootstrap bucket manually. - # pytest.cdk_obj.remove_bootstrap_stack() - - pytest.cdk_obj = None - - request.addfinalizer(teardown) - - return pytest.cdk_obj - - @pytest.fixture(scope='function') def aws_credentials(request: pytest.fixture, aws_utils: pytest.fixture, profile_name: str): """ diff --git a/Gems/AWSCore/cdk/app.py b/Gems/AWSCore/cdk/app.py index ea038f8a51..16773b5f69 100755 --- a/Gems/AWSCore/cdk/app.py +++ b/Gems/AWSCore/cdk/app.py @@ -25,7 +25,7 @@ ACCOUNT = os.environ.get('O3DE_AWS_DEPLOY_ACCOUNT', os.environ.get('CDK_DEFAULT_ PROJECT_NAME = os.environ.get('O3DE_AWS_PROJECT_NAME', f'O3DE-AWS-PROJECT').upper() # The name of this feature -FEATURE_NAME = 'Core' +FEATURE_NAME = 'AWSCore' # The name of this CDK application PROJECT_FEATURE_NAME = f'{PROJECT_NAME}-{FEATURE_NAME}' diff --git a/Gems/AWSMetrics/cdk/aws_metrics/batch_analytics.py b/Gems/AWSMetrics/cdk/aws_metrics/batch_analytics.py index 5be6562982..8398113bc4 100755 --- a/Gems/AWSMetrics/cdk/aws_metrics/batch_analytics.py +++ b/Gems/AWSMetrics/cdk/aws_metrics/batch_analytics.py @@ -96,9 +96,9 @@ class BatchAnalytics: ), athena.CfnNamedQuery( self._stack, - id='NamedQuery-NewUsersLastMonth', + id='NamedQuery-LoginLastMonth', name=resource_name_sanitizer.sanitize_resource_name( - f'{self._stack.stack_name}-NamedQuery-NewUsersLastMonth', 'athena_named_query'), + f'{self._stack.stack_name}-NamedQuery-LoginLastMonth', 'athena_named_query'), database=self._events_database_name, query_string="WITH detail AS (" "SELECT date_trunc('month', date(date_parse(CONCAT(year, '-', month, '-', day), '%Y-%m-%d'))) as event_month, * " @@ -107,9 +107,9 @@ class BatchAnalytics: "date_trunc('month', event_month) as month, " "count(*) as new_accounts " "FROM detail " - "WHERE event_name = 'user_registration' " + "WHERE event_name = 'login' " "GROUP BY date_trunc('month', event_month)", - description='New users over the last month', + description='Total number of login events over the last month', work_group=self._athena_work_group.name ) ] diff --git a/Gems/AWSMetrics/cdk/aws_metrics/data_lake_integration.py b/Gems/AWSMetrics/cdk/aws_metrics/data_lake_integration.py index aaaf03b1fa..e47b1a95c2 100755 --- a/Gems/AWSMetrics/cdk/aws_metrics/data_lake_integration.py +++ b/Gems/AWSMetrics/cdk/aws_metrics/data_lake_integration.py @@ -50,8 +50,7 @@ class DataLakeIntegration: # a specific name here, only one customer can deploy the bucket successfully. self._analytics_bucket = s3.Bucket( self._stack, - id=f'AnalyticsBucket'.lower(), - bucket_name=resource_name_sanitizer.sanitize_resource_name( + id=resource_name_sanitizer.sanitize_resource_name( f'{self._stack.stack_name}-AnalyticsBucket'.lower(), 's3_bucket'), encryption=s3.BucketEncryption.S3_MANAGED, block_public_access=s3.BlockPublicAccess( @@ -68,6 +67,13 @@ class DataLakeIntegration: cfn_bucket = self._analytics_bucket.node.find_child('Resource') cfn_bucket.apply_removal_policy(core.RemovalPolicy.DESTROY) + analytics_bucket_output = core.CfnOutput( + self._stack, + id='AnalyticsBucketName', + description='Name of the S3 bucket for storing metrics event data', + export_name=f"{self._application_name}:AnalyticsBucket", + value=self._analytics_bucket.bucket_name) + def _create_events_database(self) -> None: """ Create the Glue database for metrics events. diff --git a/Gems/AWSMetrics/cdk/aws_metrics/real_time_data_processing.py b/Gems/AWSMetrics/cdk/aws_metrics/real_time_data_processing.py index 52fdcdc122..4ef9caa022 100755 --- a/Gems/AWSMetrics/cdk/aws_metrics/real_time_data_processing.py +++ b/Gems/AWSMetrics/cdk/aws_metrics/real_time_data_processing.py @@ -182,7 +182,7 @@ class RealTimeDataProcessing: Generate the analytics processing lambda to send processed data to CloudWatch for visualization. """ analytics_processing_function_name = resource_name_sanitizer.sanitize_resource_name( - f'{self._stack.stack_name}-AnalyticsProcessingLambdaName', 'lambda_function') + f'{self._stack.stack_name}-AnalyticsProcessingLambda', 'lambda_function') self._analytics_processing_lambda_role = self._create_analytics_processing_lambda_role( analytics_processing_function_name ) diff --git a/scripts/build/Platform/Windows/pipeline.json b/scripts/build/Platform/Windows/pipeline.json index 4cfc6f696a..4c736d2292 100644 --- a/scripts/build/Platform/Windows/pipeline.json +++ b/scripts/build/Platform/Windows/pipeline.json @@ -24,28 +24,28 @@ "parameter_type": "string", "default_value": "", "use_last_run_value": true, - "description": "" + "description": "The name of the O3DE project that stacks should be deployed for." }, { "parameter_name": "O3DE_AWS_DEPLOY_REGION", "parameter_type": "string", "default_value": "", "use_last_run_value": true, - "description": "" + "description": "The region to deploy the stacks into." }, { "parameter_name": "ASSUME_ROLE_ARN", "parameter_type": "string", "default_value": "", "use_last_run_value": true, - "description": "" + "description": "The ARN of the IAM role to assume to retrieve temporary AWS credentials." }, { "parameter_name": "COMMIT_ID", "parameter_type": "string", "default_value": "", "use_last_run_value": true, - "description": "" + "description": "The commit ID for locking the version of CDK applications to deploy." } ] } From 983f18712147bfe300e470112ab893444ec76118 Mon Sep 17 00:00:00 2001 From: "rgba16f [Amazon]" <82187279+rgba16f@users.noreply.github.com> Date: Thu, 19 Aug 2021 16:31:36 -0500 Subject: [PATCH 30/54] update used dxc package to revision 3 (#3317) * Update Mac build to use rev3 of dxc package Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Update linux DXC package version requested Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Update windows DXC package revision requested Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake | 2 +- cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake | 2 +- cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index bb70a54d6f..9c142b801c 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -42,7 +42,7 @@ ly_associate_package(PACKAGE_NAME unwind-1.2.1-linux ly_associate_package(PACKAGE_NAME qt-5.15.2-rev5-linux TARGETS Qt PACKAGE_HASH 76b395897b941a173002845c7219a5f8a799e44b269ffefe8091acc048130f28) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-linux TARGETS libsamplerate PACKAGE_HASH 41643c31bc6b7d037f895f89d8d8d6369e906b92eff42b0fe05ee6a100f06261) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev2-linux TARGETS OpenSSL PACKAGE_HASH b779426d1e9c5ddf71160d5ae2e639c3b956e0fb5e9fcaf9ce97c4526024e3bc) -ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev2-linux TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 235606f98512c076a1ba84a8402ad24ac21945998abcea264e8e204678efc0ba) +ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-linux TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 88c4a359325d749bc34090b9ac466424847f3b71ba0de15045cf355c17c07099) ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-linux TARGETS SPIRVCross PACKAGE_HASH 7889ee5460a688e9b910c0168b31445c0079d363affa07b25d4c8aeb608a0b80) ly_associate_package(PACKAGE_NAME azslc-1.7.23-rev2-linux TARGETS azslc PACKAGE_HASH 1ba84d8321a566d35a1e9aa7400211ba8e6d1c11c08e4be3c93e6e74b8f7aef1) ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev1-linux TARGETS zlib PACKAGE_HASH 6418e93b9f4e6188f3b62cbd3a7822e1c4398a716e786d1522b809a727d08ba9) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index a0001d3e4e..2813ff302e 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -28,7 +28,7 @@ ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform TARGETS PVRTexTool PACKAGE_HASH d0d6da61c7557de0d2c71fc35ba56c3be49555b703f0e853d4c58225537acf1e) # platform-specific: -ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev2-mac TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 2bede9a7ef3573027c005e38139237559eebf845c13ffb54c33c5b8675f962e2) +ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-mac TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 3f77367dbb0342136ec4ebbd44bc1fedf7198089a0f83c5631248530769b2be6) ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-mac TARGETS SPIRVCross PACKAGE_HASH 78c6376ed2fd195b9b1f5fb2b56e5267a32c3aa21fb399e905308de470eb4515) ly_associate_package(PACKAGE_NAME freetype-2.10.4.14-mac-ios TARGETS freetype PACKAGE_HASH 67b4f57aed92082d3fd7c16aa244a7d908d90122c296b0a63f73e0a0b8761977) ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-mac-ios TARGETS tiff PACKAGE_HASH a23ae1f8991a29f8e5df09d6d5b00d7768a740f90752cef465558c1768343709) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index 4ac5fea18c..84b042d1b9 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -30,7 +30,7 @@ ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform # platform-specific: ly_associate_package(PACKAGE_NAME AWSGameLiftServerSDK-3.4.1-rev1-windows TARGETS AWSGameLiftServerSDK PACKAGE_HASH a0586b006e4def65cc25f388de17dc475e417dc1e6f9d96749777c88aa8271b0) ly_associate_package(PACKAGE_NAME Blast-v1.1.7_rc2-9-geb169fe-rev1-windows TARGETS Blast PACKAGE_HASH 216df71f4ffaf4a6ea3f2e77e5f27d68f2325e717fbd1626b00c785b82cd1b67) -ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev2-windows TARGETS DirectXShaderCompilerDxc PACKAGE_HASH decc53e97c7ddda9c7f853a30af7808a7b652a912f59ad2cd4bca5d308aae2c4) +ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-windows TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 803e10b94006b834cbbdd30f562a8ddf04174c2cb6956c8399ec164ef8418d1f) ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-windows TARGETS SPIRVCross PACKAGE_HASH 7d601ea9d625b1d509d38bd132a1f433d7e895b16adab76bac6103567a7a6817) ly_associate_package(PACKAGE_NAME freetype-2.10.4.14-windows TARGETS freetype PACKAGE_HASH 88dedc86ccb8c92f14c2c033e51ee7d828fa08eafd6475c6aa963938a99f4bf3) ly_associate_package(PACKAGE_NAME tiff-4.2.0.14-windows TARGETS tiff PACKAGE_HASH ab60d1398e4e1e375ec0f1a00cdb1d812a07c0096d827db575ce52dd6d714207) From e889bba963afbe724e9d7ccb0251f6344dc12419 Mon Sep 17 00:00:00 2001 From: "rgba16f [Amazon]" <82187279+rgba16f@users.noreply.github.com> Date: Thu, 19 Aug 2021 16:53:43 -0500 Subject: [PATCH 31/54] Remove unused hdf5 3rdParty package from the known packages list (#3295) * Remove unused hdf5 3rdParty package from the known packages list Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake | 1 - cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake | 1 - cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake | 1 - 3 files changed, 3 deletions(-) diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index 9c142b801c..796e0beb32 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -8,7 +8,6 @@ # shared by other platforms: ly_associate_package(PACKAGE_NAME ilmbase-2.3.0-rev4-multiplatform TARGETS ilmbase PACKAGE_HASH 97547fdf1fbc4d81b8ccf382261f8c25514ed3b3c4f8fd493f0a4fa873bba348) -ly_associate_package(PACKAGE_NAME hdf5-1.0.11-rev2-multiplatform TARGETS hdf5 PACKAGE_HASH 11d5e04df8a93f8c52a5684a4cacbf0d9003056360983ce34f8d7b601082c6bd) ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform TARGETS assimplib PACKAGE_HASH 1a9113788b893ef4a2ee63ac01eb71b981a92894a5a51175703fa225f5804dec) ly_associate_package(PACKAGE_NAME squish-ccr-20150601-rev3-multiplatform TARGETS squish-ccr PACKAGE_HASH c878c6c0c705e78403c397d03f5aa7bc87e5978298710e14d09c9daf951a83b3) ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index 2813ff302e..ff222ee244 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -8,7 +8,6 @@ # shared by other platforms: ly_associate_package(PACKAGE_NAME ilmbase-2.3.0-rev4-multiplatform TARGETS ilmbase PACKAGE_HASH 97547fdf1fbc4d81b8ccf382261f8c25514ed3b3c4f8fd493f0a4fa873bba348) -ly_associate_package(PACKAGE_NAME hdf5-1.0.11-rev2-multiplatform TARGETS hdf5 PACKAGE_HASH 11d5e04df8a93f8c52a5684a4cacbf0d9003056360983ce34f8d7b601082c6bd) ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform TARGETS assimplib PACKAGE_HASH 1a9113788b893ef4a2ee63ac01eb71b981a92894a5a51175703fa225f5804dec) ly_associate_package(PACKAGE_NAME squish-ccr-20150601-rev3-multiplatform TARGETS squish-ccr PACKAGE_HASH c878c6c0c705e78403c397d03f5aa7bc87e5978298710e14d09c9daf951a83b3) ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index 84b042d1b9..e4fcc768c6 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -8,7 +8,6 @@ # shared by other platforms: ly_associate_package(PACKAGE_NAME ilmbase-2.3.0-rev4-multiplatform TARGETS ilmbase PACKAGE_HASH 97547fdf1fbc4d81b8ccf382261f8c25514ed3b3c4f8fd493f0a4fa873bba348) -ly_associate_package(PACKAGE_NAME hdf5-1.0.11-rev2-multiplatform TARGETS hdf5 PACKAGE_HASH 11d5e04df8a93f8c52a5684a4cacbf0d9003056360983ce34f8d7b601082c6bd) ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform TARGETS assimplib PACKAGE_HASH 1a9113788b893ef4a2ee63ac01eb71b981a92894a5a51175703fa225f5804dec) ly_associate_package(PACKAGE_NAME squish-ccr-20150601-rev3-multiplatform TARGETS squish-ccr PACKAGE_HASH c878c6c0c705e78403c397d03f5aa7bc87e5978298710e14d09c9daf951a83b3) ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326) From 1a430755df763ea3dbd8d40f2a761de25685b914 Mon Sep 17 00:00:00 2001 From: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> Date: Thu, 19 Aug 2021 17:07:06 -0500 Subject: [PATCH 32/54] Landscape Canvas automation optimizations with TestAutomationBase/parallelization (#3255) * Convert Landscape Canvas main tests to use TestAutomationBase * Updating main Landscape Canvas test suite to batch run tests * Converting initial batch of Landscape Canvas periodic tests to use TestAutomationBase/test parallelization * Renaming Editor Script to fit naming convention * Updating explicit waits to wait_for_condition checks * Additional test conversions * Renaming Editor Script to fit naming convention * Additional test parallelizations * Additional test conversions * Renaming optimized test file * Adding Main test file for non-optimized tests Signed-off-by: jckand-amzn --- .../PythonTests/largeworlds/CMakeLists.txt | 6 +- .../AreaNodes_DependentComponentsAdded.py | 235 +++++------ .../AreaNodes_EntityCreatedOnNodeAdd.py | 200 ++++----- .../AreaNodes_EntityRemovedOnNodeDelete.py | 193 ++++----- .../ComponentUpdates_UpdateGraph.py | 346 +++++++-------- .../EditorScripts/Component_AddedRemoved.py | 80 ++++ .../EditorScripts/CreateNewGraph.py | 106 ----- .../Edit_DisabledNodeDuplication.py | 207 ++++----- .../Edit_UndoNodeDelete_SliceEntity.py | 249 +++++------ .../GradientMixer_NodeConstruction.py | 319 +++++++------- ...entModifierNodes_EntityCreatedOnNodeAdd.py | 210 +++++----- ...ModifierNodes_EntityRemovedOnNodeDelete.py | 197 ++++----- .../GradientNodes_DependentComponentsAdded.py | 226 +++++----- .../GradientNodes_EntityCreatedOnNodeAdd.py | 208 ++++----- ...GradientNodes_EntityRemovedOnNodeDelete.py | 200 ++++----- .../GraphClosed_OnEntityDelete.py | 147 ++++--- .../GraphClosed_OnLevelChange.py | 126 +++--- .../EditorScripts/GraphClosed_TabbedGraph.py | 146 ++++--- .../GraphUpdates_UpdateComponents.py | 254 ++++++----- .../LandscapeCanvasComponent_AddedRemoved.py | 87 ---- .../LandscapeCanvas_SliceCreateInstantiate.py | 82 ---- .../LayerBlender_NodeConstruction.py | 245 +++++------ .../LayerExtenderNodes_ComponentEntitySync.py | 270 ++++++------ .../NewGraph_CreatedSuccessfully.py | 111 +++++ .../ShapeNodes_EntityCreatedOnNodeAdd.py | 213 +++++----- .../ShapeNodes_EntityRemovedOnNodeDelete.py | 216 +++++----- .../EditorScripts/Slice_CreateInstantiate.py | 84 ++++ ...otConnections_UpdateComponentReferences.py | 393 +++++++++--------- .../test_LandscapeCanvas_Main.py | 29 ++ .../test_LandscapeCanvas_Main_Optimized.py | 22 + .../test_LandscapeCanvas_Periodic.py | 121 ++++++ ...test_LandscapeCanvas_Periodic_Optimized.py | 89 ++++ 32 files changed, 2972 insertions(+), 2645 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Component_AddedRemoved.py delete mode 100755 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/CreateNewGraph.py delete mode 100755 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvasComponent_AddedRemoved.py delete mode 100755 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvas_SliceCreateInstantiate.py create mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/NewGraph_CreatedSuccessfully.py create mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Slice_CreateInstantiate.py create mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main.py create mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main_Optimized.py create mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic.py create mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic_Optimized.py diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt index 043485d869..f3536c4071 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt @@ -130,8 +130,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ NAME AutomatedTesting::LandscapeCanvasTests_Main TEST_SERIAL TEST_SUITE main - PATH ${CMAKE_CURRENT_LIST_DIR}/landscape_canvas - PYTEST_MARKS "not SUITE_sandbox and not SUITE_periodic and not SUITE_benchmark" + PATH ${CMAKE_CURRENT_LIST_DIR}/landscape_canvas/test_LandscapeCanvas_Main.py RUNTIME_DEPENDENCIES AZ::AssetProcessor Legacy::Editor @@ -144,8 +143,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ NAME AutomatedTesting::LandscapeCanvasTests_Periodic TEST_SERIAL TEST_SUITE periodic - PATH ${CMAKE_CURRENT_LIST_DIR}/landscape_canvas - PYTEST_MARKS "SUITE_periodic" + PATH ${CMAKE_CURRENT_LIST_DIR}/landscape_canvas/test_LandscapeCanvas_Periodic.py RUNTIME_DEPENDENCIES AZ::AssetProcessor Legacy::Editor diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py index 913dc46fa5..9703423901 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py @@ -5,144 +5,147 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + dependencies_added = ( + "Node created new Entity with all required components", + "Failed to create node with all required components" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestAreaNodeComponentDependency(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="AreaNodeComponentDependency", args=["level"]) +def AreaNodes_DependentComponentsAdded(): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities with + proper dependent components. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities with - proper dependent components. + Expected Behavior: + All expected component dependencies are met when adding an area node to a graph. - Expected Behavior: - All expected component dependencies are met when adding an area node to a graph. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the area nodes to the graph area, and ensure the proper dependent components are added - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the area nodes to the graph area, and ensure the proper dependent components are added + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can check if the entity created - # from adding these vegetation area nodes has the main target Vegetation Layer Component - # as well as automatically adding all required dependency components - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Vegetation area mapping with the key being the node name and the value is the - # expected Components that should be added to the Entity created for the node - areas = { - 'SpawnerAreaNode': [ - 'Vegetation Layer Spawner', - 'Vegetation Asset List', - 'Vegetation Reference Shape' - ], - 'MeshBlockerAreaNode': [ - 'Vegetation Layer Blocker (Mesh)', - 'Mesh' - ], - 'BlockerAreaNode': [ - 'Vegetation Layer Blocker', - 'Vegetation Reference Shape' - ] - } + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = [] - for name in areas: - componentNames.extend(areas[name]) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Listen for entity creation notifications so we can check if the entity created + # from adding these vegetation area nodes has the main target Vegetation Layer Component + # as well as automatically adding all required dependency components + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - # Create nodes for the vegetation areas that have additional required dependencies and check if - # the Entity created by adding the node has the appropriate component and required - # additional components added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in areas: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Vegetation area mapping with the key being the node name and the value is the + # expected Components that should be added to the Entity created for the node + areas = { + 'SpawnerAreaNode': [ + 'Vegetation Layer Spawner', + 'Vegetation Asset List', + 'Vegetation Reference Shape' + ], + 'MeshBlockerAreaNode': [ + 'Vegetation Layer Blocker (Mesh)', + 'Mesh' + ], + 'BlockerAreaNode': [ + 'Vegetation Layer Blocker', + 'Vegetation Reference Shape' + ] + } - components = areas[nodeName] - success = False - for component in components: - componentTypeId = componentTypeIds[component] - success = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, - componentTypeId) - if not success: - break - self.test_success = self.test_success and success - if success: - self.log("{node} created new Entity with all required components".format(node=nodeName)) + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = [] + for name in areas: + componentNames.extend(areas[name]) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - x += 40.0 - y += 40.0 + # Create nodes for the vegetation areas that have additional required dependencies and check if + # the Entity created by adding the node has the appropriate component and required + # additional components added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in areas: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - # Stop listening for entity creation notifications - handler.disconnect() + components = areas[nodeName] + success = False + for component in components: + componentTypeId = componentTypeIds[component] + success = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, + componentTypeId) + if not success: + break + Report.info(nodeName) + Report.result(Tests.dependencies_added, success) + + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestAreaNodeComponentDependency() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(AreaNodes_DependentComponentsAdded) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py index 2ee0c60a7d..f3f4a1862d 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py @@ -5,125 +5,129 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + component_added = ( + "New entity created with the expected component", + "Expected component was not found on entity" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestGradientNodeEntityCreate(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="AreaNodeEntityCreate", args=["level"]) +def AreaNodes_EntityCreatedOnNodeAdd(): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. + Expected Behavior: + New entities are created when dragging area nodes to graph area. - Expected Behavior: - New entities are created when dragging area nodes to graph area. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the area nodes to the graph area, and ensure a new entity is created - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the area nodes to the graph area, and ensure a new entity is created + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Listen for entity creation notifications so we can check if the entity created - # from adding vegetation area nodes has the appropriate Vegetation Layer Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Vegetation Area mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - areas = { - 'AreaBlenderNode': 'Vegetation Layer Blender', - 'BlockerAreaNode': 'Vegetation Layer Blocker', - 'MeshBlockerAreaNode': 'Vegetation Layer Blocker (Mesh)', - 'SpawnerAreaNode': 'Vegetation Layer Spawner' - } + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = [] - for name in areas: - componentNames.append(areas[name]) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Create nodes for all the vegetation areas we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in areas: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Listen for entity creation notifications so we can check if the entity created + # from adding vegetation area nodes has the appropriate Vegetation Layer Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - areaComponent = areas[nodeName] - componentTypeId = componentTypeIds[areaComponent] - hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) - self.test_success = self.test_success and hasComponent - if hasComponent: - self.log("{node} created new Entity with {component} Component".format(node=nodeName, component=areaComponent)) + # Vegetation Area mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + areas = { + 'AreaBlenderNode': 'Vegetation Layer Blender', + 'BlockerAreaNode': 'Vegetation Layer Blocker', + 'MeshBlockerAreaNode': 'Vegetation Layer Blocker (Mesh)', + 'SpawnerAreaNode': 'Vegetation Layer Spawner' + } - x += 40.0 - y += 40.0 + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = [] + for name in areas: + componentNames.append(areas[name]) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - # Stop listening for entity creation notifications - handler.disconnect() + # Create nodes for all the vegetation areas we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in areas: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + + areaComponent = areas[nodeName] + componentTypeId = componentTypeIds[areaComponent] + hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) + Report.info(f"Node: {nodeName} | Component: {areaComponent}") + Report.result(Tests.component_added, hasComponent) + + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientNodeEntityCreate() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(AreaNodes_EntityCreatedOnNodeAdd) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py index b9960447c6..f8b0539759 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py @@ -5,123 +5,128 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + entity_deleted = ( + "Entity was deleted when node was removed", + "Entity was not deleted as expected when node was removed" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID createdEntityId = None deletedEntityId = None -class TestAreaNodeEntityDelete(EditorTestHelper): +def AreaNodes_EntityRemovedOnNodeDelete(): + """ + Summary: + This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="AreaNodeEntityDelete", args=["level"]) + Expected Behavior: + Entities are removed when area nodes are deleted from a graph. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the area nodes to the graph area, and ensure a new entity is created + 4) Delete the nodes, and ensure the newly created entities are removed - Expected Behavior: - Entities are removed when area nodes are deleted from a graph. + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the area nodes to the graph area, and ensure a new entity is created - 4) Delete the nodes, and ensure the newly created entities are removed + :return: None + """ - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math + import azlmbr.paths - :return: None - """ - def onEntityCreated(parameters): - global createdEntityId - createdEntityId = parameters[0] + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def onEntityDeleted(parameters): - global deletedEntityId - deletedEntityId = parameters[0] + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + def onEntityCreated(parameters): + global createdEntityId + createdEntityId = parameters[0] - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityDeleted(parameters): + global deletedEntityId + deletedEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can check if the entity created - # from adding gradient nodes has the appropriate Gradient Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) - handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Vegetation Area mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - areas = [ - 'AreaBlenderNode', - 'BlockerAreaNode', - 'MeshBlockerAreaNode', - 'SpawnerAreaNode', - ] + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Create nodes for all the gradients we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in areas: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Listen for entity creation notifications so we can check if the entity created + # from adding gradient nodes has the appropriate Gradient Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) + handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) - removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) + # Vegetation Area mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + areas = [ + 'AreaBlenderNode', + 'BlockerAreaNode', + 'MeshBlockerAreaNode', + 'SpawnerAreaNode', + ] - # Verify that the created Entity for this node matches the Entity that gets - # deleted when the node is removed - self.test_success = self.test_success and removed and createdEntityId.invoke("Equal", deletedEntityId) - if removed and createdEntityId.invoke("Equal", deletedEntityId): - self.log("{node} corresponding Entity was deleted when node is removed".format(node=nodeName)) + # Create nodes for all the gradients we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in areas: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, + nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - # Stop listening for entity creation notifications - handler.disconnect() + removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) + + # Verify that the created Entity for this node matches the Entity that gets + # deleted when the node is removed + Report.info(f"Node: {nodeName}") + Report.result(Tests.entity_deleted, removed and createdEntityId.invoke("Equal", deletedEntityId)) + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestAreaNodeEntityDelete() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(AreaNodes_EntityRemovedOnNodeDelete) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py index a704cc9dab..cc40d8b861 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py @@ -5,197 +5,209 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.asset as asset -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.legacy.general as general -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.math as math -import azlmbr.slice as slice -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper +class Tests: + slice_instantiated = ( + "Slice instantiated successfully", + "Failed to instantiate slice" + ) + lc_entity_found = ( + "LandscapeCanvas entity found", + "Failed to find LandscapeCanvas entity" + ) + spawner_entity_found = ( + "BushSpawner entity found", + "Failed to find BushSpawner entity" + ) + dist_filter_component_found = ( + "Vegetation Distribution Filter component on BushSpawner entity found", + "Failed to find Distribution Filter component on BushSpawner entity" + ) + existing_graph_opened = ( + "Opened existing graph from slice", + "Failed to open existing graph" + ) + dist_filter_node_found = ( + "Vegetation Distribution Filter node found on graph", + "Failed to find Distribution Filter node on graph" + ) + alt_filter_component_found = ( + "Vegetation Altitude Filter component on BushSpawner entity found", + "Failed to find Altitude Filter component on BushSpawner entity" + ) + alt_filter_node_found = ( + "Vegetation Altitude Filter node found on graph", + "Failed to find Altitude Filter node on graph" + ) + dist_filter_component_removed = ( + "Vegetation Distribution Filter component removed from BushSpawner entity", + "Failed to remove Distribution Filter component from BushSpawner entity" + ) + dist_filter_node_removed = ( + "Vegetation Distribution Filter node removed from graph", + "Failed to remove Distribution Filter node from graph" + ) + child_entity_added = ( + "New entity successfully added as a child of the BushSpawner entity", + "New entity added with an unexpected parent" + ) + box_shape_component_found = ( + "Box Shape component on Box entity found", + "Failed to find Box Shape component on Box entity" + ) + box_shape_node_found = ( + "Box Shape node found on graph", + "Failed to find Box Shape node on graph" + ) -class TestComponentUpdatesUpdateGraph(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="ComponentUpdatesUpdateGraph", args=["level"]) +def ComponentUpdates_UpdateGraph(): + """ + Summary: + This test verifies that the Landscape Canvas graphs update properly when components are added/removed outside of + Landscape Canvas. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas graphs update properly when components are added/removed outside of - Landscape Canvas. + Expected Behavior: + Graphs properly reflect component changes made to entities outside of Landscape Canvas. - Expected Behavior: - Graphs properly reflect component changes made to entities outside of Landscape Canvas. + Test Steps: + 1. Open Level + 2. Find LandscapeCanvas named entity + 3. Ensure Vegetation Distribution Component is present on the BushSpawner entity + 4. Open graph and ensure Distribution Filter wrapped node is present + 5. Delete the Vegetation Distribution Filter component from the BushSpawner entity via Entity Inspector + 6. Ensure the Vegetation Distribution Filter component was deleted from the BushSpawner entity and node is + no longer present in the graph + 7. Add Vegetation Altitude Filter to the BushSpawner entity through Entity Inspector + 8. Ensure Altitude Filter was added to the BushSpawner node in the open graph + 9. Add a new entity with unique name as a child of the Landscape Canvas entity + 10. Add a Box Shape component to the new child entity + 11. Ensure Box Shape node is present on the open graph - Test Steps: - 1. Open Level - 2. Find LandscapeCanvas named entity - 3. Ensure Vegetation Distribution Component is present on the BushSpawner entity - 4. Open graph and ensure Distribution Filter wrapped node is present - 5. Delete the Vegetation Distribution Filter component from the BushSpawner entity via Entity Inspector - 6. Ensure the Vegetation Distribution Filter component was deleted from the BushSpawner entity and node is - no longer present in the graph - 7. Add Vegetation Altitude Filter to the BushSpawner entity through Entity Inspector - 8. Ensure Altitude Filter was added to the BushSpawner node in the open graph - 9. Add a new entity with unique name as a child of the Landscape Canvas entity - 10. Add a Box Shape component to the new child entity - 11. Ensure Box Shape node is present on the open graph + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ + import os - # Create a new empty level and instantiate LC_BushFlowerBlender.slice - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - transform = math.Transform_CreateIdentity() - position = math.Vector3(64.0, 64.0, 32.0) - transform.invoke('SetPosition', position) - test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") - test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), - False) - test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) - self.test_success = self.test_success and test_slice.IsValid() - if test_slice.IsValid(): - self.log("Slice spawned!") + import azlmbr.asset as asset + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + import azlmbr.legacy.general as general + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.math as math + import azlmbr.slice as slice - # Find root entity in the loaded level - search_filter = entity.SearchFilter() - search_filter.names = ["LandscapeCanvas"] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Allow a few seconds for matching entity to be found - self.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, 5.0) - lc_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) - slice_root_id = lc_matching_entities[0] #Entity with Landscape Canvas component - self.test_success = self.test_success and slice_root_id.IsValid() - if slice_root_id.IsValid(): - self.log("LandscapeCanvas entity found") + # Open a simple level and instantiate LC_BushFlowerBlender.slice + helper.init_idle() + helper.open_level("Physics", "Base") + transform = math.Transform_CreateIdentity() + position = math.Vector3(64.0, 64.0, 32.0) + transform.invoke('SetPosition', position) + test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") + test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), + False) + test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) + Report.critical_result(Tests.slice_instantiated, test_slice.IsValid()) - # Find the BushSpawner entity - search_filter.names = ["BushSpawner"] - spawner_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) - spawner_id = spawner_matching_entities[0] #Entity with Vegetation Layer Spawner component - self.test_success = self.test_success and spawner_id.IsValid() - if spawner_id.IsValid(): - self.log("BushSpawner entity found") + # Find root entity in the loaded level + search_filter = entity.SearchFilter() + search_filter.names = ["LandscapeCanvas"] - # Get needed component type ids - distribution_filter_type_id = hydra.get_component_type_id("Vegetation Distribution Filter") - altitude_filter_type_id = hydra.get_component_type_id("Vegetation Altitude Filter") - box_shape_type_id = hydra.get_component_type_id("Box Shape") + # Allow a few seconds for matching entity to be found + helper.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, 5.0) + lc_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) + slice_root_id = lc_matching_entities[0] #Entity with Landscape Canvas component + Report.critical_result(Tests.lc_entity_found, slice_root_id.IsValid()) - # Verify the BushSpawner entity has a Distribution Filter - has_distribution_filter = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', spawner_id, - distribution_filter_type_id) - self.test_success = self.test_success and has_distribution_filter - if has_distribution_filter: - self.log("Vegetation Distribution Filter on BushSpawner entity found") + # Find the BushSpawner entity + search_filter.names = ["BushSpawner"] + spawner_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) + spawner_id = spawner_matching_entities[0] #Entity with Vegetation Layer Spawner component + Report.critical_result(Tests.spawner_entity_found, spawner_id.IsValid()) - # Open Landscape Canvas and the existing graph - general.open_pane('Landscape Canvas') - open_graph = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) - self.test_success = self.test_success and open_graph.IsValid() - if open_graph.IsValid(): - self.log("Graph opened") + # Get needed component type ids + distribution_filter_type_id = hydra.get_component_type_id("Vegetation Distribution Filter") + altitude_filter_type_id = hydra.get_component_type_id("Vegetation Altitude Filter") + box_shape_type_id = hydra.get_component_type_id("Box Shape") - # Verify that Distribution Filter node is present on the graph - spawner_distribution_filter_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', spawner_id, - distribution_filter_type_id) - spawner_distribution_filter_component_id = spawner_distribution_filter_component.GetValue() - distribution_filter_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, - 'GetNodeMatchingEntityComponentInGraph', - open_graph, - spawner_distribution_filter_component_id) - self.test_success = self.test_success and distribution_filter_node is not None - if distribution_filter_node is not None: - self.log("Distribution Filter node found on graph") - else: - self.log("Distribution Filter node not found on graph") + # Verify the BushSpawner entity has a Distribution Filter + has_distribution_filter = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', spawner_id, + distribution_filter_type_id) + Report.critical_result(Tests.dist_filter_component_found, has_distribution_filter) - # Add a Vegetation Altitude Filter component to the BushSpawner entity, and verify the node is added to the graph - spawner_altitude_filter_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', spawner_id, - altitude_filter_type_id) - spawner_altitude_filter_component_id = spawner_altitude_filter_component.GetValue() - editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentOfType', spawner_id, altitude_filter_type_id) - has_altitude_filter = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', spawner_id, - altitude_filter_type_id) - altitude_filter_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetNodeMatchingEntityComponentInGraph', - open_graph, spawner_altitude_filter_component_id) - self.test_success = self.test_success and has_altitude_filter and altitude_filter_node is not None - if has_altitude_filter: - self.log("Vegetation Altitude Filter on BushSpawner entity found") + # Open Landscape Canvas and the existing graph + general.open_pane('Landscape Canvas') + open_graph = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) + Report.critical_result(Tests.existing_graph_opened, open_graph.IsValid()) - if altitude_filter_node is not None: - self.log("Altitude Filter node found on graph") - else: - self.log("Altitude Filter node not found on graph") + # Verify that Distribution Filter node is present on the graph + spawner_distribution_filter_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', spawner_id, + distribution_filter_type_id) + spawner_distribution_filter_component_id = spawner_distribution_filter_component.GetValue() + distribution_filter_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, + 'GetNodeMatchingEntityComponentInGraph', + open_graph, + spawner_distribution_filter_component_id) + Report.critical_result(Tests.dist_filter_node_found, distribution_filter_node is not None) - # Remove the Distribution Filter - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [spawner_distribution_filter_component_id]) - general.idle_wait(1.0) + # Add a Vegetation Altitude Filter component to the BushSpawner entity, and verify the node is added to the graph + spawner_altitude_filter_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', spawner_id, + altitude_filter_type_id) + spawner_altitude_filter_component_id = spawner_altitude_filter_component.GetValue() + editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentOfType', spawner_id, altitude_filter_type_id) + has_altitude_filter = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', spawner_id, + altitude_filter_type_id) + altitude_filter_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetNodeMatchingEntityComponentInGraph', + open_graph, spawner_altitude_filter_component_id) + Report.result(Tests.dist_filter_component_found, has_altitude_filter) + Report.result(Tests.dist_filter_node_found, altitude_filter_node is not None) - # Verify the Distribution Filter was successfully removed from entity and the node was likewise removed - has_distribution_filter = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', spawner_id, - distribution_filter_type_id) - self.test_success = self.test_success and not has_distribution_filter - if not has_distribution_filter: - self.log("Vegetation Distribution Filter removed from BushSpawner entity") + # Remove the Distribution Filter + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [spawner_distribution_filter_component_id]) + general.idle_wait(1.0) - distribution_filter_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, - 'GetAllNodesMatchingEntityComponent', - spawner_distribution_filter_component_id) - self.test_success = self.test_success and not distribution_filter_node - if distribution_filter_node: - self.log("Distribution Filter node is still present on the graph") - else: - self.log("Distribution Filter node was removed from the graph") + # Verify the Distribution Filter was successfully removed from entity and the node was likewise removed + has_distribution_filter = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', spawner_id, + distribution_filter_type_id) + Report.result(Tests.dist_filter_component_removed, not has_distribution_filter) - # Add a new child entity of BushSpawner entity - box_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', spawner_id) - if editor.EditorEntityInfoRequestBus(bus.Event, 'GetParent', box_id) == spawner_id: - self.log("New entity successfully added as a child of the BushSpawner entity") - else: - self.log("New entity added with an unexpected parent") + distribution_filter_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, + 'GetAllNodesMatchingEntityComponent', + spawner_distribution_filter_component_id) + Report.result(Tests.dist_filter_node_removed, not distribution_filter_node) - # Add a Box Shape component to the new entity and verify it was properly added - editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentOfType', box_id, box_shape_type_id) - has_box_shape = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', box_id, - box_shape_type_id) - self.test_success = self.test_success and has_box_shape - if has_box_shape: - self.log("Box Shape on Box entity found") + # Add a new child entity of BushSpawner entity + box_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', spawner_id) + Report.result(Tests.child_entity_added, editor.EditorEntityInfoRequestBus(bus.Event, 'GetParent', box_id) == + spawner_id) - # Verify the Box Shape node appear on the graph - box_shape_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', box_id, - box_shape_type_id) + # Add a Box Shape component to the new entity and verify it was properly added + editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentOfType', box_id, box_shape_type_id) + has_box_shape = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', box_id, + box_shape_type_id) + Report.result(Tests.box_shape_component_found, has_box_shape) - box_shape_component_id = box_shape_component.GetValue() - box_shape_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetAllNodesMatchingEntityComponent', - box_shape_component_id) - self.test_success = self.test_success and box_shape_node is not None - if box_shape_node is not None: - self.log("Box Shape node found on graph") - else: - self.log("Box Shape node not found on graph") + # Verify the Box Shape node appears on the graph + box_shape_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', box_id, + box_shape_type_id) + + box_shape_component_id = box_shape_component.GetValue() + box_shape_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetAllNodesMatchingEntityComponent', + box_shape_component_id) + Report.result(Tests.box_shape_node_found, box_shape_node is not None) -test = TestComponentUpdatesUpdateGraph() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(ComponentUpdates_UpdateGraph) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Component_AddedRemoved.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Component_AddedRemoved.py new file mode 100644 index 0000000000..7f21a26595 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Component_AddedRemoved.py @@ -0,0 +1,80 @@ +""" +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. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + + +class Tests: + lc_component_added = ( + "Landscape Canvas component successfully added to entity", + "Failed to add Landscape Canvas component to entity" + ) + lc_component_removed = ( + "Landscape Canvas component successfully removed from entity", + "Failed to remove Landscape Canvas component from entity" + ) + + +def Component_AddedRemoved(): + """ + Summary: + This test verifies that the Landscape Canvas component can be added to/removed from an entity. + + Expected Behavior: + Closing a tabbed graph only closes the appropriate graph. + + Test Steps: + 1) Open a simple level + 2) Create a new entity + 3) Add a Landscape Canvas component to the entity + 4) Remove the Landscape Canvas component from the entity + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Create an Entity at the root of the level + newEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + + # Find the component TypeId for our Landscape Canvas component + landscape_canvas_type_id = hydra.get_component_type_id("Landscape Canvas") + + # Add the Landscape Canvas Component to our Entity + componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', newEntityId, [landscape_canvas_type_id]) + components = componentOutcome.GetValue() + landscapeCanvasComponent = components[0] + + # Validate the Landscape Canvas Component exists + hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, landscape_canvas_type_id) + Report.result(Tests.lc_component_added, hasComponent) + + # Remove the Landscape Canvas Component + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [landscapeCanvasComponent]) + + # Validate the Landscape Canvas Component is no longer on our Entity + hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, landscape_canvas_type_id) + Report.result(Tests.lc_component_removed, not hasComponent) + + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(Component_AddedRemoved) \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/CreateNewGraph.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/CreateNewGraph.py deleted file mode 100755 index 971134becf..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/CreateNewGraph.py +++ /dev/null @@ -1,106 +0,0 @@ -""" -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. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.legacy.general as general -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper - -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID -new_root_entity_id = None - - -class TestCreateNewGraph(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="CreateNewGraph", args=["level"]) - - def on_entity_created(self, parameters): - global new_root_entity_id - new_root_entity_id = parameters[0] - - print("New root entity created") - - def run_test(self): - """ - Summary: - This test verifies that new graphs can be created in Landscape Canvas. - - Expected Behavior: - New graphs can be created, and proper entity is created to hold graph data with a Landscape Canvas component. - - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Ensures the root entity created contains a Landscape Canvas component - - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. - - :return: None - """ - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - # Open Landscape Canvas tool and verify - general.open_pane("Landscape Canvas") - self.test_success = self.test_success and general.is_pane_visible("Landscape Canvas") - if general.is_pane_visible("Landscape Canvas"): - self.log("Landscape Canvas pane is open") - - # Listen for entity creation notifications so we can check if the entity created - # with the new graph has our Landscape Canvas component automatically added - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback("OnEditorEntityCreated", self.on_entity_created) - - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, "CreateNewGraph", editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") - - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, "ContainsGraph", editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") - - # Check if the entity created when we create a new graph has the - # Landscape Canvas component already added to it - landscape_canvas_type_id = hydra.get_component_type_id("Landscape Canvas") - success = editor.EditorComponentAPIBus(bus.Broadcast, "HasComponentOfType", new_root_entity_id, - landscape_canvas_type_id) - self.test_success = self.test_success and success - if success: - self.log("Root entity has Landscape Canvas component") - - # Close Landscape Canvas tool and verify - general.close_pane("Landscape Canvas") - self.test_success = self.test_success and not general.is_pane_visible("Landscape Canvas") - if not general.is_pane_visible("Landscape Canvas"): - self.log("Landscape Canvas pane is closed") - - # Stop listening for entity creation notifications - handler.disconnect() - - -test = TestCreateNewGraph() -test.run() diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py index b2b9e63a56..417e093567 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py @@ -5,131 +5,132 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestDisabledNodeDuplication(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="DisabledNodeDuplication", args=["level"]) +def Edit_DisabledNodeDuplication(): + """ + Summary: + This test verifies Editor stability after duplicating disabled Landscape Canvas nodes. - def run_test(self): - """ - Summary: - This test verifies Editor stability after duplicating disabled Landscape Canvas nodes. + Expected Behavior: + Editor remains stable and free of crashes. - Expected Behavior: - Editor remains stable and free of crashes. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Create several new nodes, disable the nodes via disabling/deleting components, and duplicate the nodes - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Create several new nodes, disable the nodes via disabling/deleting components, and duplicate the nodes + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Listen for entity creation notifications so when we add a new node - # we can access the corresponding Entity that was created so that we - # can disable/remove components on that Entity - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Mapping of our Landscape Canvas nodes with corresponding dependent components - # that we can disable/remove to reproduce the crash - nodes = { - 'SpawnerAreaNode': 'Vegetation Asset List', - 'MeshBlockerAreaNode': 'Mesh', - 'BlockerAreaNode': 'Vegetation Reference Shape', - 'FastNoiseGradientNode': 'Gradient Transform Modifier', - 'ImageGradientNode': 'Gradient Transform Modifier', - 'PerlinNoiseGradientNode': 'Gradient Transform Modifier', - 'RandomNoiseGradientNode': 'Gradient Transform Modifier' - } + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = list(set(nodes.values())) # Convert to set then back to list to remove any duplicates - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Iterate through creating our nodes and then disabling/deleting required components - # and then duplicating the node to reproduce the crash - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in nodes: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Listen for entity creation notifications so when we add a new node + # we can access the corresponding Entity that was created so that we + # can disable/remove components on that Entity + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - dependentComponentName = nodes[nodeName] - componentTypeId = componentTypeIds[dependentComponentName] - componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', newEntityId, componentTypeId) - component = componentOutcome.GetValue() + # Mapping of our Landscape Canvas nodes with corresponding dependent components + # that we can disable/remove to reproduce the crash + nodes = { + 'SpawnerAreaNode': 'Vegetation Asset List', + 'MeshBlockerAreaNode': 'Mesh', + 'BlockerAreaNode': 'Vegetation Reference Shape', + 'FastNoiseGradientNode': 'Gradient Transform Modifier', + 'ImageGradientNode': 'Gradient Transform Modifier', + 'PerlinNoiseGradientNode': 'Gradient Transform Modifier', + 'RandomNoiseGradientNode': 'Gradient Transform Modifier' + } - # First make sure we can duplicate a node with a dependent component that is disabled - editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [component]) - general.idle_wait(1.0) - graph.SceneRequestBus(bus.Event, 'DuplicateSelection', newGraphId) # This duplication would cause a crash without the fix - self.log("{node} duplicated with disabled component".format(node=nodeName)) + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = list(set(nodes.values())) # Convert to set then back to list to remove any duplicates + componentTypeIds = hydra.get_component_type_id_map(componentNames) - # Then, make sure we can duplicate the node with a dependent component that is deleted - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [component]) - general.idle_wait(1.0) - graph.SceneRequestBus(bus.Event, 'DuplicateSelection', newGraphId) # This duplication would cause a crash without the fix - self.log("{node} duplicated with deleted component".format(node=nodeName)) + # Iterate through creating our nodes and then disabling/deleting required components + # and then duplicating the node to reproduce the crash + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in nodes: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - x += 40.0 - y += 40.0 + dependentComponentName = nodes[nodeName] + componentTypeId = componentTypeIds[dependentComponentName] + componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', newEntityId, componentTypeId) + component = componentOutcome.GetValue() - # Stop listening for entity creation notifications - handler.disconnect() + # First make sure we can duplicate a node with a dependent component that is disabled + editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [component]) + helper.wait_for_condition(lambda: not editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', + [component]), 1.0) + graph.SceneRequestBus(bus.Event, 'DuplicateSelection', newGraphId) # This duplication would cause a crash without the fix + Report.info("{node} duplicated with disabled component".format(node=nodeName)) + + # Then, make sure we can duplicate the node with a dependent component that is deleted + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [component]) + helper.wait_for_condition(lambda: not editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', + componentTypeIds[dependentComponentName]), 1.0) + graph.SceneRequestBus(bus.Event, 'DuplicateSelection', newGraphId) # This duplication would cause a crash without the fix + Report.info("{node} duplicated with deleted component".format(node=nodeName)) + + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestDisabledNodeDuplication() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(Edit_DisabledNodeDuplication) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py index a651567f85..a26e16755f 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py @@ -5,133 +5,134 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.asset as asset -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.legacy.general as general -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.math as math -import azlmbr.slice as slice -import azlmbr.paths +class Tests: + slice_spawned = ( + "Slice instantiated successfully", + "Failed to instantiate slice" + ) + lc_entity_found = ( + "Landscape Canvas entity found", + "Failed to find Landscape Canvas entity" + ) + spawner_entity_found = ( + "Spawner entity found", + "Failed to find Spawner entity" + ) + graph_opened = ( + "Graph successfully opened", + "Graph failed to open" + ) + spawner_node_found = ( + "Vegetation Layer Spawner node found on graph", + "Failed to find Vegetation Layer Spawner node on graph" + ) + spawner_node_removed = ( + "Vegetation Layer Spawner node was successfully removed", + "Failed to remove Vegetation Layer Spawner node" + ) +def Edit_UndoNodeDelete_SliceEntity(): + """ + Summary: + This test verifies Editor stability after undoing the deletion of nodes on a slice entity. -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper + Expected Behavior: + Editor remains stable and free of crashes. + + Test Steps: + 1) Open a simple level + 2) Instantiate a slice with a Landscape Canvas setup + 3) Find a specific node on the graph, and delete it + 4) Restore the node with Undo + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + + import os + + import azlmbr.asset as asset + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + import azlmbr.legacy.general as general + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.math as math + import azlmbr.slice as slice + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Instantiate slice + transform = math.Transform_CreateIdentity() + position = math.Vector3(64.0, 64.0, 32.0) + transform.invoke('SetPosition', position) + test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") + test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), + False) + test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) + Report.result(Tests.slice_spawned, test_slice.IsValid()) + + # Find root entity in the loaded level + search_filter = entity.SearchFilter() + search_filter.names = ["LandscapeCanvas"] + + # Allow a few seconds for matching entity to be found + helper.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, 5.0) + lc_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) + slice_root_id = lc_matching_entities[0] # Entity with Landscape Canvas component + Report.result(Tests.lc_entity_found, slice_root_id.IsValid()) + + # Find the BushSpawner entity + search_filter.names = ["BushSpawner"] + spawner_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) + spawner_id = spawner_matching_entities[0] # Entity with Vegetation Layer Spawner component + Report.result(Tests.spawner_entity_found, spawner_id.IsValid()) + + # Open Landscape Canvas and the existing graph + general.open_pane('Landscape Canvas') + open_graph = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) + Report.result(Tests.graph_opened, open_graph.IsValid()) + + # Get needed component type ids + layer_spawner_type_id = hydra.get_component_type_id("Vegetation Layer Spawner") + + # Find the Vegetation Layer Spawner node on the BushSpawner entity + layer_spawner_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', spawner_id, + layer_spawner_type_id) + layer_spawner_component_component_id = layer_spawner_component.GetValue() + layer_spawner_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetAllNodesMatchingEntityComponent', + layer_spawner_component_component_id) + Report.result(Tests.spawner_node_found, layer_spawner_node is not None) + + # Remove the Layer Spawner node + graph.GraphControllerRequestBus(bus.Event, "RemoveNode", open_graph, layer_spawner_node[0]) + + # Verify node was removed + layer_spawner_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetAllNodesMatchingEntityComponent', + layer_spawner_component_component_id) + Report.result(Tests.spawner_node_removed, not layer_spawner_node) + + # Undo the Node deletion. This is required to be executed twice to hit the node removal. + general.undo() + general.undo() + + # self.log a line to the Console to verify the Editor is still active + Report.info("Editor is still responsive") -class TestUndoNodeDeleteSlice(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="UndoNodeDeleteSlice", args=["level"]) +if __name__ == "__main__": - def run_test(self): - """ - Summary: - This test verifies Editor stability after undoing the deletion of nodes on a slice entity. + from editor_python_test_tools.utils import Report + Report.start_test(Edit_UndoNodeDelete_SliceEntity) - Expected Behavior: - Editor remains stable and free of crashes. - - Test Steps: - 1) Create a new level - 2) Instantiate a slice with a Landscape Canvas setup - 3) Find a specific node on the graph, and delete it - 4) Restore the node with Undo - - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. - - :return: None - """ - # Create a new empty level and instantiate LC_BushFlowerBlender.slice - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - transform = math.Transform_CreateIdentity() - position = math.Vector3(64.0, 64.0, 32.0) - transform.invoke('SetPosition', position) - test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") - test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), - False) - test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) - self.test_success = self.test_success and test_slice.IsValid() - if test_slice.IsValid(): - self.log("Slice spawned!") - - # Find root entity in the loaded level - search_filter = entity.SearchFilter() - search_filter.names = ["LandscapeCanvas"] - - # Allow a few seconds for matching entity to be found - self.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, - 5.0) - lc_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) - slice_root_id = lc_matching_entities[0] # Entity with Landscape Canvas component - self.test_success = self.test_success and slice_root_id.IsValid() - if slice_root_id.IsValid(): - self.log("LandscapeCanvas entity found") - - # Find the BushSpawner entity - search_filter.names = ["BushSpawner"] - spawner_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) - spawner_id = spawner_matching_entities[0] # Entity with Vegetation Layer Spawner component - self.test_success = self.test_success and spawner_id.IsValid() - if spawner_id.IsValid(): - self.log("BushSpawner entity found") - - # Open Landscape Canvas and the existing graph - general.open_pane('Landscape Canvas') - open_graph = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) - self.test_success = self.test_success and open_graph.IsValid() - if open_graph.IsValid(): - self.log("Graph opened") - - # Get needed component type ids - layer_spawner_type_id = hydra.get_component_type_id("Vegetation Layer Spawner") - - # Find the Vegetation Layer Spawner node on the BushSpawner entity - layer_spawner_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', spawner_id, - layer_spawner_type_id) - layer_spawner_component_component_id = layer_spawner_component.GetValue() - layer_spawner_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetAllNodesMatchingEntityComponent', - layer_spawner_component_component_id) - - self.test_success = self.test_success and layer_spawner_node - if layer_spawner_node: - self.log("Vegetation Layer Spawner node found on graph") - else: - self.log("Vegetation Layer Spawner node not found") - - # Remove the Layer Spawner node - graph.GraphControllerRequestBus(bus.Event, "RemoveNode", open_graph, layer_spawner_node[0]) - - # Verify node was removed - layer_spawner_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetAllNodesMatchingEntityComponent', - layer_spawner_component_component_id) - - self.test_success = self.test_success and not layer_spawner_node - if not layer_spawner_node: - self.log("Vegetation Layer Spawner node was removed") - else: - self.log("Vegetation Layer Spawner node was not removed") - - # Undo the Node deletion. This is required to be executed twice to hit the node removal. - general.undo() - general.undo() - - # self.log a line to the Console to verify the Editor is still active - self.log("Editor is still responsive") - - -test = TestUndoNodeDeleteSlice() -test.run() diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py index 341e6d3367..c390df7c61 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py @@ -5,190 +5,205 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.entity as entity -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + preview_entity_set = ( + "Perlin Noise Gradient component Preview Entity property set to Box Shape EntityId", + "Unexpected entity set in Perlin Noise Gradient Preview Entity property" + ) + mixer_inbound_gradient_set_a = ( + "Gradient Mixer component Inbound Gradient extendable property set to Perlin Noise Gradient EntityId", + "Unexpected entity set in Gradient Mixer's Inbound Gradient property" + ) + mixer_inbound_gradient_set_b = ( + "Gradient Mixer component Inbound Gradient extendable property set to FastNoise Gradient EntityId", + "Unexpected entity set in Gradient Mixer's Inbound Gradient property" + ) + mixer_operation_a = ( + "Layer 1 Operation is set to Initialize", + "Layer 1 Operation is not set to Initialize as expected" + ) + mixer_operation_b = ( + "Layer 2 Operation is set to Average", + "Layer 2 Operation is not set to Average as expected" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper - -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestGradientMixerNodeConstruction(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientMixerNodeConstruction", args=["level"]) +def GradientMixer_NodeConstruction(): + """ + Summary: + This test verifies a Gradient Mixer vegetation setup can be constructed through Landscape Canvas. - def run_test(self): - """ - Summary: - This test verifies a Gradient Mixer vegetation setup can be constructed through Landscape Canvas. + Expected Behavior: + Entities contain all required components and component references after creating nodes and setting connections + on a Landscape Canvas graph. - Expected Behavior: - Entities contain all required components and component references after creating nodes and setting connections - on a Landscape Canvas graph. + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Add all necessary nodes to the graph and set connections to form a Gradient Mixer setup + 4) Verify all components and component references were properly set during graph construction - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Add all necessary nodes to the graph and set connections to form a Gradient Mixer setup - 4) Verify all components and component references were properly set during graph construction + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math + import azlmbr.paths - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can verify the component EntityId - # references are set correctly when connecting slots on the nodes - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - positionX = 10.0 - positionY = 10.0 - offsetX = 340.0 - offsetY = 100.0 + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Add a Box Shape node to the graph - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - boxShapeNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, - 'BoxShapeNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, boxShapeNode, math.Vector2(positionX, positionY)) - boxShapeEntityId = newEntityId + # Listen for entity creation notifications so we can verify the component EntityId + # references are set correctly when connecting slots on the nodes + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - positionX += offsetX - positionY += offsetY + positionX = 10.0 + positionY = 10.0 + offsetX = 340.0 + offsetY = 100.0 - # Add a Random Noise Gradient node to the graph - perlinNoiseNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, - 'PerlinNoiseGradientNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, perlinNoiseNode, math.Vector2(positionX, positionY)) - perlinNoiseEntityId = newEntityId + # Add a Box Shape node to the graph + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + boxShapeNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, + 'BoxShapeNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, boxShapeNode, math.Vector2(positionX, positionY)) + boxShapeEntityId = newEntityId - positionX += offsetX - positionY += offsetY + positionX += offsetX + positionY += offsetY - # Add a FastNoise Gradient node to the graph - fastNoiseNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, - 'FastNoiseGradientNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, fastNoiseNode, math.Vector2(positionX, positionY)) - fastNoiseEntityId = newEntityId + # Add a Random Noise Gradient node to the graph + perlinNoiseNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, + 'PerlinNoiseGradientNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, perlinNoiseNode, math.Vector2(positionX, positionY)) + perlinNoiseEntityId = newEntityId - positionX += offsetX - positionY += offsetY + positionX += offsetX + positionY += offsetY - # Add a Gradient Mixer node to the graph - gradientMixerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, - 'GradientMixerNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, gradientMixerNode, math.Vector2(positionX, positionY)) - gradientMixerEntityId = newEntityId + # Add a FastNoise Gradient node to the graph + fastNoiseNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, + 'FastNoiseGradientNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, fastNoiseNode, math.Vector2(positionX, positionY)) + fastNoiseEntityId = newEntityId - boundsSlotId = graph.GraphModelSlotId('Bounds') - previewBoundsSlotId = graph.GraphModelSlotId('PreviewBounds') - inboundGradientSlotId = graph.GraphModelSlotId('InboundGradient') - outboundGradientSlotId = graph.GraphModelSlotId('OutboundGradient') - inboundGradientSlotId2 = graph.GraphControllerRequestBus(bus.Event, 'ExtendSlot', newGraphId, gradientMixerNode, - 'InboundGradient') + positionX += offsetX + positionY += offsetY - # Connect slots on our nodes to construct a Gradient Mixer hierarchy - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, - perlinNoiseNode, previewBoundsSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, - fastNoiseNode, previewBoundsSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, - gradientMixerNode, previewBoundsSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, perlinNoiseNode, outboundGradientSlotId, - gradientMixerNode, inboundGradientSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, fastNoiseNode, outboundGradientSlotId, - gradientMixerNode, inboundGradientSlotId2) + # Add a Gradient Mixer node to the graph + gradientMixerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, + 'GradientMixerNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, gradientMixerNode, math.Vector2(positionX, positionY)) + gradientMixerEntityId = newEntityId - # Delay to allow all the underlying component properties to be updated after the slot connections are made - general.idle_wait(1.0) + boundsSlotId = graph.GraphModelSlotId('Bounds') + previewBoundsSlotId = graph.GraphModelSlotId('PreviewBounds') + inboundGradientSlotId = graph.GraphModelSlotId('InboundGradient') + outboundGradientSlotId = graph.GraphModelSlotId('OutboundGradient') + inboundGradientSlotId2 = graph.GraphControllerRequestBus(bus.Event, 'ExtendSlot', newGraphId, gradientMixerNode, + 'InboundGradient') - # Get component info - gradientMixerTypeId = hydra.get_component_type_id("Gradient Mixer") - perlinNoiseTypeId = hydra.get_component_type_id("Perlin Noise Gradient") - gradientMixerOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', gradientMixerEntityId, - gradientMixerTypeId) - gradientMixerComponent = gradientMixerOutcome.GetValue() - perlinNoiseOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', perlinNoiseEntityId, - perlinNoiseTypeId) - perlinNoiseComponent = perlinNoiseOutcome.GetValue() + # Connect slots on our nodes to construct a Gradient Mixer hierarchy + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, + perlinNoiseNode, previewBoundsSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, + fastNoiseNode, previewBoundsSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, + gradientMixerNode, previewBoundsSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, perlinNoiseNode, outboundGradientSlotId, + gradientMixerNode, inboundGradientSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, fastNoiseNode, outboundGradientSlotId, + gradientMixerNode, inboundGradientSlotId2) - # Verify the Preview EntityId property on our Perlin Noise Gradient component has been set to our Box Shape's EntityId - previewEntityId = hydra.get_component_property_value(perlinNoiseComponent, 'Preview Settings|Pin Preview to Shape') - self.test_success = self.test_success and previewEntityId and boxShapeEntityId.invoke("Equal", previewEntityId) - if previewEntityId and boxShapeEntityId.invoke("Equal", previewEntityId): - self.log("Perlin Noise Gradient component Preview Entity property set to Box Shape EntityId") + # Delay to allow all the underlying component properties to be updated after the slot connections are made + general.idle_wait(1.0) - # Verify the 1st Inbound Gradient EntityId property on our Gradient Mixer component has been set to our Perlin Noise - # Gradient's EntityId - inboundGradientEntityId = hydra.get_component_property_value(gradientMixerComponent, - 'Configuration|Layers|[0]|Gradient|Gradient Entity Id') - self.test_success = self.test_success and inboundGradientEntityId and perlinNoiseEntityId.invoke("Equal", inboundGradientEntityId) - if inboundGradientEntityId and perlinNoiseEntityId.invoke("Equal", inboundGradientEntityId): - self.log("Gradient Mixer component Inbound Gradient extendable property set to Perlin Noise Gradient EntityId") + # Get component info + gradientMixerTypeId = hydra.get_component_type_id("Gradient Mixer") + perlinNoiseTypeId = hydra.get_component_type_id("Perlin Noise Gradient") + gradientMixerOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', gradientMixerEntityId, + gradientMixerTypeId) + gradientMixerComponent = gradientMixerOutcome.GetValue() + perlinNoiseOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', perlinNoiseEntityId, + perlinNoiseTypeId) + perlinNoiseComponent = perlinNoiseOutcome.GetValue() - # Verify the 2nd Inbound Gradient EntityId property on our Gradient Mixer component has been set to our FastNoise - # Gradient Modifier's EntityId - inboundGradientEntityId2 = hydra.get_component_property_value(gradientMixerComponent, - 'Configuration|Layers|[1]|Gradient|Gradient Entity Id') - self.test_success = self.test_success and inboundGradientEntityId2 and fastNoiseEntityId.invoke("Equal", inboundGradientEntityId2) - if inboundGradientEntityId2 and fastNoiseEntityId.invoke("Equal", inboundGradientEntityId2): - self.log("Gradient Mixer component Inbound Gradient extendable property set to FastNoise Gradient EntityId") + # Verify the Preview EntityId property on our Perlin Noise Gradient component has been set to our Box Shape's EntityId + previewEntityId = hydra.get_component_property_value(perlinNoiseComponent, 'Preview Settings|Pin Preview to Shape') + Report.result(Tests.preview_entity_set, previewEntityId and boxShapeEntityId.invoke("Equal", previewEntityId)) - # Verify that Gradient Mixer Layer Operations are properly set - hydra.get_component_property_value(gradientMixerComponent, 'Configuration|Layers|[0]|Operation') - hydra.get_component_property_value(gradientMixerComponent, 'Configuration|Layers|[1]|Operation') + # Verify the 1st Inbound Gradient EntityId property on our Gradient Mixer component has been set to our Perlin Noise + # Gradient's EntityId + inboundGradientEntityId = hydra.get_component_property_value(gradientMixerComponent, + 'Configuration|Layers|[0]|Gradient|Gradient Entity Id') + Report.result(Tests.mixer_inbound_gradient_set_a, inboundGradientEntityId and perlinNoiseEntityId.invoke("Equal", inboundGradientEntityId)) - # Stop listening for entity creation notifications - handler.disconnect() + # Verify the 2nd Inbound Gradient EntityId property on our Gradient Mixer component has been set to our FastNoise + # Gradient Modifier's EntityId + inboundGradientEntityId2 = hydra.get_component_property_value(gradientMixerComponent, + 'Configuration|Layers|[1]|Gradient|Gradient Entity Id') + Report.result(Tests.mixer_inbound_gradient_set_b, inboundGradientEntityId2 and fastNoiseEntityId.invoke("Equal", inboundGradientEntityId2)) + + # Verify that Gradient Mixer Layer Operations are properly set + mixer_operation_a = hydra.get_component_property_value(gradientMixerComponent, 'Configuration|Layers|[0]|Operation') + mixer_operation_b = hydra.get_component_property_value(gradientMixerComponent, 'Configuration|Layers|[1]|Operation') + Report.result(Tests.mixer_operation_a, mixer_operation_a == 0) + Report.result(Tests.mixer_operation_b, mixer_operation_b == 6) + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientMixerNodeConstruction() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientMixer_NodeConstruction) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py index 43d39602be..c3952fe34b 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py @@ -5,132 +5,134 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + component_added = ( + "New entity created with the expected component", + "Expected component was not found on entity" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestGradientModifierNodeEntityCreate(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientModifierNodeEntityCreate", args=["level"]) +def GradientModifierNodes_EntityCreatedOnNodeAdd(): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. + Expected Behavior: + New entities are created when dragging Gradient Modifier nodes to graph area. - Expected Behavior: - New entities are created when dragging Gradient Modifier nodes to graph area. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure a new entity is created - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure a new entity is created + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can check if the entity created - # from adding gradient modifier nodes has the appropriate Gradient Modifier Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Gradient modifier mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - gradientModifiers = { - 'DitherGradientModifierNode': 'Dither Gradient Modifier', - 'GradientMixerNode': 'Gradient Mixer', - 'InvertGradientModifierNode': 'Invert Gradient Modifier', - 'LevelsGradientModifierNode': 'Levels Gradient Modifier', - 'PosterizeGradientModifierNode': 'Posterize Gradient Modifier', - 'SmoothStepGradientModifierNode': 'Smooth-Step Gradient Modifier', - 'ThresholdGradientModifierNode': 'Threshold Gradient Modifier' - } + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = [] - for name in gradientModifiers: - componentNames.append(gradientModifiers[name]) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Listen for entity creation notifications so we can check if the entity created + # from adding gradient modifier nodes has the appropriate Gradient Modifier Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - # Create nodes for all the gradients modifiers we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in gradientModifiers: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Gradient modifier mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + gradientModifiers = { + 'DitherGradientModifierNode': 'Dither Gradient Modifier', + 'GradientMixerNode': 'Gradient Mixer', + 'InvertGradientModifierNode': 'Invert Gradient Modifier', + 'LevelsGradientModifierNode': 'Levels Gradient Modifier', + 'PosterizeGradientModifierNode': 'Posterize Gradient Modifier', + 'SmoothStepGradientModifierNode': 'Smooth-Step Gradient Modifier', + 'ThresholdGradientModifierNode': 'Threshold Gradient Modifier' + } - gradientComponent = gradientModifiers[nodeName] - componentTypeId = componentTypeIds[gradientComponent] - hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, - componentTypeId) - self.test_success = self.test_success and hasComponent - if hasComponent: - self.log("{node} created new Entity with {component} Component".format(node=nodeName, - component=gradientComponent)) + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = [] + for name in gradientModifiers: + componentNames.append(gradientModifiers[name]) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - x += 40.0 - y += 40.0 + # Create nodes for all the gradients modifiers we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in gradientModifiers: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - # Stop listening for entity creation notifications - handler.disconnect() + gradientComponent = gradientModifiers[nodeName] + componentTypeId = componentTypeIds[gradientComponent] + hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, + componentTypeId) + Report.info(f"Node: {nodeName} | Component: {gradientComponent}") + Report.result(Tests.component_added, hasComponent) + + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientModifierNodeEntityCreate() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientModifierNodes_EntityCreatedOnNodeAdd) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py index f7b4dcf557..d7789a21fb 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py @@ -5,126 +5,129 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + entity_deleted = ( + "Entity was deleted when node was removed", + "Entity was not deleted as expected when node was removed" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID createdEntityId = None deletedEntityId = None -class TestGradientModifierNodeEntityDelete(EditorTestHelper): +def GradientModifierNodes_EntityRemovedOnNodeDelete(): + """ + Summary: + This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientModifierNodeEntityDelete", args=["level"]) + Expected Behavior: + Entities are removed when Gradient Modifier nodes are deleted from a graph. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure a new entity is created + 4) Delete the nodes, and ensure the newly created entities are removed - Expected Behavior: - Entities are removed when Gradient Modifier nodes are deleted from a graph. + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure a new entity is created - 4) Delete the nodes, and ensure the newly created entities are removed + :return: None + """ - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - :return: None - """ - def onEntityCreated(parameters): - global createdEntityId - createdEntityId = parameters[0] + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def onEntityDeleted(parameters): - global deletedEntityId - deletedEntityId = parameters[0] + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + def onEntityCreated(parameters): + global createdEntityId + createdEntityId = parameters[0] - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityDeleted(parameters): + global deletedEntityId + deletedEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can check if the entity created - # from adding gradient nodes has the appropriate Gradient Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) - handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Vegetation Area mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - gradientModifiers = [ - 'DitherGradientModifierNode', - 'GradientMixerNode', - 'InvertGradientModifierNode', - 'LevelsGradientModifierNode', - 'PosterizeGradientModifierNode', - 'SmoothStepGradientModifierNode', - 'ThresholdGradientModifierNode' - ] + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Create nodes for all the gradients we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in gradientModifiers: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Listen for entity creation notifications so we can check if the entity created + # from adding gradient nodes has the appropriate Gradient Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) + handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) - removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) + # Vegetation Area mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + gradientModifiers = [ + 'DitherGradientModifierNode', + 'GradientMixerNode', + 'InvertGradientModifierNode', + 'LevelsGradientModifierNode', + 'PosterizeGradientModifierNode', + 'SmoothStepGradientModifierNode', + 'ThresholdGradientModifierNode' + ] - # Verify that the created Entity for this node matches the Entity that gets - # deleted when the node is removed - self.test_success = self.test_success and removed and createdEntityId.invoke("Equal", deletedEntityId) - if removed and createdEntityId.invoke("Equal", deletedEntityId): - self.log("{node} corresponding Entity was deleted when node is removed".format(node=nodeName)) + # Create nodes for all the gradients we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in gradientModifiers: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - # Stop listening for entity creation notifications - handler.disconnect() + removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) + + # Verify that the created Entity for this node matches the Entity that gets + # deleted when the node is removed + Report.info(f"Node: {nodeName}") + Report.result(Tests.entity_deleted, removed and createdEntityId.invoke("Equal", deletedEntityId)) + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientModifierNodeEntityDelete() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientModifierNodes_EntityRemovedOnNodeDelete) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py index 96eac887cd..c04f9f05f6 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py @@ -5,141 +5,143 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + dependencies_added = ( + "Node created new Entity with all required components", + "Failed to create node with all required components" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestGradientNodeComponentDependency(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientNodeComponentDependency", args=["level"]) +def GradientNodes_DependentComponentsAdded(): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities with + proper dependent components. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities with - proper dependent components. + Expected Behavior: + All expected component dependencies are met when adding a Gradient Modifier node to a graph. - Expected Behavior: - All expected component dependencies are met when adding a Gradient Modifier node to a graph. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure the proper dependent components are + added - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure the proper dependent components are - added + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can check if the entity created - # from adding these gradients nodes has the main target Gradient Component - # as well as automatically adding all required dependency components - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Gradient mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - gradients = { - 'FastNoiseGradientNode': 'FastNoise Gradient', - 'ImageGradientNode': 'Image Gradient', - 'PerlinNoiseGradientNode': 'Perlin Noise Gradient', - 'RandomNoiseGradientNode': 'Random Noise Gradient' - } + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - commonComponents = [ - 'Gradient Transform Modifier', - 'Vegetation Reference Shape' - ] - componentNames = [] - for name in gradients: - componentNames.append(gradients[name]) - componentNames.extend(commonComponents) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Listen for entity creation notifications so we can check if the entity created + # from adding these gradients nodes has the main target Gradient Component + # as well as automatically adding all required dependency components + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - # Create nodes for the gradients that have additional required dependencies and check if - # the Entity created by adding the node has the appropriate Component and required - # Gradient Transform Modifier and Vegetation Reference Shape components added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in gradients: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Gradient mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + gradients = { + 'FastNoiseGradientNode': 'FastNoise Gradient', + 'ImageGradientNode': 'Image Gradient', + 'PerlinNoiseGradientNode': 'Perlin Noise Gradient', + 'RandomNoiseGradientNode': 'Random Noise Gradient' + } - gradientComponent = gradients[nodeName] - components = [gradientComponent] + commonComponents - success = False - for component in components: - componentTypeId = componentTypeIds[component] - success = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) - self.test_success = self.test_success and success - if not success: - break + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + commonComponents = [ + 'Gradient Transform Modifier', + 'Vegetation Reference Shape' + ] + componentNames = [] + for name in gradients: + componentNames.append(gradients[name]) + componentNames.extend(commonComponents) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - if success: - self.log("{node} created new Entity with all required components".format(node=nodeName)) + # Create nodes for the gradients that have additional required dependencies and check if + # the Entity created by adding the node has the appropriate Component and required + # Gradient Transform Modifier and Vegetation Reference Shape components added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in gradients: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - x += 40.0 - y += 40.0 + gradientComponent = gradients[nodeName] + components = [gradientComponent] + commonComponents + success = False + for component in components: + componentTypeId = componentTypeIds[component] + success = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) + if not success: + break + Report.info(nodeName) + Report.result(Tests.dependencies_added, success) - # Stop listening for entity creation notifications - handler.disconnect() + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientNodeComponentDependency() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientNodes_DependentComponentsAdded) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py index a484de8d2a..d5595e342c 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py @@ -5,130 +5,134 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os, sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + component_added = ( + "New entity created with the expected component", + "Expected component was not found on entity" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestGradientNodeEntityCreate(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientNodeEntityCreate", args=["level"]) +def GradientNodes_EntityCreatedOnNodeAdd(): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. + Expected Behavior: + New entities are created when dragging Gradient nodes to graph area. - Expected Behavior: - New entities are created when dragging Gradient nodes to graph area. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient nodes to the graph area, and ensure a new entity is created - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the Gradient nodes to the graph area, and ensure a new entity is created + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can check if the entity created - # from adding gradient nodes has the appropriate Gradient Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Gradient mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - gradients = { - 'AltitudeGradientNode': 'Altitude Gradient', - 'ConstantGradientNode': 'Constant Gradient', - 'FastNoiseGradientNode': 'FastNoise Gradient', - 'ImageGradientNode': 'Image Gradient', - 'PerlinNoiseGradientNode': 'Perlin Noise Gradient', - 'RandomNoiseGradientNode': 'Random Noise Gradient', - 'ShapeAreaFalloffGradientNode': 'Shape Falloff Gradient', - 'SlopeGradientNode': 'Slope Gradient', - 'SurfaceMaskGradientNode': 'Surface Mask Gradient', - } + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = [] - for name in gradients: - componentNames.append(gradients[name]) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Listen for entity creation notifications so we can check if the entity created + # from adding gradient nodes has the appropriate Gradient Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - # Create nodes for all the gradients we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in gradients: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Gradient mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + gradients = { + 'AltitudeGradientNode': 'Altitude Gradient', + 'ConstantGradientNode': 'Constant Gradient', + 'FastNoiseGradientNode': 'FastNoise Gradient', + 'ImageGradientNode': 'Image Gradient', + 'PerlinNoiseGradientNode': 'Perlin Noise Gradient', + 'RandomNoiseGradientNode': 'Random Noise Gradient', + 'ShapeAreaFalloffGradientNode': 'Shape Falloff Gradient', + 'SlopeGradientNode': 'Slope Gradient', + 'SurfaceMaskGradientNode': 'Surface Mask Gradient', + } - gradientComponent = gradients[nodeName] - componentTypeId = componentTypeIds[gradientComponent] - hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) - self.test_success = self.test_success and hasComponent - if hasComponent: - self.log("{node} created new Entity with {component} Component".format(node=nodeName, component=gradientComponent)) + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = [] + for name in gradients: + componentNames.append(gradients[name]) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - x += 40.0 - y += 40.0 + # Create nodes for all the gradients we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in gradients: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - # Stop listening for entity creation notifications - handler.disconnect() + gradientComponent = gradients[nodeName] + componentTypeId = componentTypeIds[gradientComponent] + hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) + Report.info(f"Node: {nodeName} | Component: {gradientComponent}") + Report.result(Tests.component_added, hasComponent) + + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientNodeEntityCreate() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientNodes_EntityCreatedOnNodeAdd) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py index 2e289ff41b..e5bfbfc7f1 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py @@ -5,129 +5,131 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + entity_deleted = ( + "Entity was deleted when node was removed", + "Entity was not deleted as expected when node was removed" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID createdEntityId = None deletedEntityId = None -class TestGradientNodeEntityDelete(EditorTestHelper): +def GradientNodes_EntityRemovedOnNodeDelete(): + """ + Summary: + This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientNodeEntityDelete", args=["level"]) + Expected Behavior: + Entities are removed when Gradient nodes are deleted from a graph. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient nodes to the graph area, and ensure a new entity is created + 4) Delete the nodes, and ensure the newly created entities are removed - Expected Behavior: - Entities are removed when Gradient nodes are deleted from a graph. + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the Gradient nodes to the graph area, and ensure a new entity is created - 4) Delete the nodes, and ensure the newly created entities are removed + :return: None + """ - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - :return: None - """ + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def onEntityCreated(parameters): - global createdEntityId - createdEntityId = parameters[0] + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - def onEntityDeleted(parameters): - global deletedEntityId - deletedEntityId = parameters[0] + def onEntityCreated(parameters): + global createdEntityId + createdEntityId = parameters[0] - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + def onEntityDeleted(parameters): + global deletedEntityId + deletedEntityId = parameters[0] - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Listen for entity creation notifications so we can check if the entity created - # from adding gradient nodes has the appropriate Gradient Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) - handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Gradient mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - gradients = [ - 'AltitudeGradientNode', - 'ConstantGradientNode', - 'FastNoiseGradientNode', - 'ImageGradientNode', - 'PerlinNoiseGradientNode', - 'RandomNoiseGradientNode', - 'ShapeAreaFalloffGradientNode', - 'SlopeGradientNode', - 'SurfaceMaskGradientNode', - ] + # Listen for entity creation notifications so we can check if the entity created + # from adding gradient nodes has the appropriate Gradient Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) + handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) - # Create nodes for all the gradients we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in gradients: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Gradient mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + gradients = [ + 'AltitudeGradientNode', + 'ConstantGradientNode', + 'FastNoiseGradientNode', + 'ImageGradientNode', + 'PerlinNoiseGradientNode', + 'RandomNoiseGradientNode', + 'ShapeAreaFalloffGradientNode', + 'SlopeGradientNode', + 'SurfaceMaskGradientNode', + ] - removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) + # Create nodes for all the gradients we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in gradients: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - # Verify that the created Entity for this node matches the Entity that gets - # deleted when the node is removed - self.test_success = self.test_success and removed and createdEntityId.invoke("Equal", deletedEntityId) - if removed and createdEntityId.invoke("Equal", deletedEntityId): - self.log("{node} corresponding Entity was deleted when node is removed".format(node=nodeName)) + removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) - # Stop listening for entity creation notifications - handler.disconnect() + # Verify that the created Entity for this node matches the Entity that gets + # deleted when the node is removed + Report.info(f"Node: {nodeName}") + Report.result(Tests.entity_deleted, removed and createdEntityId.invoke("Equal", deletedEntityId)) + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientNodeEntityDelete() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientNodes_EntityRemovedOnNodeDelete) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py index 0ad1549b60..0f83688206 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py @@ -5,100 +5,99 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.legacy.general as general -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + graph_closed = ( + "Graph closed on entity delete", + "Graph is still open after entity delete" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newRootEntityId = None -class TestGraphClosedOnEntityDelete(EditorTestHelper): +def GraphClosed_OnEntityDelete(): + """ + Summary: + This test verifies that Landscape Canvas graphs are auto-closed when the corresponding entity is deleted. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GraphClosedOnEntityDelete", args=["level"]) + Expected Behavior: + When a Landscape Canvas root entity is deleted, the corresponding graph automatically closes. - def run_test(self): - """ - Summary: - This test verifies that Landscape Canvas graphs are auto-closed when the corresponding entity is deleted. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Delete the automatically created entity + 4) Verify the open graph is closed - Expected Behavior: - When a Landscape Canvas root entity is deleted, the corresponding graph automatically closes. + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Delete the automatically created entity - 4) Verify the open graph is closed + :return: None + """ - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.legacy.general as general - :return: None - """ + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def onEntityCreated(parameters): - global newRootEntityId - newRootEntityId = parameters[0] + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + def onEntityCreated(parameters): + global newRootEntityId + newRootEntityId = parameters[0] - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Listen for entity creation notifications so we can store the top-level Entity created - # when a new graph is created, and then delete it to test if the graph is closed - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Create a new graph in Landscape Canvas and verify - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - graphIsOpen = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and graphIsOpen - if graphIsOpen: - self.log("Graph registered with Landscape Canvas") + # Listen for entity creation notifications so we can store the top-level Entity created + # when a new graph is created, and then delete it to test if the graph is closed + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - # Delete the top-level Entity created by the new graph - editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityById', newRootEntityId) + # Create a new graph in Landscape Canvas and verify + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + graphIsOpen = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graphIsOpen) - # We need to delay here because the closing of the graph due to Entity deletion - # is actually queued in order to workaround an undo/redo issue - # Alternatively, we could add a notifications bus for AssetEditorRequests - # that could trigger when graphs are opened/closed and then do the check there - general.idle_enable(True) - general.idle_wait(1.0) + # Delete the top-level Entity created by the new graph + editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityById', newRootEntityId) - # Verify that the corresponding graph is no longer open - graphIsClosed = not graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and graphIsClosed - if graphIsClosed: - self.log("The graph is no longer open after deleting the Entity") + # We need to delay here because the closing of the graph due to Entity deletion + # is actually queued in order to workaround an undo/redo issue + # Alternatively, we could add a notifications bus for AssetEditorRequests + # that could trigger when graphs are opened/closed and then do the check there + general.idle_enable(True) + general.idle_wait(1.0) - # Stop listening for entity creation notifications - handler.disconnect() + # Verify that the corresponding graph is no longer open + graphIsClosed = not graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_closed, graphIsClosed) + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGraphClosedOnEntityDelete() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GraphClosed_OnEntityDelete) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py index 374f26d3a4..67c2ec6908 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py @@ -5,82 +5,82 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor.graph as graph -import azlmbr.legacy.general as general -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper - -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + graph_closed = ( + "Graph closed on level change", + "Graph is still open after level change" + ) -class TestGraphClosedOnLevelChange(EditorTestHelper): +def GraphClosed_OnLevelChange(): + """ + Summary: + This test verifies that Landscape Canvas graphs are auto-closed when the currently open level changes. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GraphClosedOnLevelChange", args=["level"]) + Expected Behavior: + When a new level is loaded in the Editor, open Landscape Canvas graphs are automatically closed. - def run_test(self): - """ - Summary: - This test verifies that Landscape Canvas graphs are auto-closed when the currently open level changes. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Open a different level + 4) Verify the open graph is closed - Expected Behavior: - When a new level is loaded in the Editor, open Landscape Canvas graphs are automatically closed. + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Open a different level - 4) Verify the open graph is closed + :return: None + """ - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + import azlmbr.bus as bus + import azlmbr.editor.graph as graph + import azlmbr.legacy.general as general - :return: None - """ - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - graphIsOpen = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and graphIsOpen - if graphIsOpen: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Open a different level, which should close any open Landscape Canvas graphs - general.open_level_no_prompt('WhiteBox/EmptyLevel') + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Make sure the graph we created is now closed - graphIsOpen = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and not graphIsOpen - if not graphIsOpen: - self.log("Graph is no longer open in Landscape Canvas") + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) + + # Open a different level, which should close any open Landscape Canvas graphs + general.open_level_no_prompt('WhiteBox/EmptyLevel') + + # Make sure the graph we created is now closed + graphIsOpen = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_closed, not graphIsOpen) -test = TestGraphClosedOnLevelChange() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GraphClosed_OnLevelChange) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py index f8b0cfdb44..83762e0afb 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py @@ -5,95 +5,93 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor.graph as graph -import azlmbr.legacy.general as general -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper - -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_open = ( + "Graph is open in Landscape Canvas", + "Graph is not open in Landscape Canvas" + ) + tabbed_graph_closed = ( + "Tabbed graph closed independently", + "Closing tabbed graph resulted in unexpected graphs closing" + ) -class TestGraphClosedTabbedGraph(EditorTestHelper): +def GraphClosed_TabbedGraphClosesIndependently(): + """ + Summary: + This test verifies that Landscape Canvas tabbed graphs can be independently closed. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GraphClosedTabbedGraph", args=["level"]) + Expected Behavior: + Closing a tabbed graph only closes the appropriate graph. - def run_test(self): - """ - Summary: - This test verifies that Landscape Canvas tabbed graphs can be independently closed. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create several new graphs + 3) Close one of the open graphs + 4) Ensure the graph properly closed, and other open graphs remain open - Expected Behavior: - Closing a tabbed graph only closes the appropriate graph. + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create several new graphs - 3) Close one of the open graphs - 4) Ensure the graph properly closed, and other open graphs remain open + :return: None + """ - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + import azlmbr.bus as bus + import azlmbr.editor.graph as graph + import azlmbr.legacy.general as general - :return: None - """ + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + editor_id = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def create_new_graph(): + new_graph_id = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editor_id) + return new_graph_id - # Create 3 new graphs in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + def is_graph_open(graph_id): + graph_open = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editor_id, graph_id) + return graph_open - newGraphId2 = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId2 - if newGraphId2: - self.log("2nd new graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - newGraphId3 = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId3 - if newGraphId3: - self.log("3rd new graph created") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Make sure the graphs we created are open in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - success2 = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId2) - success3 = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId3) - self.test_success = self.test_success and success and success2 and success3 - if success and success2 and success3: - self.log("Graphs registered with Landscape Canvas") + # Create 3 new graphs in Landscape Canvas and make sure the graphs we created are open in Landscape Canvas + graph1 = create_new_graph() + Report.result(Tests.new_graph_created, graph1 is not None) + Report.result(Tests.graph_open, is_graph_open(graph1)) - # Close a single graph and verify it was properly closed and other graphs remain open - success4 = graph.AssetEditorRequestBus(bus.Event, 'CloseGraph', editorId, newGraphId2) - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - success2 = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId2) - success3 = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId3) - self.test_success = self.test_success and success and success3 and success4 and not success2 - if success and success3 and success4 and not success2: - self.log("Graph 2 was successfully closed") + graph2 = create_new_graph() + Report.result(Tests.new_graph_created, graph2 is not None) + Report.result(Tests.graph_open, is_graph_open(graph2)) + + graph3 = create_new_graph() + Report.result(Tests.new_graph_created, graph3 is not None) + Report.result(Tests.graph_open, is_graph_open(graph3)) + + # Close a single graph and verify it was properly closed and other graphs remain open + graph.AssetEditorRequestBus(bus.Event, 'CloseGraph', editor_id, graph2) + Report.result(Tests.tabbed_graph_closed, not is_graph_open(graph2) and is_graph_open(graph1) and + is_graph_open(graph3)) -test = TestGraphClosedTabbedGraph() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GraphClosed_TabbedGraphClosesIndependently) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py index cc7c2ca7dd..c489c738d5 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py @@ -5,155 +5,151 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.asset as asset -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.legacy.general as general -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.math as math -import azlmbr.slice as slice -import azlmbr.paths - -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import automatedtesting_shared.landscape_canvas_utils as lc +class Tests: + slice_instantiated = ( + "Slice instantiated successfully", + "Failed to instantiate slice" + ) + existing_graph_opened = ( + "Opened existing graph from slice", + "Failed to open existing graph" + ) + node_removed = ( + "Rotation Modifier node was removed", + "Failed to remove Rotation Modifier node" + ) + component_removed = ( + "Rotation Modifier component was removed from entity", + "Rotation Modifier component is still present on entity" + ) + entity_deleted = ( + "BushSpawner entity was deleted", + "Failed to delete BushSpawner entity" + ) + entity_reference_updated = ( + "Gradient Entity Id reference was properly updated", + "Gradient Entity Id reference was not updated properly" + ) -class TestGraphUpdatesUpdateComponents(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GraphUpdatesUpdateComponents", args=["level"]) +def GraphUpdates_UpdateComponent(): + """ + Summary: + This test verifies that components are properly updated as nodes are added/removed/updated. - def run_test(self): - """ - Summary: - This test verifies that components are properly updated as nodes are added/removed/updated. + Expected Behavior: + Landscape Canvas node CRUD properly updates component entities. - Expected Behavior: - Landscape Canvas node CRUD properly updates component entities. + Test Steps: + 1. Open Level. + 2. Open the graph on LC_BushFlowerBlender.slice + 3. Find the Rotation Modifier node on the BushSpawner entity + 4. Delete the Rotation Modifier node + 5. Ensure the Vegetation Rotation Modifier component is removed from the BushSpawner entity + 6. Delete the Vegetation Layer Spawner node from the graph + 7. Ensure BushSpawner entity is deleted + 8. Change connection from second Rotation Modifier node to a different Gradient + 9. Ensure Gradient reference on component is updated - Test Steps: - 1. Open Level. - 2. Open the graph on LC_BushFlowerBlender.slice - 3. Find the Rotation Modifier node on the BushSpawner entity - 4. Delete the Rotation Modifier node - 5. Ensure the Vegetation Rotation Modifier component is removed from the BushSpawner entity - 6. Delete the Vegetation Layer Spawner node from the graph - 7. Ensure BushSpawner entity is deleted - 8. Change connection from second Rotation Modifier node to a different Gradient - 9. Ensure Gradient reference on component is updated + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ - # Create a new empty level and instantiate LC_BushFlowerBlender.slice - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - transform = math.Transform_CreateIdentity() - position = math.Vector3(64.0, 64.0, 32.0) - transform.invoke('SetPosition', position) - test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") - test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), - False) - test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) - self.test_success = self.test_success and test_slice.IsValid() - if test_slice.IsValid(): - self.log("Slice spawned!") + import os - # Search for root entity to ensure slice is loaded - search_filter = entity.SearchFilter() - search_filter.names = ["LandscapeCanvas"] - self.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, 5.0) + import azlmbr.asset as asset + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + import azlmbr.legacy.general as general + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.math as math + import azlmbr.slice as slice - # Find needed entities in the loaded level - slice_root_id = hydra.find_entity_by_name('LandscapeCanvas') - bush_spawner_id = hydra.find_entity_by_name('BushSpawner') - flower_spawner_id = hydra.find_entity_by_name('FlowerSpawner') - inverted_perlin_noise_id = hydra.find_entity_by_name('Invert') + import automatedtesting_shared.landscape_canvas_utils as lc + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Open Landscape Canvas and the existing graph - general.open_pane('Landscape Canvas') - open_graph_id = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) - self.test_success = self.test_success and open_graph_id.IsValid() - if open_graph_id.IsValid(): - self.log('Graph opened') + # Open a simple level and instantiate LC_BushFlowerBlender.slice + helper.init_idle() + helper.open_level("Physics", "Base") + transform = math.Transform_CreateIdentity() + position = math.Vector3(64.0, 64.0, 32.0) + transform.invoke('SetPosition', position) + test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") + test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), + False) + test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) + Report.critical_result(Tests.slice_instantiated, test_slice.IsValid()) - # Find the Rotation Modifier node on the BushSpawner entity - rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', bush_spawner_id) + # Search for root entity to ensure slice is loaded + search_filter = entity.SearchFilter() + search_filter.names = ["LandscapeCanvas"] + helper.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, 5.0) - # Remove the Rotation Modifier node - graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', open_graph_id, rotation_modifier_node[0]) + # Find needed entities in the loaded level + slice_root_id = hydra.find_entity_by_name('LandscapeCanvas') + bush_spawner_id = hydra.find_entity_by_name('BushSpawner') + flower_spawner_id = hydra.find_entity_by_name('FlowerSpawner') + inverted_perlin_noise_id = hydra.find_entity_by_name('Invert') - # Verify node was removed - rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', bush_spawner_id) - self.test_success = self.test_success and not rotation_modifier_node - if not rotation_modifier_node: - self.log('Rotation Modifier node was removed') - else: - self.log('Rotation Modifier node was not removed') + # Open Landscape Canvas and the existing graph + general.open_pane('Landscape Canvas') + open_graph_id = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) + Report.critical_result(Tests.existing_graph_opened, open_graph_id.IsValid()) - # Verify the component was removed from the BushSpawner entity - has_rotation_modifier = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', bush_spawner_id, - hydra.get_component_type_id('Vegetation Rotation Modifier')) - self.test_success = self.test_success and not has_rotation_modifier - if not has_rotation_modifier: - self.log('Rotation Modifier component was removed from entity') - else: - self.log('Rotation Modifier component is still present on entity') + # Find the Rotation Modifier node on the BushSpawner entity + rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', bush_spawner_id) - # Find the Vegetation Layer Spawner node on the BushSpawner entity - layer_spawner_node = lc.find_nodes_matching_entity_component('Vegetation Layer Spawner', bush_spawner_id) + # Remove the Rotation Modifier node + graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', open_graph_id, rotation_modifier_node[0]) - # Remove the Vegetation Layer Spawner node and verify the corresponding entity is deleted - graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', open_graph_id, layer_spawner_node[0]) - bush_spawner_id = hydra.find_entity_by_name('BushSpawner') - self.test_success = self.test_success and not bush_spawner_id - if not bush_spawner_id: - self.log('BushSpawner entity was deleted') - else: - self.log('Failed to delete BushSpawner entity') + # Verify node was removed + rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', bush_spawner_id) + Report.result(Tests.node_removed, not rotation_modifier_node) - # Connect the FlowerSpawner's Rotation Modifier node to the Invert Gradient Modifier node - rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', flower_spawner_id) - invert_node = lc.find_nodes_matching_entity_component('Invert Gradient Modifier', inverted_perlin_noise_id) + # Verify the component was removed from the BushSpawner entity + has_rotation_modifier = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', bush_spawner_id, + hydra.get_component_type_id('Vegetation Rotation Modifier')) + Report.result(Tests.component_removed, not has_rotation_modifier) - inbound_gradient_z_slot = graph.GraphModelSlotId('InboundGradientZ') - outbound_gradient_slot = graph.GraphModelSlotId('OutboundGradient') - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', open_graph_id, invert_node[0], - outbound_gradient_slot, rotation_modifier_node[0], inbound_gradient_z_slot) + # Find the Vegetation Layer Spawner node on the BushSpawner entity + layer_spawner_node = lc.find_nodes_matching_entity_component('Vegetation Layer Spawner', bush_spawner_id) - general.idle_wait(1.0) # Add a small wait to ensure component property has time to update + # Remove the Vegetation Layer Spawner node and verify the corresponding entity is deleted + graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', open_graph_id, layer_spawner_node[0]) + bush_spawner_id = hydra.find_entity_by_name('BushSpawner') + Report.result(Tests.entity_deleted, not bush_spawner_id) - # Verify the Gradient Entity Id reference on the Rotation Modifier component was properly set - rotation_type_id = hydra.get_component_type_id('Vegetation Rotation Modifier') - rotation_outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', flower_spawner_id, - rotation_type_id) - rotation_component = rotation_outcome.GetValue() - gradient_reference = hydra.get_component_property_value(rotation_component, - 'Configuration|Rotation Z|Gradient|Gradient Entity Id') - gradient_reference_success = gradient_reference == inverted_perlin_noise_id - self.test_success = self.test_success and gradient_reference_success - if gradient_reference_success: - self.log('Gradient Entity Id reference was properly updated') - else: - self.log(f'Gradient Entity Id was not updated properly: Expected {inverted_perlin_noise_id.ToString()} -- Got ' - f'{gradient_reference.ToString()}.') + # Connect the FlowerSpawner's Rotation Modifier node to the Invert Gradient Modifier node + rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', flower_spawner_id) + invert_node = lc.find_nodes_matching_entity_component('Invert Gradient Modifier', inverted_perlin_noise_id) + + inbound_gradient_z_slot = graph.GraphModelSlotId('InboundGradientZ') + outbound_gradient_slot = graph.GraphModelSlotId('OutboundGradient') + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', open_graph_id, invert_node[0], + outbound_gradient_slot, rotation_modifier_node[0], inbound_gradient_z_slot) + + general.idle_wait(1.0) # Add a small wait to ensure component property has time to update + + # Verify the Gradient Entity Id reference on the Rotation Modifier component was properly set + rotation_type_id = hydra.get_component_type_id('Vegetation Rotation Modifier') + rotation_outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', flower_spawner_id, + rotation_type_id) + rotation_component = rotation_outcome.GetValue() + gradient_reference = hydra.get_component_property_value(rotation_component, + 'Configuration|Rotation Z|Gradient|Gradient Entity Id') + Report.result(Tests.entity_reference_updated, gradient_reference == inverted_perlin_noise_id) -test = TestGraphUpdatesUpdateComponents() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GraphUpdates_UpdateComponent) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvasComponent_AddedRemoved.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvasComponent_AddedRemoved.py deleted file mode 100755 index ed6f23ae24..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvasComponent_AddedRemoved.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -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. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper - -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - - -class TestLandscapeCanvasComponentAddedRemoved(EditorTestHelper): - - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="LandscapeCanvasComponentAddedRemoved", args=["level"]) - - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas component can be added to/removed from an entity. - - Expected Behavior: - Closing a tabbed graph only closes the appropriate graph. - - Test Steps: - 1) Create a new level - 2) Create a new entity - 3) Add a Landscape Canvas component to the entity - 4) Remove the Landscape Canvas component from the entity - - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. - - :return: None - """ - - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - - # Create an Entity at the root of the level - newEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - - # Find the component TypeId for our Landscape Canvas component - landscape_canvas_type_id = hydra.get_component_type_id("Landscape Canvas") - - # Add the Landscape Canvas Component to our Entity - componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', newEntityId, [landscape_canvas_type_id]) - components = componentOutcome.GetValue() - landscapeCanvasComponent = components[0] - - # Validate the Landscape Canvas Component exists - hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, landscape_canvas_type_id) - self.test_success = self.test_success and hasComponent - if hasComponent: - self.log("Landscape Canvas Component added to Entity") - - # Remove the Landscape Canvas Component - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [landscapeCanvasComponent]) - - # Validate the Landscape Canvas Component is no longer on our Entity - hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, landscape_canvas_type_id) - self.test_success = self.test_success and not hasComponent - if not hasComponent: - self.log("Landscape Canvas Component removed from Entity") - - -test = TestLandscapeCanvasComponentAddedRemoved() -test.run() diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvas_SliceCreateInstantiate.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvas_SliceCreateInstantiate.py deleted file mode 100755 index 95da5aa7dd..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvas_SliceCreateInstantiate.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -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. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - -import os -import sys - -import azlmbr.math as math -import azlmbr.paths -import azlmbr.bus as bus -import azlmbr.asset as asset -import azlmbr.slice as slice - -sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper - - -class TestLandscapeCanvasSliceCreateInstantiate(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="LandscapeCanvas_SliceCreateInstantiate", args=["level"]) - - def run_test(self): - """ - Summary: - A slice containing the LandscapeCanvas component can be created/instantiated. - - Expected Result: - Slice is created/processed/instantiated successfully and free of errors/warnings. - - Test Steps: - 1) Create a new level - 2) Create a new entity with a Landscape Canvas component - 3) Create a slice of the new entity - 4) Instantiate a new copy of the slice - - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. - :return: None - """ - - def path_is_valid_asset(asset_path): - asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_path, math.Uuid(), False) - return asset_id.invoke("IsValid") - - # Create empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) - - # Create entity with LandScape Canvas component - position = math.Vector3(512.0, 512.0, 32.0) - landscape_canvas = hydra.Entity("landscape_canvas_entity") - landscape_canvas.create_entity(position, ["Landscape Canvas"]) - - # Create slice from the created entity - slice_path = os.path.join("slices", "TestSlice.slice") - slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", landscape_canvas.id, slice_path) - - # Verify if slice is created - self.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0) - self.log(f"Slice has been created successfully: {path_is_valid_asset(slice_path)}") - - # Instantiate slice - transform = math.Transform_CreateIdentity() - asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", slice_path, math.Uuid(), False) - test_slice = slice.SliceRequestBus(bus.Broadcast, "InstantiateSliceFromAssetId", asset_id, transform) - self.wait_for_condition(lambda: test_slice.IsValid(), 3.0) - self.log(f"Slice instantiated: {test_slice.IsValid()}") - - -test = TestLandscapeCanvasSliceCreateInstantiate() -test.run() diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py index f68bfd91a6..b2bf20411b 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py @@ -5,157 +5,160 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.entity as entity -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + blender_first_layer_set = ( + "Spawner entity set as the first layer of the Vegetation Layer Blender component", + "Unexpected entity set as the first layer of the Vegetation Layer Blender component" + ) + blender_second_layer_set = ( + "Blocker entity set as the second layer of the Vegetation Layer Blender component", + "Unexpected entity set as the second layer of the Vegetation Layer Blender component" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestLayerBlenderNodeConstruction(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="LayerBlenderNodeConstruction", args=["level"]) +def LayerBlender_NodeConstruction(): + """ + Summary: + This test verifies a Layer Blender vegetation setup can be constructed through Landscape Canvas. - def run_test(self): - """ - Summary: - This test verifies a Layer Blender vegetation setup can be constructed through Landscape Canvas. + Expected Behavior: + Entities contain all required components and component references after creating nodes and setting connections + on a Landscape Canvas graph. - Expected Behavior: - Entities contain all required components and component references after creating nodes and setting connections - on a Landscape Canvas graph. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Add all necessary nodes to the graph and set connections to form a Layer Blender setup + 4) Verify all components and component references were properly set during graph construction - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Add all necessary nodes to the graph and set connections to form a Layer Blender setup - 4) Verify all components and component references were properly set during graph construction + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can verify the component EntityId - # references are set correctly when connecting slots on the nodes - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - positionX = 10.0 - positionY = 10.0 - offsetX = 340.0 - offsetY = 100.0 + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Add a Vegetation Layer Spawner node to the graph - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - layerSpawnerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'SpawnerAreaNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, layerSpawnerNode, math.Vector2(positionX, positionY)) - layerSpawnerEntityId = newEntityId + # Listen for entity creation notifications so we can verify the component EntityId + # references are set correctly when connecting slots on the nodes + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - positionX += offsetX - positionY += offsetY + positionX = 10.0 + positionY = 10.0 + offsetX = 340.0 + offsetY = 100.0 - # Add a Vegetation Layer Blocker node to the graph - layerBlockerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'BlockerAreaNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, layerBlockerNode, math.Vector2(positionX, positionY)) - layerBlockerEntityId = newEntityId + # Add a Vegetation Layer Spawner node to the graph + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + layerSpawnerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'SpawnerAreaNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, layerSpawnerNode, math.Vector2(positionX, positionY)) + layerSpawnerEntityId = newEntityId - positionX += offsetX - positionY += offsetY + positionX += offsetX + positionY += offsetY - # Add a Vegetation Layer Blender node to the graph - layerBlenderNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'AreaBlenderNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, layerBlenderNode, math.Vector2(positionX, positionY)) - layerBlenderNodeEntityId = newEntityId + # Add a Vegetation Layer Blocker node to the graph + layerBlockerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'BlockerAreaNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, layerBlockerNode, math.Vector2(positionX, positionY)) + layerBlockerEntityId = newEntityId - positionX += offsetX - positionY += offsetY + positionX += offsetX + positionY += offsetY - outboundAreaSlotId = graph.GraphModelSlotId('OutboundArea') - inboundAreaSlotId = graph.GraphModelSlotId('InboundArea') - inboundAreaSlotId2 = graph.GraphControllerRequestBus(bus.Event, 'ExtendSlot', newGraphId, layerBlenderNode, - 'InboundArea') + # Add a Vegetation Layer Blender node to the graph + layerBlenderNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'AreaBlenderNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, layerBlenderNode, math.Vector2(positionX, positionY)) + layerBlenderNodeEntityId = newEntityId - # Connect slots on our nodes to construct a Vegetation Layer Blender hierarchy - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, layerSpawnerNode, outboundAreaSlotId, - layerBlenderNode, inboundAreaSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, layerBlockerNode, outboundAreaSlotId, - layerBlenderNode, inboundAreaSlotId2) + positionX += offsetX + positionY += offsetY - # Delay to allow all the underlying component properties to be updated after the slot connections are made - general.idle_wait(1.0) + outboundAreaSlotId = graph.GraphModelSlotId('OutboundArea') + inboundAreaSlotId = graph.GraphModelSlotId('InboundArea') + inboundAreaSlotId2 = graph.GraphControllerRequestBus(bus.Event, 'ExtendSlot', newGraphId, layerBlenderNode, + 'InboundArea') - # Get component info - layerBlenderTypeId = hydra.get_component_type_id("Vegetation Layer Blender") - vegetationLayerBlenderOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', - layerBlenderNodeEntityId, layerBlenderTypeId) - layerBlenderComponent = vegetationLayerBlenderOutcome.GetValue() + # Connect slots on our nodes to construct a Vegetation Layer Blender hierarchy + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, layerSpawnerNode, outboundAreaSlotId, + layerBlenderNode, inboundAreaSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, layerBlockerNode, outboundAreaSlotId, + layerBlenderNode, inboundAreaSlotId2) - # Verify the Vegetation Areas properties on our Vegetation Layer Blender component have been set to our area EntityIds - area1EntityId = hydra.get_component_property_value(layerBlenderComponent, 'Configuration|Vegetation Areas|[0]') - self.test_success = self.test_success and area1EntityId and layerSpawnerEntityId.invoke("Equal", area1EntityId) - if area1EntityId and layerSpawnerEntityId.invoke("Equal", area1EntityId): - self.log("Vegetation Layer Blender component Vegetation Areas[0] property set to Vegetation Layer Spawner EntityId") + # Delay to allow all the underlying component properties to be updated after the slot connections are made + general.idle_wait(1.0) - area2EntityId = hydra.get_component_property_value(layerBlenderComponent, 'Configuration|Vegetation Areas|[1]') - self.test_success = self.test_success and area2EntityId and layerBlockerEntityId.invoke("Equal", area2EntityId) - if area2EntityId and layerBlockerEntityId.invoke("Equal", area2EntityId): - self.log("Vegetation Layer Blender component Vegetation Areas[1] property set to Vegetation Layer Blocker EntityId") + # Get component info + layerBlenderTypeId = hydra.get_component_type_id("Vegetation Layer Blender") + vegetationLayerBlenderOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', + layerBlenderNodeEntityId, layerBlenderTypeId) + layerBlenderComponent = vegetationLayerBlenderOutcome.GetValue() - # Stop listening for entity creation notifications - handler.disconnect() + # Verify the Vegetation Areas properties on our Vegetation Layer Blender component have been set to our area EntityIds + area1EntityId = hydra.get_component_property_value(layerBlenderComponent, 'Configuration|Vegetation Areas|[0]') + Report.result(Tests.blender_first_layer_set, area1EntityId and layerSpawnerEntityId.invoke("Equal", area1EntityId)) + + area2EntityId = hydra.get_component_property_value(layerBlenderComponent, 'Configuration|Vegetation Areas|[1]') + Report.result(Tests.blender_second_layer_set, area2EntityId and layerBlockerEntityId.invoke("Equal", area2EntityId)) + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestLayerBlenderNodeConstruction() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(LayerBlender_NodeConstruction) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py index 5b523e0b38..510c404614 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py @@ -5,164 +5,170 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + component_added = ( + "Expected component is present on entity", + "Expected component was not found on entity" + ) + component_removed = ( + "Expected component was removed from entity", + "Component is unexpectedly still present on entity" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestLayerExtenderNodeComponentEntitySync(EditorTestHelper): +def LayerExtenderNodes_ComponentEntitySync(): + """ + Summary: + This test verifies that all wrapped nodes can be successfully added to/removed from parent nodes. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="LayerExtenderNodeComponentEntitySync", args=["level"]) + Expected Behavior: + All wrapped extender nodes can be added to/removed from appropriate parent nodes. - def run_test(self): - """ - Summary: - This test verifies that all wrapped nodes can be successfully added to/removed from parent nodes. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Add Area Blender and Layer Spawner nodes to the graph, and add/remove each extender node to/from each - Expected Behavior: - All wrapped extender nodes can be added to/removed from appropriate parent nodes. + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Add Area Blender and Layer Spawner nodes to the graph, and add/remove each extender node to/from each + :return: None + """ - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math + import azlmbr.paths - :return: None - """ + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Listen for entity creation notifications so we can check if the - # proper components are added when we add nodes - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Extender mapping with the key being the node name and the value is the - # expected Component that should be added to the layer Entity for that wrapped node - extenders = { - 'AltitudeFilterNode': 'Vegetation Altitude Filter', - 'DistanceBetweenFilterNode': 'Vegetation Distance Between Filter', - 'DistributionFilterNode': 'Vegetation Distribution Filter', - 'ShapeIntersectionFilterNode': 'Vegetation Shape Intersection Filter', - 'SlopeFilterNode': 'Vegetation Slope Filter', - 'SurfaceMaskDepthFilterNode': 'Vegetation Surface Mask Depth Filter', - 'SurfaceMaskFilterNode': 'Vegetation Surface Mask Filter', - 'PositionModifierNode': 'Vegetation Position Modifier', - 'RotationModifierNode': 'Vegetation Rotation Modifier', - 'ScaleModifierNode': 'Vegetation Scale Modifier', - 'SlopeAlignmentModifierNode': 'Vegetation Slope Alignment Modifier', - 'AssetWeightSelectorNode': 'Vegetation Asset Weight Selector' - } + # Listen for entity creation notifications so we can check if the + # proper components are added when we add nodes + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = [] - for name in extenders: - componentNames.append(extenders[name]) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Extender mapping with the key being the node name and the value is the + # expected Component that should be added to the layer Entity for that wrapped node + extenders = { + 'AltitudeFilterNode': 'Vegetation Altitude Filter', + 'DistanceBetweenFilterNode': 'Vegetation Distance Between Filter', + 'DistributionFilterNode': 'Vegetation Distribution Filter', + 'ShapeIntersectionFilterNode': 'Vegetation Shape Intersection Filter', + 'SlopeFilterNode': 'Vegetation Slope Filter', + 'SurfaceMaskDepthFilterNode': 'Vegetation Surface Mask Depth Filter', + 'SurfaceMaskFilterNode': 'Vegetation Surface Mask Filter', + 'PositionModifierNode': 'Vegetation Position Modifier', + 'RotationModifierNode': 'Vegetation Rotation Modifier', + 'ScaleModifierNode': 'Vegetation Scale Modifier', + 'SlopeAlignmentModifierNode': 'Vegetation Slope Alignment Modifier', + 'AssetWeightSelectorNode': 'Vegetation Asset Weight Selector' + } - areas = [ - 'AreaBlenderNode', - 'SpawnerAreaNode' - ] + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = [] + for name in extenders: + componentNames.append(extenders[name]) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - # Add/remove all our supported extender nodes to the Layer Areas and check if the appropriate - # Components are added/removed to the wrapper node's Entity - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for areaName in areas: - nodePosition = math.Vector2(x, y) - areaNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, areaName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, areaNode, nodePosition) + areas = [ + 'AreaBlenderNode', + 'SpawnerAreaNode' + ] - success = True - for extenderName in extenders: - # Add the wrapped node for the extender - extenderNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, - 'CreateNodeForTypeName', newGraph, - extenderName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, extenderNode, nodePosition) - graph.GraphControllerRequestBus(bus.Event, 'WrapNode', newGraphId, areaNode, extenderNode) + # Add/remove all our supported extender nodes to the Layer Areas and check if the appropriate + # Components are added/removed to the wrapper node's Entity + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for areaName in areas: + nodePosition = math.Vector2(x, y) + areaNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, areaName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, areaNode, nodePosition) - # Check that the appropriate Component was added when the extender node was added - extenderComponent = extenders[extenderName] - componentTypeId = componentTypeIds[extenderComponent] - success = success and editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, + success = True + for extenderName in extenders: + # Add the wrapped node for the extender + extenderNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, + 'CreateNodeForTypeName', newGraph, + extenderName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, extenderNode, nodePosition) + graph.GraphControllerRequestBus(bus.Event, 'WrapNode', newGraphId, areaNode, extenderNode) + + # Check that the appropriate Component was added when the extender node was added + extenderComponent = extenders[extenderName] + componentTypeId = componentTypeIds[extenderComponent] + success = success and editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, + componentTypeId) + Report.info(f"Component: {extenderComponent}") + Report.result(Tests.component_added, success) + if not success: + break + + # Check that the appropriate Component was removed when the extender node was removed + graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, extenderNode) + success = success and not editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) - self.test_success = self.test_success and success - if not success: - self.log("{node} failed to add {component} Component".format(node=areaName, - component=extenderComponent)) - break + Report.info(f"Component: {extenderComponent}") + Report.result(Tests.component_removed, success) + if not success: + break - # Check that the appropriate Component was removed when the extender node was removed - graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, extenderNode) - success = success and not editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, - componentTypeId) - self.test_success = self.test_success and success - if not success: - self.log("{node} failed to remove {component} Component".format(node=areaName, - component=extenderComponent)) - break + if success: + Report.info(f"{areaName} successfully added and removed all filters/modifiers/selectors") - if success: - self.log("{node} successfully added and removed all filters/modifiers/selectors".format(node=areaName)) - - # Stop listening for entity creation notifications - handler.disconnect() + # Stop listening for entity creation notifications + handler.disconnect() -test = TestLayerExtenderNodeComponentEntitySync() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(LayerExtenderNodes_ComponentEntitySync) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/NewGraph_CreatedSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/NewGraph_CreatedSuccessfully.py new file mode 100644 index 0000000000..d13c5dfa2f --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/NewGraph_CreatedSuccessfully.py @@ -0,0 +1,111 @@ +""" +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. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + + +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + lc_component_added = ( + "Root entity created with the Landscape Canvas component", + "Landscape Canvas component was not found on the root entity" + ) + lc_tool_closed = ( + "Landscape Canvas tool closed", + "Failed to close Landscape Canvas tool" + ) + + +new_root_entity_id = None + + +def NewGraph_CreatedSuccessfully(): + """ + Summary: + This test verifies that new graphs can be created in Landscape Canvas. + + Expected Behavior: + New graphs can be created, and proper entity is created to hold graph data with a Landscape Canvas component. + + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Ensures the root entity created contains a Landscape Canvas component + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.legacy.general as general + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID + + def on_entity_created(parameters): + global new_root_entity_id + new_root_entity_id = parameters[0] + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Listen for entity creation notifications so we can check if the entity created + # with the new graph has our Landscape Canvas component automatically added + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback("OnEditorEntityCreated", on_entity_created) + + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) + + # Create a new graph in Landscape Canvas + new_graph_id = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, new_graph_id is not None) + + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, new_graph_id) + Report.result(Tests.graph_registered, graph_registered) + + # Check if the entity created when we create a new graph has the + # Landscape Canvas component already added to it + landscape_canvas_type_id = hydra.get_component_type_id("Landscape Canvas") + success = editor.EditorComponentAPIBus(bus.Broadcast, "HasComponentOfType", new_root_entity_id, + landscape_canvas_type_id) + Report.result(Tests.lc_component_added, success) + + # Close Landscape Canvas tool and verify + general.close_pane("Landscape Canvas") + Report.result(Tests.lc_tool_closed, not general.is_pane_visible("Landscape Canvas")) + + # Stop listening for entity creation notifications + handler.disconnect() + + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(NewGraph_CreatedSuccessfully) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py index 0c877535a9..93464c7ad3 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py @@ -5,133 +5,136 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + component_added = ( + "New entity created with the expected component", + "Expected component was not found on entity" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestShapeNodeEntityCreate(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="ShapeNodeEntityCreate", args=["level"]) +def ShapeNodes_EntityCreatedOnNodeAdd(): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. + Expected Behavior: + New entities are created when dragging shape nodes to graph area. - Expected Behavior: - New entities are created when dragging shape nodes to graph area. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the shape nodes to the graph area, and ensure a new entity is created - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the shape nodes to the graph area, and ensure a new entity is created + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + helper.init_idle() + helper.open_level("Physics", "Base") - # Listen for entity creation notifications so we can check if the entity created - # from adding shape nodes has the appropriate Shape Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Shape mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - shapes = { - 'BoxShapeNode': 'Box Shape', - 'CapsuleShapeNode': 'Capsule Shape', - 'CompoundShapeNode': 'Compound Shape', - 'CylinderShapeNode': 'Cylinder Shape', - 'PolygonPrismShapeNode': 'Polygon Prism Shape', - 'SphereShapeNode': 'Sphere Shape', - 'TubeShapeNode': 'Tube Shape', - 'DiskShapeNode': 'Disk Shape' - } + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = [] - for name in shapes: - componentNames.append(shapes[name]) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Create nodes for all the shapes we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in shapes: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Listen for entity creation notifications so we can check if the entity created + # from adding shape nodes has the appropriate Shape Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - shapeComponent = shapes[nodeName] - componentTypeId = componentTypeIds[shapeComponent] - hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, - componentTypeId) - self.test_success = self.test_success and hasComponent - if hasComponent: - self.log("{node} created new Entity with {component} Component".format(node=nodeName, - component=shapeComponent)) + # Shape mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + shapes = { + 'BoxShapeNode': 'Box Shape', + 'CapsuleShapeNode': 'Capsule Shape', + 'CompoundShapeNode': 'Compound Shape', + 'CylinderShapeNode': 'Cylinder Shape', + 'PolygonPrismShapeNode': 'Polygon Prism Shape', + 'SphereShapeNode': 'Sphere Shape', + 'TubeShapeNode': 'Tube Shape', + 'DiskShapeNode': 'Disk Shape' + } - x += 40.0 - y += 40.0 + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = [] + for name in shapes: + componentNames.append(shapes[name]) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - # Stop listening for entity creation notifications - handler.disconnect() + # Create nodes for all the shapes we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in shapes: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + + shapeComponent = shapes[nodeName] + componentTypeId = componentTypeIds[shapeComponent] + hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, + componentTypeId) + Report.info(f"Node: {nodeName} | Component: {shapeComponent}") + Report.result(Tests.component_added, hasComponent) + + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestShapeNodeEntityCreate() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(ShapeNodes_EntityCreatedOnNodeAdd) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py index 2416e05fdf..d2708f643d 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py @@ -5,127 +5,129 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + entity_deleted = ( + "Entity was deleted when node was removed", + "Entity was not deleted as expected when node was removed" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID createdEntityId = None deletedEntityId = None -class TestShapeNodeEntityDelete(EditorTestHelper): +def ShapeNodes_EntityRemovedOnNodeDelete(): + """ + Summary: + This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="ShapeNodeEntityDelete", args=["level"]) + Expected Behavior: + Entities are removed when shape nodes are deleted from a graph. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the shape nodes to the graph area, and ensure a new entity is created + 4) Delete the nodes, and ensure the newly created entities are removed - Expected Behavior: - Entities are removed when shape nodes are deleted from a graph. + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the shape nodes to the graph area, and ensure a new entity is created - 4) Delete the nodes, and ensure the newly created entities are removed + :return: None + """ - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - :return: None - """ + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def onEntityCreated(parameters): - global createdEntityId - createdEntityId = parameters[0] - - def onEntityDeleted(parameters): - global deletedEntityId - deletedEntityId = parameters[0] + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') - - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") - - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") - - # Listen for entity creation/deletion notifications so we can verify the - # Entity created when adding a new also gets deleted when the node is deleted - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) - handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) - - # All of the shape nodes that we support - shapes = [ - 'BoxShapeNode', - 'CapsuleShapeNode', - 'CompoundShapeNode', - 'CylinderShapeNode', - 'PolygonPrismShapeNode', - 'SphereShapeNode', - 'TubeShapeNode', - 'DiskShapeNode' - ] - - # Create nodes for all the shapes we support and check if the Entity is created - # and then deleted when the node is removed - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in shapes: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - - removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) - - # Verify that the created Entity for this node matches the Entity that gets - # deleted when the node is removed - self.test_success = self.test_success and removed and createdEntityId.invoke("Equal", deletedEntityId) - if removed and createdEntityId.invoke("Equal", deletedEntityId): - self.log("{node} corresponding Entity was deleted when node is removed".format(node=nodeName)) - - # Stop listening for entity creation/deletion notifications - handler.disconnect() + def onEntityCreated(parameters): + global createdEntityId + createdEntityId = parameters[0] + + def onEntityDeleted(parameters): + global deletedEntityId + deletedEntityId = parameters[0] + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) + + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) + + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) + + # Listen for entity creation/deletion notifications so we can verify the + # Entity created when adding a new also gets deleted when the node is deleted + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) + handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) + + # All of the shape nodes that we support + shapes = [ + 'BoxShapeNode', + 'CapsuleShapeNode', + 'CompoundShapeNode', + 'CylinderShapeNode', + 'PolygonPrismShapeNode', + 'SphereShapeNode', + 'TubeShapeNode', + 'DiskShapeNode' + ] + + # Create nodes for all the shapes we support and check if the Entity is created + # and then deleted when the node is removed + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in shapes: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + + removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) + + # Verify that the created Entity for this node matches the Entity that gets + # deleted when the node is removed + Report.info(f"Node: {nodeName}") + Report.result(Tests.entity_deleted, removed and createdEntityId.invoke("Equal", deletedEntityId)) + + # Stop listening for entity creation/deletion notifications + handler.disconnect() -test = TestShapeNodeEntityDelete() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(ShapeNodes_EntityRemovedOnNodeDelete) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Slice_CreateInstantiate.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Slice_CreateInstantiate.py new file mode 100644 index 0000000000..c5ab08f99a --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Slice_CreateInstantiate.py @@ -0,0 +1,84 @@ +""" +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. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + + +class Tests: + slice_created = ( + "Slice created successfully", + "Failed to create slice" + ) + slice_instantiated = ( + "Slice instantiated successfully", + "Failed to instantiate slice" + ) + + +def Slice_CreateInstantiate(): + """ + Summary: + A slice containing the LandscapeCanvas component can be created/instantiated. + + Expected Result: + Slice is created/processed/instantiated successfully and free of errors/warnings. + + Test Steps: + 1) Open a simple level + 2) Create a new entity with a Landscape Canvas component + 3) Create a slice of the new entity + 4) Instantiate a new copy of the slice + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ + + import os + + import azlmbr.math as math + import azlmbr.bus as bus + import azlmbr.asset as asset + import azlmbr.slice as slice + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + def path_is_valid_asset(asset_path): + asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_path, math.Uuid(), False) + return asset_id.invoke("IsValid") + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Create entity with Landscape Canvas component + position = math.Vector3(512.0, 512.0, 32.0) + landscape_canvas = hydra.Entity("landscape_canvas_entity") + landscape_canvas.create_entity(position, ["Landscape Canvas"]) + + # Create slice from the created entity + slice_path = os.path.join("slices", "TestSlice.slice") + slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", landscape_canvas.id, slice_path) + + # Verify if slice is created + helper.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0) + Report.result(Tests.slice_created, path_is_valid_asset(slice_path)) + + # Instantiate slice + transform = math.Transform_CreateIdentity() + asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", slice_path, math.Uuid(), False) + test_slice = slice.SliceRequestBus(bus.Broadcast, "InstantiateSliceFromAssetId", asset_id, transform) + helper.wait_for_condition(lambda: test_slice.IsValid(), 5.0) + Report.result(Tests.slice_instantiated, test_slice.IsValid()) + + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(Slice_CreateInstantiate) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py index 2156795b1a..3169908621 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py @@ -5,210 +5,217 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + preview_entity_set = ( + "Random Noise Gradient component Preview Entity property set to Box Shape EntityId", + "Unexpected entity set in Random Noise Gradient Preview Entity property" + ) + dither_inbound_gradient_set = ( + "Dither Gradient Modifier component Inbound Gradient property set to Random Noise Gradient EntityId", + "Unexpected entity set in Dither Gradient's Inbound Gradient property" + ) + mixer_inbound_gradient_set = ( + "Gradient Mixer component Inbound Gradient extendable property set to Dither Gradient Modifier EntityId", + "Unexpected entity set in Gradient Mixer's Inbound Gradient property" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestSlotConnectionsUpdateComponents(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="SlotConnectionsUpdateComponents", args=["level"]) +def SlotConnections_UpdateComponentReferences(): + """ + Summary: + This test verifies that the Landscape Canvas slot connections properly update component references. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas slot connections properly update component references. + Expected Behavior: + A reference created through slot connections in Landscape Canvas is reflected in the Entity Inspector. - Expected Behavior: - A reference created through slot connections in Landscape Canvas is reflected in the Entity Inspector. + Test Steps: + 1) Open an existing level + 2) Open Landscape Canvas and create a new graph + 3) Several nodes are added to a graph, and connections are set between the nodes + 4) Component references are verified via Entity Inspector - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Several nodes are added to a graph, and connections are set between the nodes - 4) Component references are verified via Entity Inspector + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math + import azlmbr.paths - :return: None - """ + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Retrieve the proper component TypeIds per component name - componentNames = [ - 'Random Noise Gradient', - 'Dither Gradient Modifier', - 'Gradient Mixer' - ] - componentTypeIds = hydra.get_component_type_id_map(componentNames) - - # Helper method for retrieving an EntityId from a specific property on a component - def getEntityIdFromComponentProperty(targetEntityId, componentTypeName, propertyPath): - componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', targetEntityId, - componentTypeIds[componentTypeName]) - if not componentOutcome.IsSuccess(): - return None - - component = componentOutcome.GetValue() - propertyOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, - propertyPath) - if not propertyOutcome.IsSuccess(): - return None - - return propertyOutcome.GetValue() - - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] - - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') - - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") - - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") - - # Listen for entity creation notifications so we can verify the component EntityId - # references are set correctly when connecting slots on the nodes - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) - - positionX = 10.0 - positionY = 10.0 - offsetX = 340.0 - offsetY = 100.0 - - # Add a box shape node to the graph - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - boxShapeNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'BoxShapeNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, boxShapeNode, math.Vector2(positionX, - positionY)) - boxShapeEntityId = newEntityId - - positionX += offsetX - positionY += offsetY - - # Add a random noise gradient node to the graph - randomNoiseNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'RandomNoiseGradientNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, randomNoiseNode, math.Vector2(positionX, - positionY)) - randomNoiseEntityId = newEntityId - - positionX += offsetX - positionY += offsetY - - # Add a dither gradient modifier node to the graph - ditherNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'DitherGradientModifierNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, ditherNode, math.Vector2(positionX, - positionY)) - ditherEntityId = newEntityId - - positionX += offsetX - positionY += offsetY - - # Add a gradient mixer node to the graph - gradientMixerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'GradientMixerNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, gradientMixerNode, math.Vector2(positionX, - positionY)) - gradientMixerEntityId = newEntityId - - boundsSlotId = graph.GraphModelSlotId('Bounds') - previewBoundsSlotId = graph.GraphModelSlotId('PreviewBounds') - inboundGradientSlotId = graph.GraphModelSlotId('InboundGradient') - outboundGradientSlotId = graph.GraphModelSlotId('OutboundGradient') - - # Connect slots on our nodes to test all slot types like so: - # Shape -> Gradient -> Gradient Modifier -> Gradient Mixer - # - # Which tests the following slot types: - # * Shape -> Preview Bounds - # * Gradient Output -> Gradient Modifier - # * Gradient Output -> Gradient Mixer (extendable slots) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, - randomNoiseNode, previewBoundsSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, randomNoiseNode, - outboundGradientSlotId, ditherNode, inboundGradientSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, ditherNode, - outboundGradientSlotId, gradientMixerNode, inboundGradientSlotId) - - # Delay to allow all the underlying component properties to be updated after the slot connections are made - general.idle_wait(1.0) - - # Verify the Preview EntityId property on our Random Noise Gradient component has been set to our Box Shape's - # EntityId - previewEntityId = getEntityIdFromComponentProperty(randomNoiseEntityId, 'Random Noise Gradient', - 'Preview Settings|Pin Preview to Shape') - random_gradient_success = previewEntityId and boxShapeEntityId.invoke("Equal", previewEntityId) - self.test_success = self.test_success and random_gradient_success - if random_gradient_success: - self.log("Random Noise Gradient component Preview Entity property set to Box Shape EntityId") - - # Verify the Inbound Gradient EntityId property on our Dither Gradient Modifier component has been set to our - # Random Noise Gradient's EntityId - inboundGradientEntityId = getEntityIdFromComponentProperty(ditherEntityId, 'Dither Gradient Modifier', - 'Configuration|Gradient|Gradient Entity Id') - dither_gradient_success = inboundGradientEntityId and randomNoiseEntityId.invoke("Equal", - inboundGradientEntityId) - self.test_success = self.test_success and dither_gradient_success - if dither_gradient_success: - self.log("Dither Gradient Modifier component Inbound Gradient property set to Random Noise Gradient " - "EntityId") - - # Verify the Inbound Gradient Mixer EntityId property on our Gradient Mixer component has been set to our - # Dither Gradient Modifier's EntityId - inboundGradientMixerEntityId = getEntityIdFromComponentProperty(gradientMixerEntityId, 'Gradient Mixer', - 'Configuration|Layers|[0]|Gradient|Gradient Entity Id') - gradient_mixer_success = inboundGradientMixerEntityId and ditherEntityId.invoke("Equal", - inboundGradientMixerEntityId) - self.test_success = self.test_success and gradient_mixer_success - if gradient_mixer_success: - self.log("Gradient Mixer component Inbound Gradient extendable property set to Dither Gradient Modifier " - "EntityId") - - # Stop listening for entity creation notifications - handler.disconnect() + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID -test = TestSlotConnectionsUpdateComponents() -test.run() + # Retrieve the proper component TypeIds per component name + componentNames = [ + 'Random Noise Gradient', + 'Dither Gradient Modifier', + 'Gradient Mixer' + ] + componentTypeIds = hydra.get_component_type_id_map(componentNames) + + # Helper method for retrieving an EntityId from a specific property on a component + def getEntityIdFromComponentProperty(targetEntityId, componentTypeName, propertyPath): + componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', targetEntityId, + componentTypeIds[componentTypeName]) + + if not componentOutcome.IsSuccess(): + return None + + component = componentOutcome.GetValue() + propertyOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, + propertyPath) + if not propertyOutcome.IsSuccess(): + return None + + return propertyOutcome.GetValue() + + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) + + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) + + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) + + # Listen for entity creation notifications so we can verify the component EntityId + # references are set correctly when connecting slots on the nodes + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) + + positionX = 10.0 + positionY = 10.0 + offsetX = 340.0 + offsetY = 100.0 + + # Add a box shape node to the graph + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + boxShapeNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'BoxShapeNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, boxShapeNode, math.Vector2(positionX, + positionY)) + boxShapeEntityId = newEntityId + + positionX += offsetX + positionY += offsetY + + # Add a random noise gradient node to the graph + randomNoiseNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'RandomNoiseGradientNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, randomNoiseNode, math.Vector2(positionX, + positionY)) + randomNoiseEntityId = newEntityId + + positionX += offsetX + positionY += offsetY + + # Add a dither gradient modifier node to the graph + ditherNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'DitherGradientModifierNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, ditherNode, math.Vector2(positionX, + positionY)) + ditherEntityId = newEntityId + + positionX += offsetX + positionY += offsetY + + # Add a gradient mixer node to the graph + gradientMixerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'GradientMixerNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, gradientMixerNode, math.Vector2(positionX, + positionY)) + gradientMixerEntityId = newEntityId + + boundsSlotId = graph.GraphModelSlotId('Bounds') + previewBoundsSlotId = graph.GraphModelSlotId('PreviewBounds') + inboundGradientSlotId = graph.GraphModelSlotId('InboundGradient') + outboundGradientSlotId = graph.GraphModelSlotId('OutboundGradient') + + # Connect slots on our nodes to test all slot types like so: + # Shape -> Gradient -> Gradient Modifier -> Gradient Mixer + # + # Which tests the following slot types: + # * Shape -> Preview Bounds + # * Gradient Output -> Gradient Modifier + # * Gradient Output -> Gradient Mixer (extendable slots) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, + randomNoiseNode, previewBoundsSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, randomNoiseNode, + outboundGradientSlotId, ditherNode, inboundGradientSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, ditherNode, + outboundGradientSlotId, gradientMixerNode, inboundGradientSlotId) + + # Delay to allow all the underlying component properties to be updated after the slot connections are made + general.idle_wait(1.0) + + + # Verify the Preview EntityId property on our Random Noise Gradient component has been set to our Box Shape's + # EntityId + previewEntityId = getEntityIdFromComponentProperty(randomNoiseEntityId, 'Random Noise Gradient', + 'Preview Settings|Pin Preview to Shape') + random_gradient_success = previewEntityId and boxShapeEntityId.invoke("Equal", previewEntityId) + Report.result(Tests.preview_entity_set, random_gradient_success) + + # Verify the Inbound Gradient EntityId property on our Dither Gradient Modifier component has been set to our + # Random Noise Gradient's EntityId + inboundGradientEntityId = getEntityIdFromComponentProperty(ditherEntityId, 'Dither Gradient Modifier', + 'Configuration|Gradient|Gradient Entity Id') + dither_gradient_success = inboundGradientEntityId and randomNoiseEntityId.invoke("Equal", + inboundGradientEntityId) + Report.result(Tests.dither_inbound_gradient_set, dither_gradient_success) + + # Verify the Inbound Gradient Mixer EntityId property on our Gradient Mixer component has been set to our + # Dither Gradient Modifier's EntityId + inboundGradientMixerEntityId = getEntityIdFromComponentProperty(gradientMixerEntityId, 'Gradient Mixer', + 'Configuration|Layers|[0]|Gradient|Gradient Entity Id') + gradient_mixer_success = inboundGradientMixerEntityId and ditherEntityId.invoke("Equal", + inboundGradientMixerEntityId) + Report.result(Tests.mixer_inbound_gradient_set, gradient_mixer_success) + + # Stop listening for entity creation notifications + handler.disconnect() + + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(SlotConnections_UpdateComponentReferences) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main.py new file mode 100644 index 0000000000..af4855a546 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main.py @@ -0,0 +1,29 @@ +""" +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. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +import os +import pytest +import sys + +import ly_test_tools.environment.file_system as file_system + +sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../automatedtesting_shared') +from base import TestAutomationBase + + +@pytest.mark.SUITE_main +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(TestAutomationBase): + + def test_LandscapeCanvas_SlotConnections_UpdateComponentReferences(self, request, workspace, editor, launcher_platform): + from .EditorScripts import SlotConnections_UpdateComponentReferences as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GradientMixer_NodeConstruction(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientMixer_NodeConstruction as test_module + self._run_test(request, workspace, editor, test_module) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main_Optimized.py new file mode 100644 index 0000000000..68bac24452 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main_Optimized.py @@ -0,0 +1,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. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +import pytest + +from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite + + +@pytest.mark.SUITE_periodic +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(EditorTestSuite): + + class test_LandscapeCanvas_SlotConnections_UpdateComponentReferences(EditorSharedTest): + from .EditorScripts import SlotConnections_UpdateComponentReferences as test_module + + class test_LandscapeCanvas_GradientMixer_NodeConstruction(EditorSharedTest): + from .EditorScripts import GradientMixer_NodeConstruction as test_module diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic.py new file mode 100644 index 0000000000..ef8b3e492b --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic.py @@ -0,0 +1,121 @@ +""" +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. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +import os +import pytest +import sys + +import ly_test_tools.environment.file_system as file_system + +sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../automatedtesting_shared') +from base import TestAutomationBase + + +@pytest.fixture +def remove_test_slice(request, workspace, project): + file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice.slice")], True, True) + + def teardown(): + file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice.slice")], True, + True) + + request.addfinalizer(teardown) + + +@pytest.mark.SUITE_periodic +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(TestAutomationBase): + + def test_LandscapeCanvas_AreaNodes_DependentComponentsAdded(self, request, workspace, editor, launcher_platform): + from .EditorScripts import AreaNodes_DependentComponentsAdded as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_AreaNodes_EntityCreatedOnNodeAdd(self, request, workspace, editor, launcher_platform): + from .EditorScripts import AreaNodes_EntityCreatedOnNodeAdd as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_AreaNodes_EntityRemovedOnNodeDelete(self, request, workspace, editor, launcher_platform): + from .EditorScripts import AreaNodes_EntityRemovedOnNodeDelete as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_LayerExtenderNodes_ComponentEntitySync(self, request, workspace, editor, launcher_platform): + from .EditorScripts import LayerExtenderNodes_ComponentEntitySync as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_Edit_DisabledNodeDuplication(self, request, workspace, editor, launcher_platform): + from .EditorScripts import Edit_DisabledNodeDuplication as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_Edit_UndoNodeDelete_SliceEntity(self, request, workspace, editor, launcher_platform): + from .EditorScripts import Edit_UndoNodeDelete_SliceEntity as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_NewGraph_CreatedSuccessfully(self, request, workspace, editor, launcher_platform): + from .EditorScripts import NewGraph_CreatedSuccessfully as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_Component_AddedRemoved(self, request, workspace, editor, launcher_platform): + from .EditorScripts import Component_AddedRemoved as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GraphClosed_OnLevelChange(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GraphClosed_OnLevelChange as test_module + self._run_test(request, workspace, editor, test_module) + + @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2201") + def test_LandscapeCanvas_GraphClosed_OnEntityDelete(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GraphClosed_OnEntityDelete as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GraphClosed_TabbedGraphClosesIndependently(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GraphClosed_TabbedGraph as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_Slice_CreateInstantiate(self, request, workspace, editor, remove_test_slice, launcher_platform): + from .EditorScripts import Slice_CreateInstantiate as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GradientModifierNodes_EntityCreatedOnNodeAdd(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientModifierNodes_EntityCreatedOnNodeAdd as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GradientModifierNodes_EntityRemovedOnNodeDelete(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientModifierNodes_EntityRemovedOnNodeDelete as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GradientNodes_DependentComponentsAdded(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientNodes_DependentComponentsAdded as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GradientNodes_EntityCreatedOnNodeAdd(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientNodes_EntityCreatedOnNodeAdd as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GradientNodes_EntityRemovedOnNodeDelete(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientNodes_EntityRemovedOnNodeDelete as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GraphUpdates_UpdateComponents(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GraphUpdates_UpdateComponents as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_ComponentUpdates_UpdateGraph(self, request, workspace, editor, launcher_platform): + from .EditorScripts import ComponentUpdates_UpdateGraph as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_LayerBlender_NodeConstruction(self, request, workspace, editor, launcher_platform): + from .EditorScripts import LayerBlender_NodeConstruction as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_ShapeNodes_EntityCreatedOnNodeAdd(self, request, workspace, editor, launcher_platform): + from .EditorScripts import ShapeNodes_EntityCreatedOnNodeAdd as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_ShapeNodes_EntityRemovedOnNodeDelete(self, request, workspace, editor, launcher_platform): + from .EditorScripts import ShapeNodes_EntityRemovedOnNodeDelete as test_module + self._run_test(request, workspace, editor, test_module) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic_Optimized.py new file mode 100644 index 0000000000..59e8b1fe90 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic_Optimized.py @@ -0,0 +1,89 @@ +""" +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. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +import os +import pytest + +import ly_test_tools.environment.file_system as file_system +from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite + + +@pytest.mark.SUITE_periodic +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(EditorTestSuite): + + class test_LandscapeCanvas_AreaNodes_DependentComponentsAdded(EditorSharedTest): + from .EditorScripts import AreaNodes_DependentComponentsAdded as test_module + + class test_LandscapeCanvas_AreaNodes_EntityCreatedOnNodeAdd(EditorSharedTest): + from .EditorScripts import AreaNodes_EntityCreatedOnNodeAdd as test_module + + class test_LandscapeCanvas_AreaNodes_EntityRemovedOnNodeDelete(EditorSharedTest): + from .EditorScripts import AreaNodes_EntityRemovedOnNodeDelete as test_module + + class test_LandscapeCanvas_LayerExtenderNodes_ComponentEntitySync(EditorSharedTest): + from .EditorScripts import LayerExtenderNodes_ComponentEntitySync as test_module + + class test_LandscapeCanvas_Edit_DisabledNodeDuplication(EditorSharedTest): + from .EditorScripts import Edit_DisabledNodeDuplication as test_module + + class test_LandscapeCanvas_Edit_UndoNodeDelete_SliceEntity(EditorSharedTest): + from .EditorScripts import Edit_UndoNodeDelete_SliceEntity as test_module + + class test_LandscapeCanvas_NewGraph_CreatedSuccessfully(EditorSharedTest): + from .EditorScripts import NewGraph_CreatedSuccessfully as test_module + + class test_LandscapeCanvas_Component_AddedRemoved(EditorSharedTest): + from .EditorScripts import Component_AddedRemoved as test_module + + class test_LandscapeCanvas_GraphClosed_OnLevelChange(EditorSharedTest): + from .EditorScripts import GraphClosed_OnLevelChange as test_module + + @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2201") + class test_LandscapeCanvas_GraphClosed_OnEntityDelete(EditorSharedTest): + from .EditorScripts import GraphClosed_OnEntityDelete as test_module + + class test_LandscapeCanvas_GraphClosed_TabbedGraphClosesIndependently(EditorSharedTest): + from .EditorScripts import GraphClosed_TabbedGraph as test_module + + class test_LandscapeCanvas_Slice_CreateInstantiate(EditorSingleTest): + # Custom teardown to remove slice asset created during test + def teardown(self, request, workspace, editor, editor_test_results, launcher_platform): + file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "slices", + "TestSlice.slice")], True, True) + from .EditorScripts import Slice_CreateInstantiate as test_module + + class test_LandscapeCanvas_GradientModifierNodes_EntityCreatedOnNodeAdd(EditorSharedTest): + from .EditorScripts import GradientModifierNodes_EntityCreatedOnNodeAdd as test_module + + class test_LandscapeCanvas_GradientModifierNodes_EntityRemovedOnNodeDelete(EditorSharedTest): + from .EditorScripts import GradientModifierNodes_EntityRemovedOnNodeDelete as test_module + + class test_LandscapeCanvas_GradientNodes_DependentComponentsAdded(EditorSharedTest): + from .EditorScripts import GradientNodes_DependentComponentsAdded as test_module + + class test_LandscapeCanvas_GradientNodes_EntityCreatedOnNodeAdd(EditorSharedTest): + from .EditorScripts import GradientNodes_EntityCreatedOnNodeAdd as test_module + + class test_LandscapeCanvas_GradientNodes_EntityRemovedOnNodeDelete(EditorSharedTest): + from .EditorScripts import GradientNodes_EntityRemovedOnNodeDelete as test_module + + class test_LandscapeCanvas_GraphUpdates_UpdateComponents(EditorSharedTest): + from .EditorScripts import GraphUpdates_UpdateComponents as test_module + + class test_LandscapeCanvas_ComponentUpdates_UpdateGraph(EditorSharedTest): + from .EditorScripts import ComponentUpdates_UpdateGraph as test_module + + class test_LandscapeCanvas_LayerBlender_NodeConstruction(EditorSharedTest): + from .EditorScripts import LayerBlender_NodeConstruction as test_module + + class test_LandscapeCanvas_ShapeNodes_EntityCreatedOnNodeAdd(EditorSharedTest): + from .EditorScripts import ShapeNodes_EntityCreatedOnNodeAdd as test_module + + class test_LandscapeCanvas_ShapeNodes_EntityRemovedOnNodeDelete(EditorSharedTest): + from .EditorScripts import ShapeNodes_EntityRemovedOnNodeDelete as test_module From e67485b51f11cc351c768321900cf0e1065f58df Mon Sep 17 00:00:00 2001 From: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> Date: Thu, 19 Aug 2021 17:07:32 -0500 Subject: [PATCH 33/54] Gradient Signal automation optimizations with TestAutomationBase/parallelization (#3316) * GradientSignal automation optimizations with TestAutomationBase/parallelization * Changing Gradient Signal test registration to use TestAutomationBase Signed-off-by: jckand-amzn --- .../PythonTests/largeworlds/CMakeLists.txt | 2 +- .../GradientGenerators_Incompatibilities.py | 198 +++++++------ .../GradientModifiers_Incompatibilities.py | 268 +++++++++--------- ...ClearingPinnedEntitySetsPreviewToOrigin.py | 200 +++++++------ ...eviewSettings_DefaultPinnedEntityIsSelf.py | 149 +++++----- ...GradientReferencesAddRemoveSuccessfully.py | 144 +++++----- ...SurfaceTagEmitter_ComponentDependencies.py | 200 +++++++------ ...mitter_SurfaceTagsAddRemoveSuccessfully.py | 126 ++++---- ...ponentIncompatibleWithExpectedGradients.py | 178 ++++++------ ...sform_ComponentIncompatibleWithSpawners.py | 154 +++++----- ..._FrequencyZoomCanBeSetBeyondSliderRange.py | 133 +++++---- .../GradientTransform_RequiresShape.py | 130 +++++---- ...ient_ProcessedImageAssignedSuccessfully.py | 144 +++++----- .../ImageGradient_RequiresShape.py | 132 +++++---- .../test_GradientSignal_Periodic.py | 71 +++++ .../test_GradientSignal_Periodic_Optimized.py | 55 ++++ 16 files changed, 1162 insertions(+), 1122 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic.py create mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic_Optimized.py diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt index f3536c4071..f133780fbc 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt @@ -157,7 +157,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ NAME AutomatedTesting::GradientSignalTests_Periodic TEST_SERIAL TEST_SUITE periodic - PATH ${CMAKE_CURRENT_LIST_DIR}/gradient_signal + PATH ${CMAKE_CURRENT_LIST_DIR}/gradient_signal/test_GradientSignal_Periodic.py RUNTIME_DEPENDENCIES AZ::AssetProcessor Legacy::Editor diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py index 37679d34ef..09cd760647 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py @@ -4,124 +4,118 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -class TestGradientGeneratorIncompatibilities(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientGeneratorIncompatibilities", args=["level"]) +def GradientGenerators_Incompatibilities(): + """ + Summary: + This test verifies that components are disabled when conflicting components are present on the same entity. - def run_test(self): - """ - Summary: - This test verifies that components are disabled when conflicting components are present on the same entity. + Expected Behavior: + Gradient Generator components are incompatible with Vegetation area components. - Expected Behavior: - Gradient Generator components are incompatible with Vegetation area components. + Test Steps: + 1) Open a simple level + 2) Create a new entity in the level + 3) Add each Gradient Generator component to an entity, and add a Vegetation Area component to the same entity + 4) Verify that components are only enabled when entity is free of a conflicting component - Test Steps: - 1) Create a new level - 2) Create a new entity in the level - 3) Add each Gradient Generator component to an entity, and add a Vegetation Area component to the same entity - 4) Verify that components are only enabled when entity is free of a conflicting component + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity - gradient_generators = [ - 'Altitude Gradient', - 'Constant Gradient', - 'FastNoise Gradient', - 'Image Gradient', - 'Perlin Noise Gradient', - 'Random Noise Gradient', - 'Shape Falloff Gradient', - 'Slope Gradient', - 'Surface Mask Gradient' - ] - require_transform_modifiers = [ - 'FastNoise Gradient', - 'Image Gradient', - 'Perlin Noise Gradient', - 'Random Noise Gradient' - ] - vegetation_areas = [ - 'Vegetation Layer Spawner', - 'Vegetation Layer Blender', - 'Vegetation Layer Blocker', - 'Vegetation Layer Blocker (Mesh)' - ] - area_dependencies = { - 'Vegetation Layer Spawner': 'Vegetation Asset List', - 'Vegetation Layer Blocker (Mesh)': 'Mesh' - } + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + gradient_generators = [ + 'Altitude Gradient', + 'Constant Gradient', + 'FastNoise Gradient', + 'Image Gradient', + 'Perlin Noise Gradient', + 'Random Noise Gradient', + 'Shape Falloff Gradient', + 'Slope Gradient', + 'Surface Mask Gradient' + ] + require_transform_modifiers = [ + 'FastNoise Gradient', + 'Image Gradient', + 'Perlin Noise Gradient', + 'Random Noise Gradient' + ] + vegetation_areas = [ + 'Vegetation Layer Spawner', + 'Vegetation Layer Blender', + 'Vegetation Layer Blocker', + 'Vegetation Layer Blocker (Mesh)' + ] + area_dependencies = { + 'Vegetation Layer Spawner': 'Vegetation Asset List', + 'Vegetation Layer Blocker (Mesh)': 'Mesh' + } - # For every gradient generator component, verify that they are incompatible - # which each vegetation area component - for component_name in gradient_generators: - for vegetation_area_name in vegetation_areas: - # Create a new Entity in the level - entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Most of these need a shape, so use a Box Shape - hydra.add_component('Box Shape', entity_id) + # For every gradient generator component, verify that they are incompatible + # which each vegetation area component + for component_name in gradient_generators: + for vegetation_area_name in vegetation_areas: + # Create a new Entity in the level + entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - # Add the specific vegetation area dependencies (if necessary) - if vegetation_area_name in area_dependencies: - hydra.add_component(area_dependencies[vegetation_area_name], entity_id) + # Most of these need a shape, so use a Box Shape + hydra.add_component('Box Shape', entity_id) - # Add the vegetation area component we are validating against, then add the - # gradient generator afterwards, so that the gradient generator will actually - # be disabled (if it was present before, it would only get deactivated instead of disabled - # by the vegetation area) - area_component = hydra.add_component(vegetation_area_name, entity_id) - gradient_component = hydra.add_component(component_name, entity_id) + # Add the specific vegetation area dependencies (if necessary) + if vegetation_area_name in area_dependencies: + hydra.add_component(area_dependencies[vegetation_area_name], entity_id) - # Verify the gradient generator component is disabled since the vegetation area is incompatible - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) - self.test_success = self.test_success and not active - if not active: - self.log(f"{component_name} is disabled before removing {vegetation_area_name} component") + # Add the vegetation area component we are validating against, then add the + # gradient generator afterwards, so that the gradient generator will actually + # be disabled (if it was present before, it would only get deactivated instead of disabled + # by the vegetation area) + area_component = hydra.add_component(vegetation_area_name, entity_id) + gradient_component = hydra.add_component(component_name, entity_id) - # Remove the vegetation area component - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [area_component]) + # Verify the gradient generator component is disabled since the vegetation area is incompatible + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) + component_is_disabled = ( + f"{component_name} is disabled before removing {vegetation_area_name} component", + f"{component_name} is unexpectedly enabled before removing {vegetation_area_name} component" + ) + Report.result(component_is_disabled, not active) - # Add required dependencies for our gradient generators after the vegetation - # area has been removed, because the transform modifier is also incompatible - # with the vegetation areas - if component_name in require_transform_modifiers: - hydra.add_component('Gradient Transform Modifier', entity_id) + # Remove the vegetation area component + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [area_component]) - # Verify the gradient generator component is enabled now that the vegetation area is gone - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) - self.test_success = self.test_success and active - if active: - self.log(f"{component_name} is enabled after removing {vegetation_area_name} component") + # Add required dependencies for our gradient generators after the vegetation + # area has been removed, because the transform modifier is also incompatible + # with the vegetation areas + if component_name in require_transform_modifiers: + hydra.add_component('Gradient Transform Modifier', entity_id) + + # Verify the gradient generator component is enabled now that the vegetation area is gone + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) + component_is_enabled = ( + f"{component_name} is enabled after removing {vegetation_area_name} component", + f"{component_name} is unexpectedly disabled after removing {vegetation_area_name} component" + ) + Report.result(component_is_enabled, active) -test = TestGradientGeneratorIncompatibilities() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientGenerators_Incompatibilities) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py index 8908493187..a4d9181744 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py @@ -4,164 +4,162 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -class TestGradientModifiersIncompatibilities(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientModifiersIncompatibilities", args=["level"]) +def GradientModifiers_Incompatibilities(): + """ + Summary: + This test verifies that components are disabled when conflicting components are present on the same entity. - def run_test(self): - """ - Summary: - This test verifies that components are disabled when conflicting components are present on the same entity. + Expected Behavior: + Gradient Modifier components are incompatible with Vegetation area components. - Expected Behavior: - Gradient Modifier components are incompatible with Vegetation area components. + Test Steps: + 1) Open a simple level + 2) Create a new entity in the level + 3) Add each Gradient Modifier component to an entity, and add a Vegetation Area component to the same entity + 4) Verify that components are only enabled when entity is free of a conflicting component - Test Steps: - 1) Create a new level - 2) Create a new entity in the level - 3) Add each Gradient Modifier component to an entity, and add a Vegetation Area component to the same entity - 4) Verify that components are only enabled when entity is free of a conflicting component + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity - gradient_generators = [ - 'Altitude Gradient', - 'Constant Gradient', - 'FastNoise Gradient', - 'Image Gradient', - 'Perlin Noise Gradient', - 'Random Noise Gradient', - 'Shape Falloff Gradient', - 'Slope Gradient', - 'Surface Mask Gradient' - ] - require_transform_modifiers = [ - 'FastNoise Gradient', - 'Image Gradient', - 'Perlin Noise Gradient', - 'Random Noise Gradient' - ] - gradient_modifiers = [ - 'Dither Gradient Modifier', - 'Gradient Mixer', - 'Invert Gradient Modifier', - 'Levels Gradient Modifier', - 'Posterize Gradient Modifier', - 'Smooth-Step Gradient Modifier', - 'Threshold Gradient Modifier' - ] - vegetation_areas = [ - 'Vegetation Layer Spawner', - 'Vegetation Layer Blender', - 'Vegetation Layer Blocker', - 'Vegetation Layer Blocker (Mesh)' - ] - area_dependencies = { - 'Vegetation Layer Spawner': 'Vegetation Asset List', - 'Vegetation Layer Blocker (Mesh)': 'Mesh' - } + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + gradient_generators = [ + 'Altitude Gradient', + 'Constant Gradient', + 'FastNoise Gradient', + 'Image Gradient', + 'Perlin Noise Gradient', + 'Random Noise Gradient', + 'Shape Falloff Gradient', + 'Slope Gradient', + 'Surface Mask Gradient' + ] + require_transform_modifiers = [ + 'FastNoise Gradient', + 'Image Gradient', + 'Perlin Noise Gradient', + 'Random Noise Gradient' + ] + gradient_modifiers = [ + 'Dither Gradient Modifier', + 'Gradient Mixer', + 'Invert Gradient Modifier', + 'Levels Gradient Modifier', + 'Posterize Gradient Modifier', + 'Smooth-Step Gradient Modifier', + 'Threshold Gradient Modifier' + ] + vegetation_areas = [ + 'Vegetation Layer Spawner', + 'Vegetation Layer Blender', + 'Vegetation Layer Blocker', + 'Vegetation Layer Blocker (Mesh)' + ] + area_dependencies = { + 'Vegetation Layer Spawner': 'Vegetation Asset List', + 'Vegetation Layer Blocker (Mesh)': 'Mesh' + } - # For every gradient modifier component, verify that they are incompatible - # which each vegetation area and gradient generator/modifier component - all_gradients = gradient_modifiers + gradient_generators - for component_name in gradient_modifiers: - for vegetation_area_name in vegetation_areas: - # Create a new Entity in the level - entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Most of these need a shape, so use a Box Shape - hydra.add_component('Box Shape', entity_id) + # For every gradient modifier component, verify that they are incompatible + # which each vegetation area and gradient generator/modifier component + all_gradients = gradient_modifiers + gradient_generators + for component_name in gradient_modifiers: + for vegetation_area_name in vegetation_areas: + # Create a new Entity in the level + entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - # Add the specific vegetation area dependencies (if necessary) - if vegetation_area_name in area_dependencies: - hydra.add_component(area_dependencies[vegetation_area_name], entity_id) + # Most of these need a shape, so use a Box Shape + hydra.add_component('Box Shape', entity_id) - # Add the vegetation area component we are validating against, then add the - # gradient modifier afterwards, so that the gradient modifier will actually - # be disabled (if it was present before, it would only get deactivated instead of disabled - # by the vegetation area) - area_component = hydra.add_component(vegetation_area_name, entity_id) - gradient_component = hydra.add_component(component_name, entity_id) + # Add the specific vegetation area dependencies (if necessary) + if vegetation_area_name in area_dependencies: + hydra.add_component(area_dependencies[vegetation_area_name], entity_id) - # Verify the gradient modifier component is disabled since the vegetation area is incompatible - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) - self.test_success = self.test_success and not active - if not active: - self.log("{gradient} is disabled before removing {vegetation_area} component".format(gradient=component_name, vegetation_area=vegetation_area_name)) + # Add the vegetation area component we are validating against, then add the + # gradient modifier afterwards, so that the gradient modifier will actually + # be disabled (if it was present before, it would only get deactivated instead of disabled + # by the vegetation area) + area_component = hydra.add_component(vegetation_area_name, entity_id) + gradient_component = hydra.add_component(component_name, entity_id) - # Remove the vegetation area component - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [area_component]) + # Verify the gradient modifier component is disabled since the vegetation area is incompatible + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) + component_is_disabled = ( + f"{component_name} is disabled before removing {vegetation_area_name} component", + f"{component_name} is unexpectedly enabled before removing {vegetation_area_name} component" + ) + Report.result(component_is_disabled, not active) - # Verify the gradient modifier component is enabled now that the vegetation area is gone - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) - self.test_success = self.test_success and active - if active: - self.log("{gradient} is enabled after removing {vegetation_area} component".format(gradient=component_name, vegetation_area=vegetation_area_name)) + # Remove the vegetation area component + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [area_component]) - for gradient_name in all_gradients: - # Create a new Entity in the level - entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + # Verify the gradient modifier component is enabled now that the vegetation area is gone + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) + component_is_enabled = ( + f"{component_name} is enabled after removing {vegetation_area_name} component", + f"{component_name} is unexpectedly disabled after removing {vegetation_area_name} component" + ) + Report.result(component_is_enabled, active) - # Most of these need a shape, so use a Box Shape - hydra.add_component('Box Shape', entity_id) + for gradient_name in all_gradients: + # Create a new Entity in the level + entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - # Add the specific gradient generator dependencies (if necessary) - conflicting_components = [] - if gradient_name in require_transform_modifiers: - component = hydra.add_component('Gradient Transform Modifier', entity_id) - conflicting_components.append(component) + # Most of these need a shape, so use a Box Shape + hydra.add_component('Box Shape', entity_id) - # Add the gradient component we are validating against, then add the - # gradient modifier afterwards, so that the gradient modifier will actually - # be disabled (if it was present before, it would only get deactivated instead of disabled - # by the other gradient) - component = hydra.add_component(gradient_name, entity_id) + # Add the specific gradient generator dependencies (if necessary) + conflicting_components = [] + if gradient_name in require_transform_modifiers: + component = hydra.add_component('Gradient Transform Modifier', entity_id) conflicting_components.append(component) - gradient_component = hydra.add_component(component_name, entity_id) - # Verify the gradient modifier component is disabled since the other gradient is incompatible - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) - self.test_success = self.test_success and not active - if not active: - self.log("{gradient} is disabled before removing {conflicting_gradient} component".format(gradient=component_name, conflicting_gradient=gradient_name)) + # Add the gradient component we are validating against, then add the + # gradient modifier afterwards, so that the gradient modifier will actually + # be disabled (if it was present before, it would only get deactivated instead of disabled + # by the other gradient) + component = hydra.add_component(gradient_name, entity_id) + conflicting_components.append(component) + gradient_component = hydra.add_component(component_name, entity_id) - # Remove the conflicting gradient component (and transform modifier if it was added) - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', conflicting_components) + # Verify the gradient modifier component is disabled since the other gradient is incompatible + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) + component_is_disabled = ( + f"{component_name} is disabled before removing {gradient_name} component", + f"{component_name} is unexpectedly enabled before removing {gradient_name} component" + ) + Report.result(component_is_disabled, not active) - # Verify the gradient modifier component is enabled now that the other gradient is gone - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) - self.test_success = self.test_success and active - if active: - self.log("{gradient} is enabled after removing {conflicting_gradient} component".format(gradient=component_name, conflicting_gradient=gradient_name)) + # Remove the conflicting gradient component (and transform modifier if it was added) + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', conflicting_components) + + # Verify the gradient modifier component is enabled now that the other gradient is gone + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) + component_is_enabled = ( + f"{component_name} is enabled after removing {gradient_name} component", + f"{component_name} is unexpectedly disabled after removing {gradient_name} component" + ) + Report.result(component_is_enabled, active) -test = TestGradientModifiersIncompatibilities() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientModifiers_Incompatibilities) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py index 73e8b95823..3749f93bf5 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py @@ -5,129 +5,125 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.math as math -import azlmbr.paths -import azlmbr.entity as EntityId +def GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin(): + """ + Summary: + A temporary level is created. An entity for each test case is created and added with the corresponding + components to verify if the gradient transform is set to the world origin. -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper + Expected Behavior: + 1) Preview image updates to reflect change in transform of the gradient sampler. + 2) New Preview Position property is exposed, and set to 0,0,0 (world origin). + 3) Preview Size is set to 1,1,1 by default. + Test Steps: + 1) Open level + 2) Create entity with Random Noise gradient and verify gradient position after clearing pinned entity + 3) Create entity with Levels Gradient Modifier and verify gradient position after clearing pinned entity + 4) Create entity with Posterize Gradient Modifier and verify gradient position after clearing pinned entity + 5) Create entity with Smooth-Step Gradient Modifier and verify gradient position after clearing pinned entity + 6) Create entity with Threshold Gradient Modifier and verify gradient position after clearing pinned entity + 7) Create entity with FastNoise Gradient and verify gradient position after clearing pinned entity + 8) Create entity with Dither Gradient Modifier and verify gradient position after clearing pinned entity + 9) Create entity with Invert Gradient Modifier and verify gradient position after clearing pinned entity + 10) Create entity with Perlin Noise Gradient and verify gradient position after clearing pinned entity -class TestGradientPreviewSettings(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientPreviewSettings_ClearPinnedEntity", args=["level"]) + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - def run_test(self): - """ - Summary: - A temporary level is created. An entity for each test case is created and added with the corresponding - components to verify if the gradient transform is set to the world origin. + :return: None + """ - Expected Behavior: - 1) Preview image updates to reflect change in transform of the gradient sampler. - 2) New Preview Position property is exposed, and set to 0,0,0 (world origin). - 3) Preview Size is set to 1,1,1 by default. + import sys - Test Steps: - 1) Open level - 2) Create entity with Random Noise gradient and verify gradient position after clearing pinned entity - 3) Create entity with Levels Gradient Modifier and verify gradient position after clearing pinned entity - 4) Create entity with Posterize Gradient Modifier and verify gradient position after clearing pinned entity - 5) Create entity with Smooth-Step Gradient Modifier and verify gradient position after clearing pinned entity - 6) Create entity with Threshold Gradient Modifier and verify gradient position after clearing pinned entity - 7) Create entity with FastNoise Gradient and verify gradient position after clearing pinned entity - 8) Create entity with Dither Gradient Modifier and verify gradient position after clearing pinned entity - 9) Create entity with Invert Gradient Modifier and verify gradient position after clearing pinned entity - 10) Create entity with Perlin Noise Gradient and verify gradient position after clearing pinned entity + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.math as math + import azlmbr.entity as EntityId - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - :return: None - """ + WORLD_ORIGIN = math.Vector3(0.0, 0.0, 0.0) + EXPECTED_SIZE = math.Vector3(1.0, 1.0, 1.0) + CLOSE_THRESHOLD = sys.float_info.min - WORLD_ORIGIN = math.Vector3(0.0, 0.0, 0.0) - EXPECTED_SIZE = math.Vector3(1.0, 1.0, 1.0) - CLOSE_THRESHOLD = sys.float_info.min + def create_entity(entity_name, components_to_add): + entity_position = math.Vector3(125.0, 136.0, 32.0) + entity_id = editor.ToolsApplicationRequestBus( + bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + ) + entity = hydra.Entity(entity_name, entity_id) + if entity_id.IsValid(): + print(f"{entity_name} entity Created") + entity.components = [] + for component in components_to_add: + entity.components.append(hydra.add_component(component, entity_id)) + return entity - def create_entity(enity_name, components_to_add): - entity_position = math.Vector3(125.0, 136.0, 32.0) - entity_id = editor.ToolsApplicationRequestBus( - bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + def clear_entityid_check_position(entity_name, components_to_add, check_preview_size=False): + entity = create_entity(entity_name, components_to_add) + hydra.get_set_test(entity, 0, "Preview Settings|Pin Preview to Shape", EntityId.EntityId()) + preview_position = hydra.get_component_property_value( + entity.components[0], "Preview Settings|Preview Position" + ) + preview_set_to_origin = ( + f"{entity_name}: Preview Position set to world origin", + f"{entity_name}: Preview Position set to unexpected coords" + ) + Report.result(preview_set_to_origin, preview_position.IsClose(WORLD_ORIGIN, CLOSE_THRESHOLD)) + if check_preview_size: + preview_size = hydra.get_component_property_value(entity.components[0], "Preview Settings|Preview Size") + preview_size_default_set = ( + f"{entity_name}: Preview Size set as expected", + f"{entity_name}: Preview Size set to unexpected value. Expected {EXPECTED_SIZE}, Found {preview_size}" ) - entity = hydra.Entity(enity_name, entity_id) - if entity_id.IsValid(): - print(f"{enity_name} entity Created") - entity.components = [] - for component in components_to_add: - entity.components.append(hydra.add_component(component, entity_id)) - return entity + Report.result(preview_size_default_set, preview_size.IsClose(EXPECTED_SIZE, CLOSE_THRESHOLD)) + return entity - def clear_entityid_check_position(entity_name, components_to_add, check_preview_size=False): - entity = create_entity(entity_name, components_to_add) - hydra.get_set_test(entity, 0, "Preview Settings|Pin Preview to Shape", EntityId.EntityId()) - preview_position = hydra.get_component_property_value( - entity.components[0], "Preview Settings|Preview Position" - ) - if preview_position.IsClose(WORLD_ORIGIN, CLOSE_THRESHOLD): - print(f"{entity_name} --- Preview Position set to world origin") - if check_preview_size: - preview_size = hydra.get_component_property_value(entity.components[0], "Preview Settings|Preview Size") - if preview_size.IsClose(EXPECTED_SIZE, CLOSE_THRESHOLD): - print(f"{entity_name} --- Preview Size set to (1, 1, 1)") - return entity + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # 1) Open level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + # 2) Create entity with Random Noise gradient and verify gradient position after clearing pinned entity + clear_entityid_check_position( + "Random Noise Gradient", ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"], True + ) - # 2) Create entity with Random Noise gradient and verify gradient position after clearing pinned entity - clear_entityid_check_position( - "Random Noise Gradient", ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"], True - ) + # 3) Create entity with Levels Gradient Modifier and verify gradient position after clearing pinned entity + clear_entityid_check_position("Levels Gradient Modifier", ["Levels Gradient Modifier"]) - # 3) Create entity with Levels Gradient Modifier and verify gradient position after clearing pinned entity - clear_entityid_check_position("Levels Gradient Modifier", ["Levels Gradient Modifier"]) + # 4) Create entity with Posterize Gradient Modifier and verify gradient position after clearing pinned entity + clear_entityid_check_position("Posterize Gradient Modifier", ["Posterize Gradient Modifier"]) - # 4) Create entity with Posterize Gradient Modifier and verify gradient position after clearing pinned entity - clear_entityid_check_position("Posterize Gradient Modifier", ["Posterize Gradient Modifier"]) + # 5) Create entity with Smooth-Step Gradient Modifier and verify gradient position after clearing pinned entity + clear_entityid_check_position("Smooth-Step Gradient Modifier", ["Smooth-Step Gradient Modifier"]) - # 5) Create entity with Smooth-Step Gradient Modifier and verify gradient position after clearing pinned entity - clear_entityid_check_position("Smooth-Step Gradient Modifier", ["Smooth-Step Gradient Modifier"]) + # 6) Create entity with Threshold Gradient Modifier and verify gradient position after clearing pinned entity + clear_entityid_check_position("Threshold Gradient Modifier", ["Threshold Gradient Modifier"]) - # 6) Create entity with Threshold Gradient Modifier and verify gradient position after clearing pinned entity - clear_entityid_check_position("Threshold Gradient Modifier", ["Threshold Gradient Modifier"]) + # 7) Create entity with FastNoise Gradient and verify gradient position after clearing pinned entity + clear_entityid_check_position( + "FastNoise Gradient", ["FastNoise Gradient", "Gradient Transform Modifier", "Box Shape"], True + ) - # 7) Create entity with FastNoise Gradient and verify gradient position after clearing pinned entity - clear_entityid_check_position( - "FastNoise Gradient", ["FastNoise Gradient", "Gradient Transform Modifier", "Box Shape"], True - ) + # 8) Create entity with Dither Gradient Modifier and verify gradient position after clearing pinned entity + clear_entityid_check_position("Dither Gradient Modifier", ["Dither Gradient Modifier"], True) - # 8) Create entity with Dither Gradient Modifier and verify gradient position after clearing pinned entity - clear_entityid_check_position("Dither Gradient Modifier", ["Dither Gradient Modifier"], True) + # 9) Create entity with Invert Gradient Modifier and verify gradient position after clearing pinned entity + clear_entityid_check_position("Invert Gradient Modifier", ["Invert Gradient Modifier"]) - # 9) Create entity with Invert Gradient Modifier and verify gradient position after clearing pinned entity - clear_entityid_check_position("Invert Gradient Modifier", ["Invert Gradient Modifier"]) - - # 10) Create entity with Perlin Noise Gradient and verify gradient position after clearing pinned entity - clear_entityid_check_position( - "Perlin Noise Gradient", ["Perlin Noise Gradient", "Gradient Transform Modifier", "Box Shape"], True - ) + # 10) Create entity with Perlin Noise Gradient and verify gradient position after clearing pinned entity + clear_entityid_check_position( + "Perlin Noise Gradient", ["Perlin Noise Gradient", "Gradient Transform Modifier", "Box Shape"], True + ) -test = TestGradientPreviewSettings() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py index 99a54f614a..3756452710 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py @@ -5,18 +5,6 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper - class Scoped: def __init__(self, constructor, destructor, *args): @@ -33,81 +21,84 @@ class TestParams: self.accessed_component = accessed_component -class TestGradientPreviewSettings(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientPreviewSettings_DefaultPinnedEntity", args=["level"]) +def GradientPreviewSettings_DefaultPinnedEntityIsSelf(): + """ + Summary: + This test verifies default values for the pinned entity for Gradient Preview settings. - def run_test(self): - """ - Summary: - This test verifies default values for the pinned entity for Gradient Preview settings. + Expected Behavior: + Pinned entity is self for all gradient generator/modifiers. - Expected Behavior: - Pinned entity is self for all gradient generator/modifiers. + Test Steps: + 1) Open a simple level + 2) Create a new entity in the level + 3) Add each Gradient Generator component to an entity, and verify the Pin Preview to Shape property is set to + self - Test Steps: - 1) Create a new level - 2) Create a new entity in the level - 3) Add each Gradient Generator component to an entity, and verify the Pin Preview to Shape property is set to - self + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity - def execute_test(test_id, function, *args): - if function(*args): - self.log(test_id + ' has Preview pinned to own Entity result: SUCCESS') + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def create_entity(): - return editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - - def delete_entity(entity_id): - editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityAndAllDescendants', entity_id) - - def attach_components(component_list, entity_id): - components = [] - for i in component_list: - components.append(hydra.add_component(i, entity_id)) - return components - - def validate_id_is_current(param): - entity_ptr = Scoped(create_entity, delete_entity) - added_components = attach_components(param.required_components, entity_ptr.data) - value = hydra.get_component_property_value(added_components[param.accessed_component], - 'Preview Settings|Pin Preview to Shape') - self.test_success = self.test_success and entity_ptr.data.Equal(value) - return entity_ptr.data.Equal(value) - - param_list = [ - TestParams(['Gradient Transform Modifier', 'Box Shape', 'Perlin Noise Gradient'], 2), - TestParams(['Random Noise Gradient', 'Gradient Transform Modifier', 'Box Shape'], 0), - TestParams(['FastNoise Gradient', 'Gradient Transform Modifier', 'Box Shape'], 0), - TestParams(['Dither Gradient Modifier'], 0), - TestParams(['Invert Gradient Modifier'], 0), - TestParams(['Levels Gradient Modifier'], 0), - TestParams(['Posterize Gradient Modifier'], 0), - TestParams(['Smooth-Step Gradient Modifier'], 0), - TestParams(['Threshold Gradient Modifier'], 0) - ] - - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, + def execute_test(test_id, function, *args): + pinned_to_self = ( + f"{test_id} has Preview pinned to self", + f"{test_id} has Preview pinned to a different entity" ) + Report.result(pinned_to_self, function(*args)) - for param in param_list: - execute_test(param.required_components[param.accessed_component], - validate_id_is_current, param) + def create_entity(): + return editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + + def delete_entity(entity_id): + editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityAndAllDescendants', entity_id) + + def attach_components(component_list, entity_id): + components = [] + for i in component_list: + components.append(hydra.add_component(i, entity_id)) + return components + + def validate_id_is_current(param): + entity_ptr = Scoped(create_entity, delete_entity) + added_components = attach_components(param.required_components, entity_ptr.data) + value = hydra.get_component_property_value(added_components[param.accessed_component], + 'Preview Settings|Pin Preview to Shape') + return entity_ptr.data.Equal(value) + + param_list = [ + TestParams(['Gradient Transform Modifier', 'Box Shape', 'Perlin Noise Gradient'], 2), + TestParams(['Random Noise Gradient', 'Gradient Transform Modifier', 'Box Shape'], 0), + TestParams(['FastNoise Gradient', 'Gradient Transform Modifier', 'Box Shape'], 0), + TestParams(['Dither Gradient Modifier'], 0), + TestParams(['Invert Gradient Modifier'], 0), + TestParams(['Levels Gradient Modifier'], 0), + TestParams(['Posterize Gradient Modifier'], 0), + TestParams(['Smooth-Step Gradient Modifier'], 0), + TestParams(['Threshold Gradient Modifier'], 0) + ] + + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + for param in param_list: + execute_test(param.required_components[param.accessed_component], + validate_id_is_current, param) -test = TestGradientPreviewSettings() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientPreviewSettings_DefaultPinnedEntityIsSelf) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSampling_GradientReferencesAddRemoveSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSampling_GradientReferencesAddRemoveSuccessfully.py index 6d88f43d5a..8e85345a6f 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSampling_GradientReferencesAddRemoveSuccessfully.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSampling_GradientReferencesAddRemoveSuccessfully.py @@ -5,92 +5,82 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.math as math -import azlmbr.paths -import azlmbr.entity as EntityId +def GradientSampling_GradientReferencesAddRemoveSuccessfully(): + """ + Summary: + An existing gradient generator can be pinned and cleared to/from the Gradient Entity Id field -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper + Expected Behavior: + Gradient generator is assigned to the Gradient Entity Id field. + Gradient generator is removed from the field. + Test Steps: + 1) Open level + 2) Create a new entity with components "Random Noise Gradient", "Gradient Transform Modifier" and "Box Shape" + 3) Create a new entity with Gradient Modifier's, pin and clear the random noise entity id to the Gradient Id + field in Gradient Modifier -class TestGradientSampling(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientSampling_GradientReferences", args=["level"]) + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - def run_test(self): - """ - Summary: - An existing gradient generator can be pinned and cleared to/from the Gradient Entity Id field + :return: None + """ - Expected Behavior: - Gradient generator is assigned to the Gradient Entity Id field. - Gradient generator is removed from the field. + import azlmbr.math as math + import azlmbr.entity as EntityId - Test Steps: - 1) Open level - 2) Create a new entity with components "Random Noise Gradient", "Gradient Transform Modifier" and "Box Shape" - 3) Create a new entity with Gradient Modifier's, pin and clear the random noise entity id to the Gradient Id - field in Gradient Modifier + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. - - :return: None - """ - - def modifier_pin_clear_to_gradiententityid(modifier): - entity_position = math.Vector3(125.0, 136.0, 32.0) - component_to_add = [modifier] - gradient_modifier = hydra.Entity(modifier) - gradient_modifier.create_entity(entity_position, component_to_add) - gradient_modifier.get_set_test(0, "Configuration|Gradient|Gradient Entity Id", random_noise.id) - entity = hydra.get_component_property_value( - gradient_modifier.components[0], "Configuration|Gradient|Gradient Entity Id" - ) - if entity.Equal(random_noise.id): - print(f"Gradient Generator is pinned to the {modifier} successfully") - else: - print(f"Failed to pin Gradient Generator to the {modifier}") - hydra.get_set_test(gradient_modifier, 0, "Configuration|Gradient|Gradient Entity Id", EntityId.EntityId()) - entity = hydra.get_component_property_value( - gradient_modifier.components[0], "Configuration|Gradient|Gradient Entity Id" - ) - if entity.Equal(EntityId.EntityId()): - print(f"Gradient Generator is cleared from the {modifier} successfully") - else: - print(f"Failed to clear Gradient Generator from the {modifier}") - - # 1) Open level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) - - # 2) Create a new entity with components "Random Noise Gradient", "Gradient Transform Modifier" and "Box Shape" + def modifier_pin_clear_to_gradiententityid(modifier): entity_position = math.Vector3(125.0, 136.0, 32.0) - components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"] - random_noise = hydra.Entity("Random_Noise") - random_noise.create_entity(entity_position, components_to_add) + component_to_add = [modifier] + gradient_modifier = hydra.Entity(modifier) + gradient_modifier.create_entity(entity_position, component_to_add) + gradient_modifier.get_set_test(0, "Configuration|Gradient|Gradient Entity Id", random_noise.id) + entity = hydra.get_component_property_value( + gradient_modifier.components[0], "Configuration|Gradient|Gradient Entity Id" + ) + gradient_pinned_to_modifier = ( + f"Gradient Generator is pinned to the {modifier} successfully", + f"Failed to pin Gradient Generator to the {modifier}" + ) + Report.result(gradient_pinned_to_modifier, entity.Equal(random_noise.id)) + hydra.get_set_test(gradient_modifier, 0, "Configuration|Gradient|Gradient Entity Id", EntityId.EntityId()) + entity = hydra.get_component_property_value( + gradient_modifier.components[0], "Configuration|Gradient|Gradient Entity Id" + ) + gradient_cleared_from_modifier = ( + f"Gradient Generator is cleared from the {modifier} successfully", + f"Failed to clear Gradient Generator from the {modifier}" + ) + Report.result(gradient_cleared_from_modifier, entity.Equal(EntityId.EntityId())) - # 3) Create a new entity with Gradient Modifier's, pin and clear the random noise entity id to the Gradient Id - # field in Gradient Modifier - modifier_pin_clear_to_gradiententityid("Dither Gradient Modifier") - modifier_pin_clear_to_gradiententityid("Invert Gradient Modifier") - modifier_pin_clear_to_gradiententityid("Levels Gradient Modifier") - modifier_pin_clear_to_gradiententityid("Posterize Gradient Modifier") - modifier_pin_clear_to_gradiententityid("Smooth-Step Gradient Modifier") - modifier_pin_clear_to_gradiententityid("Threshold Gradient Modifier") + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # 2) Create a new entity with components "Random Noise Gradient", "Gradient Transform Modifier" and "Box Shape" + entity_position = math.Vector3(125.0, 136.0, 32.0) + components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"] + random_noise = hydra.Entity("Random_Noise") + random_noise.create_entity(entity_position, components_to_add) + + # 3) Create a new entity with Gradient Modifier's, pin and clear the random noise entity id to the Gradient Id + # field in Gradient Modifier + modifier_pin_clear_to_gradiententityid("Dither Gradient Modifier") + modifier_pin_clear_to_gradiententityid("Invert Gradient Modifier") + modifier_pin_clear_to_gradiententityid("Levels Gradient Modifier") + modifier_pin_clear_to_gradiententityid("Posterize Gradient Modifier") + modifier_pin_clear_to_gradiententityid("Smooth-Step Gradient Modifier") + modifier_pin_clear_to_gradiententityid("Threshold Gradient Modifier") -test = TestGradientSampling() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientSampling_GradientReferencesAddRemoveSuccessfully) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py index 26d791495a..f653515a39 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py @@ -5,114 +5,104 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.math as math -import azlmbr.bus as bus -import azlmbr.entity as entity -import azlmbr.paths -import azlmbr.editor as editor - -sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -class TestGradientSurfaceTagEmitterDependencies(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__( - self, log_prefix="GradientSurfaceTagEmitter_ComponentDependencies", args=["level"] +def GradientSurfaceTagEmitter_ComponentDependencies(): + """ + Summary: + This test verifies that the Gradient Surface Tag Emitter component is dependent on a gradient component. + + Expected Result: + Gradient Surface Tag Emitter component is disabled until a Gradient Generator, Modifier or Gradient Reference + component (and any sub-dependencies) is added to the entity. + + Test Steps: + 1) Open level + 2) Create a new entity with a Gradient Surface Tag Emitter component + 3) Verify the component is disabled until a dependent component is also added to the entity + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + + import azlmbr.math as math + import azlmbr.bus as bus + import azlmbr.entity as entity + import azlmbr.editor as editor + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + def is_enabled(EntityComponentIdPair): + return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Create an entity with Gradient Surface Tag Emitter component + position = math.Vector3(512.0, 512.0, 32.0) + gradient = hydra.Entity("gradient") + gradient.create_entity(position, ["Gradient Surface Tag Emitter"]) + + # Make sure Gradient Surface Tag Emitter is disabled + gradient_surface_tag_disabled = ( + "Gradient Surface Tag Emitter is Disabled", + "Gradient Surface Tag Emitter is Enabled, but should be Disabled without dependencies met" + ) + Report.result(gradient_surface_tag_disabled, not is_enabled(gradient.components[0])) + + # Verify Gradient Surface Tag Emitter component is enabled after adding Gradient, Generator, Modifier + # or Reference component + new_components_to_add = [ + "Dither Gradient Modifier", + "Gradient Mixer", + "Invert Gradient Modifier", + "Levels Gradient Modifier", + "Posterize Gradient Modifier", + "Smooth-Step Gradient Modifier", + "Threshold Gradient Modifier", + "Altitude Gradient", + "Constant Gradient", + "FastNoise Gradient", + "Image Gradient", + "Perlin Noise Gradient", + "Random Noise Gradient", + "Reference Gradient", + "Shape Falloff Gradient", + "Slope Gradient", + "Surface Mask Gradient", + ] + for component in new_components_to_add: + component_list = ["FastNoise Gradient", "Image Gradient", "Perlin Noise Gradient", "Random Noise Gradient"] + if component in component_list: + for Component in ["Gradient Transform Modifier", "Box Shape"]: + hydra.add_component(Component, gradient.id) + typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', [component], + entity.EntityType().Game) + ComponentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', gradient.id, [typeIdsList[0]]) + Components = ComponentOutcome.GetValue() + ComponentIdPair = Components[0] + gradient_enabled = is_enabled(gradient.components[0]) + new_components_enabled = is_enabled(ComponentIdPair) + dependencies_met = ( + f"{component} and Gradient Surface Tag Emitter are enabled", + f"{component} and Gradient Surface Tag Emitter are disabled" ) + Report.result(dependencies_met, new_components_enabled and gradient_enabled) - def run_test(self): - """ - Summary: - This test verifies that the Gradient Surface Tag Emitter component is dependent on a gradient component. - - Expected Result: - Gradient Surface Tag Emitter component is disabled until a Gradient Generator, Modifier or Gradient Reference - component (and any sub-dependencies) is added to the entity. - - Test Steps: - 1) Open level - 2) Create a new entity with a Gradient Surface Tag Emitter component - 3) Verify the component is disabled until a dependent component is also added to the entity - - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. - - :return: None - """ - - def is_enabled(EntityComponentIdPair): - return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) - - # Create empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) - - # Create an entity with Gradient Surface Tag Emitter component - position = math.Vector3(512.0, 512.0, 32.0) - gradient = hydra.Entity("gradient") - gradient.create_entity(position, ["Gradient Surface Tag Emitter"]) - - # Make sure Gradient Surface Tag Emitter is disabled - is_enable = is_enabled(gradient.components[0]) - if not is_enable: - self.log("Gradient Surface Tag Emitter is Disabled") - elif not is_enable: - self.log("Gradient Surface Tag Emitter is Enabled, but should be Disabled without dependencies met") - - # Verify Gradient Surface Tag Emitter component is enabled after adding Gradient, Generator, Modifier - # or Reference component - new_components_to_add = [ - "Dither Gradient Modifier", - "Gradient Mixer", - "Invert Gradient Modifier", - "Levels Gradient Modifier", - "Posterize Gradient Modifier", - "Smooth-Step Gradient Modifier", - "Threshold Gradient Modifier", - "Altitude Gradient", - "Constant Gradient", - "FastNoise Gradient", - "Image Gradient", - "Perlin Noise Gradient", - "Random Noise Gradient", - "Reference Gradient", - "Shape Falloff Gradient", - "Slope Gradient", - "Surface Mask Gradient", - ] - for component in new_components_to_add: - component_list = ["FastNoise Gradient", "Image Gradient", "Perlin Noise Gradient", "Random Noise Gradient"] - if component in component_list: - for Component in ["Gradient Transform Modifier", "Box Shape"]: - hydra.add_component(Component, gradient.id) - typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', [component], - entity.EntityType().Game) - ComponentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', gradient.id, [typeIdsList[0]]) - Components = ComponentOutcome.GetValue() - ComponentIdPair = Components[0] - gradient_enabled = new_components_enabled = False - gradient_enabled = is_enabled(gradient.components[0]) - new_components_enabled = is_enabled(ComponentIdPair) - if new_components_enabled and gradient_enabled: - self.log(f"{component} and Gradient Surface Tag Emitter are enabled") - else: - self.log(f"{component} and Gradient Surface Tag Emitter are disabled") - if component in component_list: - hydra.remove_component("Gradient Transform Modifier", gradient.id) - hydra.remove_component("Box Shape", gradient.id) - hydra.remove_component(component, gradient.id) + if component in component_list: + hydra.remove_component("Gradient Transform Modifier", gradient.id) + hydra.remove_component("Box Shape", gradient.id) + hydra.remove_component(component, gradient.id) -test = TestGradientSurfaceTagEmitterDependencies() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientSurfaceTagEmitter_ComponentDependencies) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py index 44c9792296..90840a135d 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py @@ -5,75 +5,69 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.math as math -import azlmbr.paths -import azlmbr.surface_data as surface_data +def GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(): + """ + Summary: + Entity with Gradient Surface Tag Emitter and Reference Gradient components is created. + And new surface tag has been added and removed. -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper + Expected Behavior: + A new Surface Tag can be added and removed from the component + + Test Steps: + 1) Open level + 2) Create an entity with Gradient Surface Tag Emitter and Reference Gradient components. + 3) Add/ remove Surface Tags + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + + import azlmbr.math as math + import azlmbr.surface_data as surface_data + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # 2) Create an entity with Gradient Surface Tag Emitter and Reference Gradient components. + entity_position = math.Vector3(125.0, 136.0, 32.0) + components_to_add = ["Gradient Surface Tag Emitter", "Reference Gradient"] + entity = hydra.Entity("entity") + entity.create_entity(entity_position, components_to_add) + + # 3) Add/ remove Surface Tags + tag = surface_data.SurfaceTag() + tag.SetTag("water") + pte = hydra.get_property_tree(entity.components[0]) + path = "Configuration|Extended Tags" + pte.add_container_item(path, 0, tag) + success = helper.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 1, 1.0) + tag_added_to_container = ( + "Successfully added surface tag", + "Failed to add surface tag" + ) + Report.result(tag_added_to_container, success) + pte.remove_container_item(path, 0) + success = helper.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 0, 1.0) + tag_removed_from_container = ( + "Successfully removed surface tag", + "Failed to remove surface tag" + ) + Report.result(tag_removed_from_container, success) -class TestGradientSurfaceTagEmitter(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSucessfully", - args=["level"]) +if __name__ == "__main__": - def run_test(self): - """ - Summary: - Entity with Gradient Surface Tag Emitter and Reference Gradient components is created. - And new surface tag has been added and removed. - - Expected Behavior: - A new Surface Tag can be added and removed from the component + from editor_python_test_tools.utils import Report + Report.start_test(GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully) - Test Steps: - 1) Open level - 2) Create an entity with Gradient Surface Tag Emitter and Reference Gradient components. - 3) Add/ remove Surface Tags - - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. - - :return: None - """ - - # 1) Open level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) - - # 2) Create an entity with Gradient Surface Tag Emitter and Reference Gradient components. - entity_position = math.Vector3(125.0, 136.0, 32.0) - components_to_add = ["Gradient Surface Tag Emitter", "Reference Gradient"] - entity = hydra.Entity("entity") - entity.create_entity(entity_position, components_to_add) - - # 3) Add/ remove Surface Tags - tag = surface_data.SurfaceTag() - tag.SetTag("water") - pte = hydra.get_property_tree(entity.components[0]) - path = "Configuration|Extended Tags" - pte.add_container_item(path, 0, tag) - success = self.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 1) - self.test_success = self.test_success and success - print(f"Added SurfaceTag: container count is {pte.get_container_count(path).GetValue()}") - pte.remove_container_item(path, 0) - success = self.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 0) - self.test_success = self.test_success and success - print(f"Removed SurfaceTag: container count is {pte.get_container_count(path).GetValue()}") - - -test = TestGradientSurfaceTagEmitter() -test.run() diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithExpectedGradients.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithExpectedGradients.py index b5f342a15f..5e6df4d52f 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithExpectedGradients.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithExpectedGradients.py @@ -5,118 +5,102 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.math as math -import azlmbr.entity as EntityId +def GradientTransform_ComponentIncompatibleWithExpectedGradients(): + """ + Summary: + A New level is created. A New entity is created with components Gradient Transform Modifier and Box Shape. + Adding components Constant Gradient, Altitude Gradient, Gradient Mixer, Reference Gradient, Shape + Falloff Gradient, Slope Gradient and Surface Mask Gradient to the same entity. -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper + Expected Behavior: + All added components are disabled and inform the user that they are incompatible with the Gradient Transform + Modifier + Test Steps: + 1) Create level + 2) Create a new entity with components Gradient Transform Modifier and Box Shape + 3) Make sure all components are enabled in Entity + 4) Add Constant Gradient, Altitude Gradient, Gradient Mixer, Reference Gradient, Shape + Falloff Gradient, Slope Gradient and Surface Mask Gradient to the same entity + 5) Make sure all newly added components are disabled -class TestGradientTransform_ComponentIncompatibleWithExpectedGradients(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientTransform_ComponentIncompatibleWithExpectedGradients", - args=["level"]) + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - def run_test(self): - """ - Summary: - A New level is created. A New entity is created with components Gradient Transform Modifier and Box Shape. - Adding components Constant Gradient, Altitude Gradient, Gradient Mixer, Reference Gradient, Shape - Falloff Gradient, Slope Gradient and Surface Mask Gradient to the same entity. + :return: None + """ - Expected Behavior: - All added components are disabled and inform the user that they are incompatible with the Gradient Transform - Modifier + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.math as math + import azlmbr.entity as EntityId - Test Steps: - 1) Create level - 2) Create a new entity with components Gradient Transform Modifier and Box Shape - 3) Make sure all components are enabled in Entity - 4) Add Constant Gradient, Altitude Gradient, Gradient Mixer, Reference Gradient, Shape - Falloff Gradient, Slope Gradient and Surface Mask Gradient to the same entity - 5) Make sure all newly added components are disabled + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + def is_enabled(EntityComponentIdPair): + return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) - :return: None - """ + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - def is_enabled(EntityComponentIdPair): - return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) + # 2) Create a new entity with components Gradient Transform Modifier and Box Shape + entity_position = math.Vector3(125.0, 136.0, 32.0) + components_to_add = ["Gradient Transform Modifier", "Box Shape"] + gradient_id = editor.ToolsApplicationRequestBus( + bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + ) + gradient = hydra.Entity("gradient", gradient_id) - # 1) Create level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, + gradient.components = [] + + for component in components_to_add: + gradient.components.append(hydra.add_component(component, gradient_id)) + entity_created = ( + "Entity created successfully", + "Failed to create entity" + ) + Report.critical_result(entity_created, gradient_id.isValid()) + + # 3) Make sure all components are enabled in Entity + index = 0 + for component in components_to_add: + components_enabled = ( + f"{component} is enabled", + f"{component} is unexpectedly disabled" ) + Report.critical_result(components_enabled, is_enabled(gradient.components[index])) + index += 1 - # 2) Create a new entity with components Gradient Transform Modifier and Box Shape - entity_position = math.Vector3(125.0, 136.0, 32.0) - components_to_add = ["Gradient Transform Modifier", "Box Shape"] - gradient_id = editor.ToolsApplicationRequestBus( - bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + # 4) Add Constant Gradient, Altitude Gradient, Gradient Mixer, Reference Gradient, Shape + # Falloff Gradient, Slope Gradient and Surface Mask Gradient to the same entity + new_components_to_add = [ + "Constant Gradient", + "Altitude Gradient", + "Gradient Mixer", + "Reference Gradient", + "Shape Falloff Gradient", + "Slope Gradient", + "Surface Mask Gradient", + ] + new_components_enabled = False + for component in new_components_to_add: + gradient.components.append(hydra.add_component(component, gradient_id)) + gradient_components_disabled = ( + f"{component} is disabled", + f"{component} is enabled, but should be disabled" ) - gradient = hydra.Entity("gradient", gradient_id) - - gradient.components = [] - - for component in components_to_add: - gradient.components.append(hydra.add_component(component, gradient_id)) - if gradient_id.isValid(): - self.log("New Entity Created") - - # 3) Make sure all components are enabled in Entity - index = 0 - for component in components_to_add: - is_enable = is_enabled(gradient.components[index]) - if is_enable: - self.log(f"{component} is Enabled") - self.test_success = self.test_success and is_enable - elif not is_enable: - self.log(f"{component} is disabled, but it should be enabled") - self.test_success = self.test_success and is_enable - break - index += 1 - - # 4) Add Constant Gradient, Altitude Gradient, Gradient Mixer, Reference Gradient, Shape - # Falloff Gradient, Slope Gradient and Surface Mask Gradient to the same entity - new_components_to_add = [ - "Constant Gradient", - "Altitude Gradient", - "Gradient Mixer", - "Reference Gradient", - "Shape Falloff Gradient", - "Slope Gradient", - "Surface Mask Gradient", - ] - index = 2 - new_components_enabled = False - for component in new_components_to_add: - gradient.components.append(hydra.add_component(component, gradient_id)) - new_components_enabled = is_enabled(gradient.components[index]) - if new_components_enabled: - self.log(f"{component} is enabled, but should be disabled") - break + Report.result(gradient_components_disabled, not is_enabled(gradient.components[2])) + if not is_enabled(gradient.components[2]): editor.EditorComponentAPIBus(bus.Broadcast, "RemoveComponents", component) - # 5) Make sure all newly added components are disabled - if not new_components_enabled: - self.log("All newly added components are incompatible and disabled") - self.test_success = self.test_success and not new_components_enabled +if __name__ == "__main__": -test = TestGradientTransform_ComponentIncompatibleWithExpectedGradients() -test.run() + from editor_python_test_tools.utils import Report + Report.start_test(GradientTransform_ComponentIncompatibleWithExpectedGradients) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithSpawners.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithSpawners.py index 54270c5ee5..fd65996fdd 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithSpawners.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithSpawners.py @@ -5,104 +5,88 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.math as math -import azlmbr.entity as EntityId +def GradientTransform_ComponentIncompatibleWithSpawners(): + """ + Summary: + A simple level is opened. A New entity is created with components Gradient Transform Modifier and Box Shape. + Adding a component Vegetation Layer Spawner to the same entity. -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper + Expected Behavior: + The Vegetation Layer Spawner is deactivated and it is communicated that it is incompatible with Gradient + Transform Modifier + Test Steps: + 1) Open a simple level + 2) Create a new entity with components Gradient Transform Modifier and Box Shape + 3) Make sure all components are enabled in Entity + 4) Add Vegetation Layer Spawner to the same entity + 5) Make sure newly added component is disabled -class TestGradientTransform_ComponentIncompatibleWithSpawners(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientTransform_ComponentIncompatibleWithSpawners", - args=["level"]) + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - def run_test(self): - """ - Summary: - A New level is created. A New entity is created with components Gradient Transform Modifier and Box Shape. - Adding a component Vegetation Layer Spawner to the same entity. + :return: None + """ - Expected Behavior: - The Vegetation Layer Spawner is deactivated and it is communicated that it is incompatible with Gradient - Transform Modifier + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.math as math + import azlmbr.entity as EntityId - Test Steps: - 1) Create level - 2) Create a new entity with components Gradient Transform Modifier and Box Shape - 3) Make sure all components are enabled in Entity - 4) Add Vegetation Layer Spawner to the same entity - 5) Make sure newly added component is disabled + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + def is_enabled(EntityComponentIdPair): + return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) - :return: None - """ + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - def is_enabled(EntityComponentIdPair): - return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) + # 2) Create a new entity with components Gradient Transform Modifier and Box Shape + entity_position = math.Vector3(125.0, 136.0, 32.0) + components_to_add = ["Gradient Transform Modifier", "Box Shape"] + gradient_id = editor.ToolsApplicationRequestBus( + bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + ) + gradient = hydra.Entity("gradient", gradient_id) - # 1) Create level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, + gradient.components = [] + + for component in components_to_add: + gradient.components.append(hydra.add_component(component, gradient_id)) + entity_created = ( + "Entity created successfully", + "Failed to create entity" + ) + Report.critical_result(entity_created, gradient_id.isValid()) + + # 3) Make sure all components are enabled in Entity + index = 0 + for component in components_to_add: + components_enabled = ( + f"{component} is enabled", + f"{component} is unexpectedly disabled" ) + Report.critical_result(components_enabled, is_enabled(gradient.components[index])) + index += 1 - # 2) Create a new entity with components Gradient Transform Modifier and Box Shape - entity_position = math.Vector3(125.0, 136.0, 32.0) - components_to_add = ["Gradient Transform Modifier", "Box Shape"] - gradient_id = editor.ToolsApplicationRequestBus( - bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() - ) - gradient = hydra.Entity("gradient", gradient_id) + # 4) Add Vegetation Layer Spawner to the same entity + gradient.components.append(hydra.add_component("Vegetation Layer Spawner", gradient_id)) - gradient.components = [] - - for component in components_to_add: - gradient.components.append(hydra.add_component(component, gradient_id)) - if gradient_id.isValid(): - self.log("New Entity Created") - - # 3) Make sure all components are enabled in Entity - index = 0 - for component in components_to_add: - is_enable = is_enabled(gradient.components[index]) - if is_enable: - self.log(f"{component} is Enabled") - self.test_success = self.test_success and is_enable - elif not is_enable: - self.log(f"{component} is Disabled. But It should be Enabled in an Entity") - self.test_success = self.test_success and is_enable - break - index += 1 - - # 4) Add Vegetation Layer Spawner to the same entity - new_component_to_add = "Vegetation Layer Spawner" - index = 2 - gradient.components.append(hydra.add_component(new_component_to_add, gradient_id)) - new_component_enabled = is_enabled(gradient.components[index]) - - # 5) Make sure newly added component is disabled - if not new_component_enabled: - self.log(f"{new_component_to_add} is incompatible and disabled") - self.test_success = self.test_success and not new_component_enabled - elif new_component_enabled: - self.log(f"{new_component_to_add} is compatible and enabled. But It should be Incompatible and disabled") - self.test_success = self.test_success and new_component_enabled + # 5) Make sure newly added component is disabled + spawner_component_disabled = ( + "Spawner component is disabled", + "Spawner component is unexpectedly enabled" + ) + Report.result(spawner_component_disabled, not is_enabled(gradient.components[2])) -test = TestGradientTransform_ComponentIncompatibleWithSpawners() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientTransform_ComponentIncompatibleWithSpawners) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange.py index 94647a0b6f..530503db86 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange.py @@ -5,87 +5,82 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -""" -C3430292: Frequency Zoom can manually be set higher than 8. -""" -import os -import sys - -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.math as math -import azlmbr.paths -import azlmbr.entity as EntityId - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper +class Tests: + entity_created = ( + "Entity created successfully", + "Failed to create entity" + ) + components_added = ( + "All expected components added to entity", + "Failed to add expected components to entity" + ) + higher_zoom_value_set = ( + "Frequency Zoom is equal to expected value", + "Frequency Zoom is not equal to expected value" + ) -class TestGradientTransformFrequencyZoom(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientTransform_FrequencyZoomBeyondSliders", args=["level"]) +def GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange(): + """ + Summary: + Frequency Zoom can manually be set higher than 8 in a random noise gradient - def run_test(self): - """ - Summary: - Frequency Zoom can manually be set higher than 8 in a random noise gradient + Expected Behavior: + The value properly changes, despite the value being outside of the slider limit - Expected Behavior: - The value properly changes, despite the value being outside of the slider limit + Test Steps: + 1) Open level + 2) Create entity + 3) Add components to the entity + 4) Set the frequency value of the component + 5) Verify if the frequency value is set to higher value - Test Steps: - 1) Open level - 2) Create entity - 3) Add components to the entity - 4) Set the frequency value of the component - 5) Verify if the frequency value is set to higher value + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.math as math + import azlmbr.entity as EntityId - # 1) Open level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # 2) Create entity - entity_position = math.Vector3(125.0, 136.0, 32.0) - entity_id = editor.ToolsApplicationRequestBus( - bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() - ) - if entity_id.IsValid(): - print("Entity Created") + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # 3) Add components to the entity - components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"] - entity = hydra.Entity("entity", entity_id) - entity.components = [] - for component in components_to_add: - entity.components.append(hydra.add_component(component, entity_id)) - print("Components added to the entity") + # 2) Create entity + entity_position = math.Vector3(125.0, 136.0, 32.0) + entity_id = editor.ToolsApplicationRequestBus( + bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + ) + Report.critical_result(Tests.entity_created, entity_id.IsValid()) - # 4) Set the frequency value of the component - hydra.get_set_test(entity, 1, "Configuration|Frequency Zoom", 10) + # 3) Add components to the entity + components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"] + entity = hydra.Entity("entity", entity_id) + entity.components = [] + for component in components_to_add: + entity.components.append(hydra.add_component(component, entity_id)) + Report.critical_result(Tests.components_added, len(entity.components) == 3) - # 5) Verify if the frequency value is set to higher value - curr_value = hydra.get_component_property_value(entity.components[1], "Configuration|Frequency Zoom") - if curr_value == 10.0: - print("Frequency Zoom is equal to expected value") - else: - print("Frequency Zoom is not equal to expected value") + # 4) Set the frequency value of the component + hydra.get_set_test(entity, 1, "Configuration|Frequency Zoom", 10) + + # 5) Verify if the frequency value is set to higher value + curr_value = hydra.get_component_property_value(entity.components[1], "Configuration|Frequency Zoom") + Report.result(Tests.higher_zoom_value_set, curr_value == 10.0) -test = TestGradientTransformFrequencyZoom() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py index c9cfc225d1..09cce359d5 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py @@ -4,73 +4,71 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -class TestGradientTransformRequiresShape(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientTransformRequiresShape", args=["level"]) - - def run_test(self): - """ - Summary: - This test verifies that the Gradient Transform Modifier component is dependent on a shape component. - - Expected Result: - Gradient Transform Modifier component is disabled until a shape component is added to the entity. - - Test Steps: - 1) Open level - 2) Create a new entity with a Gradient Transform Modifier component - 3) Verify the component is disabled until a shape component is also added to the entity - - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. - - :return: None - """ - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) - - # Create a new Entity in the level - entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - - # Add a Gradient Transform Component (that will be disabled since there is no shape on the Entity) - gradient_transform_component = hydra.add_component('Gradient Transform Modifier', entity_id) - - # Verify the Gradient Transform Component is not active before adding the Shape - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_transform_component) - self.test_success = self.test_success and not active - if not active: - self.log("Gradient Transform component is not active without a Shape component on the Entity") - - # Add a Shape component to the same Entity - hydra.add_component('Box Shape', entity_id) - - # Check if the Gradient Transform Component is active now after adding the Shape - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_transform_component) - self.test_success = self.test_success and active - if active: - self.log("Gradient Transform Modifier component is active now that the Entity has a Shape") +class Tests: + disabled_without_shape = ( + "Gradient Transform Modifier component is disabled without a Shape component on the Entity", + "Gradient Transform Modifier component is unexpectedly enabled without a Shape component on the Entity", + ) + enabled_with_shape = ( + "Gradient Transform Modifier component is enabled now that the Entity has a Shape", + "Gradient Transform Modifier component is still disabled alongside a Shape component", + ) -test = TestGradientTransformRequiresShape() -test.run() +def GradientTransform_RequiresShape(): + """ + Summary: + This test verifies that the Gradient Transform Modifier component is dependent on a shape component. + + Expected Result: + Gradient Transform Modifier component is disabled until a shape component is added to the entity. + + Test Steps: + 1) Open level + 2) Create a new entity with a Gradient Transform Modifier component + 3) Verify the component is disabled until a shape component is also added to the entity + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Create a new Entity in the level + entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + + # Add a Gradient Transform Component (that will be disabled since there is no shape on the Entity) + gradient_transform_component = hydra.add_component('Gradient Transform Modifier', entity_id) + + # Verify the Gradient Transform Component is not active before adding the Shape + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_transform_component) + Report.result(Tests.disabled_without_shape, not active) + + # Add a Shape component to the same Entity + hydra.add_component('Box Shape', entity_id) + + # Check if the Gradient Transform Component is active now after adding the Shape + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_transform_component) + Report.result(Tests.enabled_with_shape, active) + + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientTransform_RequiresShape) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py index 1063260550..42458665e1 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py @@ -5,89 +5,91 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.asset as asset -import azlmbr.bus as bus -import azlmbr.entity as EntityId -import azlmbr.editor as editor -import azlmbr.math as math -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper +class Tests: + image_gradient_entity_created = ( + "Image Gradient entity created", + "Failed to create Image Gradient entity", + ) + image_gradient_asset_found = ( + "image_grad_test_gsi.png was found in the workspace", + "image_grad_test_gsi.png was not found in the workspace" + ) + image_gradient_assigned = ( + "Successfully assigned image gradient asset", + "Failed to assign image gradient asset" + ) -class TestImageGradient(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="ImageGradient_ProcessedImageAssignedSucessfully", - args=["level"]) +def ImageGradient_ProcessedImageAssignedSuccessfully(): + """ + Summary: + Level created with Entity having Image Gradient and Gradient Transform Modifier components. + Save any new image to your workspace with the suffix "_gsi" and assign as image asset. - def run_test(self): - """ - Summary: - Level created with Entity having Image Gradient and Gradient Transform Modifier components. - Save any new image to your workspace with the suffix "_gsi" and assign as image asset. - - Expected Behavior: - Image can be assigned as the Image Asset for the Image as Gradient component. + Expected Behavior: + Image can be assigned as the Image Asset for the Image as Gradient component. - Test Steps: - 1) Create level - 2) Create an entity with Image Gradient and Gradient Transform Modifier components. - 3) Assign the newly processed gradient image as Image asset. + Test Steps: + 1) Open a level + 2) Create an entity with Image Gradient and Gradient Transform Modifier components. + 3) Assign the newly processed gradient image as Image asset. - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. - :return: None - """ + :return: None + """ - # 1) Create level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + import os - # 2) Create an entity with Image Gradient and Gradient Transform Modifier components - components_to_add = ["Image Gradient", "Gradient Transform Modifier", "Box Shape"] - entity_position = math.Vector3(512.0, 512.0, 32.0) - new_entity_id = editor.ToolsApplicationRequestBus( - bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() - ) - if new_entity_id.IsValid(): - print("Image Gradient Entity created") - image_gradient_entity = hydra.Entity("Image Gradient Entity", new_entity_id) - image_gradient_entity.components = [] - for component in components_to_add: - image_gradient_entity.add_component(component) + import azlmbr.asset as asset + import azlmbr.bus as bus + import azlmbr.entity as EntityId + import azlmbr.editor as editor + import azlmbr.math as math - # 3) Assign the processed gradient signal image as the Image Gradient's image asset and verify success + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # First, check for the base image in the workspace - base_image = "image_grad_test_gsi.png" - base_image_path = os.path.join("AutomatedTesting", "Assets", "ImageGradients", base_image) - if os.path.isfile(base_image_path): - print(f"{base_image} was found in the workspace") + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Next, assign the processed image to the Image Gradient's Image Asset property - processed_image_path = os.path.join("Assets", "ImageGradients", "image_grad_test_gsi.gradimage") - asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", processed_image_path, math.Uuid(), - False) - hydra.get_set_test(image_gradient_entity, 0, "Configuration|Image Asset", asset_id) + # 2) Create an entity with Image Gradient and Gradient Transform Modifier components + components_to_add = ["Image Gradient", "Gradient Transform Modifier", "Box Shape"] + entity_position = math.Vector3(512.0, 512.0, 32.0) + new_entity_id = editor.ToolsApplicationRequestBus( + bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + ) + Report.critical_result(Tests.image_gradient_entity_created, new_entity_id.IsValid()) + image_gradient_entity = hydra.Entity("Image Gradient Entity", new_entity_id) + image_gradient_entity.components = [] + for component in components_to_add: + image_gradient_entity.add_component(component) - # Finally, verify if the gradient image is assigned as the Image Asset - success = hydra.get_component_property_value(image_gradient_entity.components[0], "Configuration|Image Asset") == asset_id - self.test_success = self.test_success and success + # 3) Assign the processed gradient signal image as the Image Gradient's image asset and verify success + + # First, check for the base image in the workspace + base_image = "image_grad_test_gsi.png" + base_image_path = os.path.join("AutomatedTesting", "Assets", "ImageGradients", base_image) + Report.critical_result(Tests.image_gradient_asset_found, os.path.isfile(base_image_path)) + + # Next, assign the processed image to the Image Gradient's Image Asset property + processed_image_path = os.path.join("Assets", "ImageGradients", "image_grad_test_gsi.gradimage") + asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", processed_image_path, math.Uuid(), + False) + hydra.get_set_test(image_gradient_entity, 0, "Configuration|Image Asset", asset_id) + + # Finally, verify if the gradient image is assigned as the Image Asset + success = hydra.get_component_property_value(image_gradient_entity.components[0], "Configuration|Image Asset") == asset_id + Report.result(Tests.image_gradient_assigned, success) -test = TestImageGradient() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(ImageGradient_ProcessedImageAssignedSuccessfully) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py index 2c6ac8d15b..3b832d160a 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py @@ -4,74 +4,72 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -class TestImageGradientRequiresShape(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="ImageGradientRequiresShape", args=["level"]) - - def run_test(self): - """ - Summary: - This test verifies that the Image Gradient component is dependent on a shape component. - - Expected Result: - Gradient Transform Modifier component is disabled until a shape component is added to the entity. - - Test Steps: - 1) Open level - 2) Create a new entity with a Image Gradient component - 3) Verify the component is disabled until a shape component is also added to the entity - - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. - - :return: None - """ - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) - - # Create a new Entity in the level - entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - - # Add an Image Gradient and Gradient Transform Component (should be disabled until a Shape exists on the Entity) - image_gradient_component = hydra.add_component('Image Gradient', entity_id) - hydra.add_component('Gradient Transform Modifier', entity_id) - - # Verify the Image Gradient Component is not active before adding the Shape - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', image_gradient_component) - self.test_success = self.test_success and not active - if not active: - self.log("Image Gradient component is not active without a Shape component on the Entity") - - # Add a Shape component to the same Entity - hydra.add_component('Box Shape', entity_id) - - # Check if the Image Gradient Component is active now after adding the Shape - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', image_gradient_component) - self.test_success = self.test_success and active - if active: - self.log("Image Gradient component is active now that the Entity has a Shape") +class Tests: + disabled_without_shape = ( + "Image Gradient component is disabled without a Shape component on the Entity", + "Image Gradient component is unexpectedly enabled without a Shape component on the Entity", + ) + enabled_with_shape = ( + "Image Gradient component is enabled now that the Entity has a Shape", + "Image Gradient component is still disabled alongside a Shape component", + ) -test = TestImageGradientRequiresShape() -test.run() +def ImageGradient_RequiresShape(): + """ + Summary: + This test verifies that the Image Gradient component is dependent on a shape component. + + Expected Result: + Gradient Transform Modifier component is disabled until a shape component is added to the entity. + + Test Steps: + 1) Open level + 2) Create a new entity with a Image Gradient component + 3) Verify the component is disabled until a shape component is also added to the entity + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Create a new Entity in the level + entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + + # Add an Image Gradient and Gradient Transform Component (should be disabled until a Shape exists on the Entity) + image_gradient_component = hydra.add_component('Image Gradient', entity_id) + hydra.add_component('Gradient Transform Modifier', entity_id) + + # Verify the Image Gradient Component is not active before adding the Shape + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', image_gradient_component) + Report.result(Tests.disabled_without_shape, not active) + + # Add a Shape component to the same Entity + hydra.add_component('Box Shape', entity_id) + + # Check if the Image Gradient Component is active now after adding the Shape + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', image_gradient_component) + Report.result(Tests.enabled_with_shape, active) + + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(ImageGradient_RequiresShape) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic.py new file mode 100644 index 0000000000..21eecf642c --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic.py @@ -0,0 +1,71 @@ +""" +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. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +import os +import pytest +import sys + +sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../automatedtesting_shared') +from base import TestAutomationBase + + +@pytest.mark.SUITE_periodic +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(TestAutomationBase): + + def test_GradientGenerators_Incompatibilities(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientGenerators_Incompatibilities as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientModifiers_Incompatibilities(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientModifiers_Incompatibilities as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientPreviewSettings_DefaultPinnedEntityIsSelf(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientPreviewSettings_DefaultPinnedEntityIsSelf as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientSampling_GradientReferencesAddRemoveSuccessfully(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientSampling_GradientReferencesAddRemoveSuccessfully as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientSurfaceTagEmitter_ComponentDependencies(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientSurfaceTagEmitter_ComponentDependencies as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientTransform_RequiresShape(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientTransform_RequiresShape as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientTransform_ComponentIncompatibleWithSpawners(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientTransform_ComponentIncompatibleWithSpawners as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientTransform_ComponentIncompatibleWithExpectedGradients(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientTransform_ComponentIncompatibleWithExpectedGradients as test_module + self._run_test(request, workspace, editor, test_module) + + def test_ImageGradient_RequiresShape(self, request, workspace, editor, launcher_platform): + from .EditorScripts import ImageGradient_RequiresShape as test_module + self._run_test(request, workspace, editor, test_module) + + def test_ImageGradient_ProcessedImageAssignedSuccessfully(self, request, workspace, editor, launcher_platform): + from .EditorScripts import ImageGradient_ProcessedImageAssignedSuccessfully as test_module + self._run_test(request, workspace, editor, test_module) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic_Optimized.py new file mode 100644 index 0000000000..514504d324 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic_Optimized.py @@ -0,0 +1,55 @@ +""" +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. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +import pytest + +from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite + + +@pytest.mark.SUITE_periodic +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(EditorTestSuite): + + class test_GradientGenerators_Incompatibilities(EditorSharedTest): + from .EditorScripts import GradientGenerators_Incompatibilities as test_module + + class test_GradientModifiers_Incompatibilities(EditorSharedTest): + from .EditorScripts import GradientModifiers_Incompatibilities as test_module + + class test_GradientPreviewSettings_DefaultPinnedEntityIsSelf(EditorSharedTest): + from .EditorScripts import GradientPreviewSettings_DefaultPinnedEntityIsSelf as test_module + + class test_GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin(EditorSharedTest): + from .EditorScripts import GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin as test_module + + class test_GradientSampling_GradientReferencesAddRemoveSuccessfully(EditorSharedTest): + from .EditorScripts import GradientSampling_GradientReferencesAddRemoveSuccessfully as test_module + + class test_GradientSurfaceTagEmitter_ComponentDependencies(EditorSharedTest): + from .EditorScripts import GradientSurfaceTagEmitter_ComponentDependencies as test_module + + class test_GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(EditorSharedTest): + from .EditorScripts import GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully as test_module + + class test_GradientTransform_RequiresShape(EditorSharedTest): + from .EditorScripts import GradientTransform_RequiresShape as test_module + + class test_GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange(EditorSharedTest): + from .EditorScripts import GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange as test_module + + class test_GradientTransform_ComponentIncompatibleWithSpawners(EditorSharedTest): + from .EditorScripts import GradientTransform_ComponentIncompatibleWithSpawners as test_module + + class test_GradientTransform_ComponentIncompatibleWithExpectedGradients(EditorSharedTest): + from .EditorScripts import GradientTransform_ComponentIncompatibleWithExpectedGradients as test_module + + class test_ImageGradient_RequiresShape(EditorSharedTest): + from .EditorScripts import ImageGradient_RequiresShape as test_module + + class test_ImageGradient_ProcessedImageAssignedSuccessfully(EditorSharedTest): + from .EditorScripts import ImageGradient_ProcessedImageAssignedSuccessfully as test_module From e8bca8bc00793c63989392b319a625b5b5ca31f0 Mon Sep 17 00:00:00 2001 From: jckand-amzn Date: Thu, 19 Aug 2021 17:08:39 -0500 Subject: [PATCH 34/54] Updating test with a workaround for assigning a PhysX Mesh asset to a PhysX Collider component Signed-off-by: jckand-amzn --- ...ysXColliderSurfaceTagEmitter_E2E_Editor.py | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py index beb5c2af72..2052c59a94 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py @@ -10,6 +10,7 @@ import sys sys.path.append(os.path.dirname(os.path.abspath(__file__))) import azlmbr.asset as asset +import azlmbr.editor as editor import azlmbr.legacy.general as general import azlmbr.bus as bus import azlmbr.math as math @@ -107,7 +108,7 @@ class TestPhysXColliderSurfaceTagEmitter(EditorTestHelper): # Create an entity with a PhysX Collider and our PhysX Collider Surface Tag Emitter collider_entity = hydra.Entity("Collider Surface") collider_entity.create_entity( - entity_center_point, + entity_center_point, ["PhysX Collider", "PhysX Collider Surface Tag Emitter"] ) if collider_entity.id.IsValid(): @@ -153,23 +154,29 @@ class TestPhysXColliderSurfaceTagEmitter(EditorTestHelper): self.test_success = self.test_success and baseline_success # Setup collider entity with a PhysX Mesh - test_physx_mesh_asset_path = asset.AssetCatalogRequestBus( + test_physx_mesh_asset_id = asset.AssetCatalogRequestBus( bus.Broadcast, "GetAssetIdByPath", os.path.join("levels", "physics", "c4044697_material_perfacematerialvalidation", "test.pxmesh"), math.Uuid(), False) - hydra.get_set_test(collider_entity, 0, "Shape Configuration|Shape", 7) - hydra.get_set_test(collider_entity, 0, "Shape Configuration|Asset|PhysX Mesh", test_physx_mesh_asset_path) + + # Remove/re-add component due to LYN-5496 + collider_entity.remove_component("PhysX Collider") + collider_entity.add_component("PhysX Collider") + self.wait_for_condition(lambda: editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', + collider_entity.components[1]), 5.0) + hydra.get_set_test(collider_entity, 1, "Shape Configuration|Shape", 7) + hydra.get_set_test(collider_entity, 1, "Shape Configuration|Asset|PhysX Mesh", test_physx_mesh_asset_id) # Set the asset scale to match the test heights of the shapes tested asset_scale = math.Vector3(1.0, 1.0, 9.0) - collider_entity.get_set_test(0, "Shape Configuration|Asset|Configuration|Asset Scale", asset_scale) + collider_entity.get_set_test(1, "Shape Configuration|Asset|Configuration|Asset Scale", asset_scale) # Test: Generate a new surface on the collider. # There should be one instance at the very top of the collider mesh, and none on the baseline surface # (We use a small query box to only check for one placed instance point) self.log("Starting PhysX Mesh Collider Test") - hydra.get_set_test(collider_entity, 1, "Configuration|Generated Tags", [surface_tag]) - hydra.get_set_test(collider_entity, 1, "Configuration|Extended Tags", [invalid_tag]) + hydra.get_set_test(collider_entity, 0, "Configuration|Generated Tags", [surface_tag]) + hydra.get_set_test(collider_entity, 0, "Configuration|Extended Tags", [invalid_tag]) top_point_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 1), 5.0) self.test_success = self.test_success and top_point_success baseline_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point, @@ -180,8 +187,8 @@ class TestPhysXColliderSurfaceTagEmitter(EditorTestHelper): # There should be no instances at the very top of the collider mesh, and none on the baseline surface within # our query box as PhysX meshes are treated as hollow shells, not solid volumes. # (We use a small query box to only check for one placed instance point) - hydra.get_set_test(collider_entity, 1, "Configuration|Generated Tags", [invalid_tag]) - hydra.get_set_test(collider_entity, 1, "Configuration|Extended Tags", [surface_tag]) + hydra.get_set_test(collider_entity, 0, "Configuration|Generated Tags", [invalid_tag]) + hydra.get_set_test(collider_entity, 0, "Configuration|Extended Tags", [surface_tag]) top_point_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 0), 5.0) self.test_success = self.test_success and top_point_success baseline_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point, From f41438770c656110202304d0a8edce63ae686892 Mon Sep 17 00:00:00 2001 From: Judy Ng Date: Thu, 19 Aug 2021 15:09:01 -0700 Subject: [PATCH 35/54] add shaderoptiongroup natvis (#3315) Signed-off-by: Judy Ng --- .../Natvis/shaderoptiongroup.natvis | 23 +++++++++++++++++++ .../Windows/platform_windows_files.cmake | 1 + 2 files changed, 24 insertions(+) create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Common/VisualStudio/Natvis/shaderoptiongroup.natvis diff --git a/Gems/Atom/RPI/Code/Source/Platform/Common/VisualStudio/Natvis/shaderoptiongroup.natvis b/Gems/Atom/RPI/Code/Source/Platform/Common/VisualStudio/Natvis/shaderoptiongroup.natvis new file mode 100644 index 0000000000..64ad28af72 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Common/VisualStudio/Natvis/shaderoptiongroup.natvis @@ -0,0 +1,23 @@ + + + + + + shader option group + + m_id.m_key + + + + iOption++ + + + + + ((m_id.m_key.m_bits[(int) (m_layout.px->m_options[iOption].m_bitOffset / m_id.m_key.BitsPerWord)] >> (m_layout.px->m_options[iOption].m_bitOffset - ((int) (m_layout.px->m_options[iOption].m_bitOffset / 32) * 32))) & ((1u << (m_layout.px->m_options[iOption].m_bitCount)) - 1u)) + (m_layout.px->m_options[iOption].m_minValue.m_index) + + + + + + diff --git a/Gems/Atom/RPI/Code/Source/Platform/Windows/platform_windows_files.cmake b/Gems/Atom/RPI/Code/Source/Platform/Windows/platform_windows_files.cmake index 057fecfc90..c805aa9577 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/Windows/platform_windows_files.cmake +++ b/Gems/Atom/RPI/Code/Source/Platform/Windows/platform_windows_files.cmake @@ -9,4 +9,5 @@ set(FILES Atom_RPI_Traits_Platform.h Atom_RPI_Traits_Windows.h + ../Common/VisualStudio/Natvis/shaderoptiongroup.natvis ) From 62a00412453023775d869bf869a48742aa4ad16f Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 19 Aug 2021 16:16:28 -0700 Subject: [PATCH 36/54] enable warning 4296: 'operator': expression is always false Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Editor/EditorViewportWidget.cpp | 1 - Code/Editor/Objects/BaseObject.cpp | 4 +- Code/Editor/Objects/EntityObject.cpp | 2 +- Code/Editor/Undo/Undo.cpp | 2 +- Code/Editor/Util/3DConnexionDriver.cpp | 39 ++++++++---------- Code/Editor/Util/KDTree.cpp | 2 +- Code/Editor/ViewPane.cpp | 2 + .../IO/Streamer/StreamerContext_WinAPI.cpp | 2 +- .../AzCore/Tests/AZStd/VectorAndArray.cpp | 41 ++++++++++++------- .../AzFramework/IO/RemoteFileIO.cpp | 10 ----- Code/Legacy/CryCommon/IXml.h | 2 +- .../resourcecompiler/rcjoblistmodel.cpp | 8 ++-- .../native/utilities/ByteArrayStream.cpp | 1 - .../native/utilities/assetUtils.cpp | 5 --- .../Standalone/Source/Driller/AreaChart.cpp | 7 +--- .../AWSGameLiftCreateSessionActivity.cpp | 2 +- ...WSGameLiftCreateSessionOnQueueActivity.cpp | 2 +- .../SphericalHarmonicsUtility.inl | 7 +--- .../Shader/ShaderVariantTreeAsset.cpp | 1 - .../Include/Atom/Utils/ImGuiGpuProfiler.inl | 4 +- .../Source/AnimGraphConnectionCommands.cpp | 4 +- .../Code/MCore/Source/StringConversions.cpp | 2 +- .../GraphModel/Code/Tests/TestEnvironment.cpp | 2 +- .../Code/Source/Editor/Core/GraphContext.cpp | 2 +- .../Code/Source/Cinematics/AnimPostFXNode.cpp | 2 +- .../Source/Cinematics/AnimScreenFaderNode.cpp | 2 +- .../Code/Source/Cinematics/CommentNode.cpp | 2 +- .../Code/Source/Cinematics/LayerNode.cpp | 2 +- .../Code/Source/Cinematics/MaterialNode.cpp | 2 +- .../Code/Source/Cinematics/SceneNode.cpp | 2 +- .../Source/Cinematics/ShadowsSetupNode.cpp | 2 +- .../ScriptCanvas/Core/NodeFunctionGeneric.h | 2 + .../Core/NodeableNodeOverloaded.cpp | 14 +++---- .../ScriptCanvas/Core/SubgraphInterface.cpp | 2 +- .../Libraries/String/StringGenerics.h | 2 +- .../Translation/TranslationUtilities.cpp | 2 +- .../ScriptEventBroadcast.cpp | 2 +- .../ScriptEventMethod.cpp | 2 +- .../Common/MSVC/Configurations_msvc.cmake | 4 +- 39 files changed, 93 insertions(+), 105 deletions(-) diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp index c305b1be6c..ec965cc51f 100644 --- a/Code/Editor/EditorViewportWidget.cpp +++ b/Code/Editor/EditorViewportWidget.cpp @@ -2634,7 +2634,6 @@ void EditorViewportWidget::ShowCursor() ////////////////////////////////////////////////////////////////////////// void EditorViewportWidget::PushDisableRendering() { - assert(m_disableRenderingCount >= 0); ++m_disableRenderingCount; } diff --git a/Code/Editor/Objects/BaseObject.cpp b/Code/Editor/Objects/BaseObject.cpp index 8eb3bb83c1..59a58e1ac1 100644 --- a/Code/Editor/Objects/BaseObject.cpp +++ b/Code/Editor/Objects/BaseObject.cpp @@ -2038,7 +2038,7 @@ bool CBaseObject::HitHelperAtTest(HitContext& hc, const Vec3& pos) ////////////////////////////////////////////////////////////////////////// CBaseObject* CBaseObject::GetChild(size_t const i) const { - assert(i >= 0 && i < m_childs.size()); + assert(i < m_childs.size()); return m_childs[i]; } @@ -2729,7 +2729,7 @@ void CBaseObject::SetMinSpec(uint32 nSpec, bool bSetChildren) // Set min spec for all childs. if (bSetChildren) { - for (size_t i = m_childs.size() - 1; i >= 0; --i) + for (int i = static_cast(m_childs.size()) - 1; i >= 0; --i) { m_childs[i]->SetMinSpec(nSpec, true); } diff --git a/Code/Editor/Objects/EntityObject.cpp b/Code/Editor/Objects/EntityObject.cpp index d2a2ae7d18..45aaa7919e 100644 --- a/Code/Editor/Objects/EntityObject.cpp +++ b/Code/Editor/Objects/EntityObject.cpp @@ -1413,7 +1413,7 @@ void CEntityObject::PostClone(CBaseObject* pFromObject, CObjectCloneContext& ctx void CEntityObject::ResolveEventTarget(CBaseObject* object, unsigned int index) { // Find target id. - assert(index >= 0 && index < m_eventTargets.size()); + assert(index < m_eventTargets.size()); if (object) { object->AddEventListener(this); diff --git a/Code/Editor/Undo/Undo.cpp b/Code/Editor/Undo/Undo.cpp index b49c6ea567..910a670bee 100644 --- a/Code/Editor/Undo/Undo.cpp +++ b/Code/Editor/Undo/Undo.cpp @@ -49,7 +49,7 @@ public: } void Undo(bool bUndo) override { - for (size_t i = m_undoSteps.size() - 1; i >= 0; i--) + for (int i = static_cast(m_undoSteps.size()) - 1; i >= 0; i--) { m_undoSteps[i]->Undo(bUndo); } diff --git a/Code/Editor/Util/3DConnexionDriver.cpp b/Code/Editor/Util/3DConnexionDriver.cpp index c1c3b47c4b..73e7954c88 100644 --- a/Code/Editor/Util/3DConnexionDriver.cpp +++ b/Code/Editor/Util/3DConnexionDriver.cpp @@ -60,34 +60,29 @@ bool C3DConnexionDriver::InitDevice() { UINT nchars = 300; TCHAR deviceName[300]; - if (GetRawInputDeviceInfo(m_pRawInputDeviceList[i].hDevice, - RIDI_DEVICENAME, deviceName, &nchars) >= 0) - { - //_RPT3(_CRT_WARN, "Device[%d]: handle=0x%x name = %S\n", i, g_pRawInputDeviceList[i].hDevice, deviceName); - } + GetRawInputDeviceInfo(m_pRawInputDeviceList[i].hDevice, + RIDI_DEVICENAME, deviceName, &nchars); RID_DEVICE_INFO dinfo; UINT sizeofdinfo = sizeof(dinfo); dinfo.cbSize = sizeofdinfo; - if (GetRawInputDeviceInfo(m_pRawInputDeviceList[i].hDevice, - RIDI_DEVICEINFO, &dinfo, &sizeofdinfo) >= 0) + GetRawInputDeviceInfo(m_pRawInputDeviceList[i].hDevice, + RIDI_DEVICEINFO, &dinfo, &sizeofdinfo); + if (dinfo.dwType == RIM_TYPEHID) { - if (dinfo.dwType == RIM_TYPEHID) + RID_DEVICE_INFO_HID* phidInfo = &dinfo.hid; + // Add this one to the list of interesting devices? + // Actually only have to do this once to get input from all usage 1, usagePage 8 devices + // This just keeps out the other usages. + // You might want to put up a list for users to select amongst the different devices. + // In particular, to assign separate functionality to the different devices. + if (phidInfo->usUsagePage == 1 && phidInfo->usUsage == 8) { - RID_DEVICE_INFO_HID* phidInfo = &dinfo.hid; - // Add this one to the list of interesting devices? - // Actually only have to do this once to get input from all usage 1, usagePage 8 devices - // This just keeps out the other usages. - // You might want to put up a list for users to select amongst the different devices. - // In particular, to assign separate functionality to the different devices. - if (phidInfo->usUsagePage == 1 && phidInfo->usUsage == 8) - { - m_pRawInputDevices[m_nUsagePage1Usage8Devices].usUsagePage = phidInfo->usUsagePage; - m_pRawInputDevices[m_nUsagePage1Usage8Devices].usUsage = phidInfo->usUsage; - m_pRawInputDevices[m_nUsagePage1Usage8Devices].dwFlags = 0; - m_pRawInputDevices[m_nUsagePage1Usage8Devices].hwndTarget = nullptr; - m_nUsagePage1Usage8Devices++; - } + m_pRawInputDevices[m_nUsagePage1Usage8Devices].usUsagePage = phidInfo->usUsagePage; + m_pRawInputDevices[m_nUsagePage1Usage8Devices].usUsage = phidInfo->usUsage; + m_pRawInputDevices[m_nUsagePage1Usage8Devices].dwFlags = 0; + m_pRawInputDevices[m_nUsagePage1Usage8Devices].hwndTarget = nullptr; + m_nUsagePage1Usage8Devices++; } } } diff --git a/Code/Editor/Util/KDTree.cpp b/Code/Editor/Util/KDTree.cpp index 182b9b8eb1..af06a58c9f 100644 --- a/Code/Editor/Util/KDTree.cpp +++ b/Code/Editor/Util/KDTree.cpp @@ -467,7 +467,7 @@ bool CKDTree::FindNearestVertexRecursively(KDTreeNode* pNode, const Vec3& raySrc uint32 nVertexIndex = pNode->GetVertexIndex(i); uint32 nObjIndex = pNode->GetObjIndex(i); - assert(nObjIndex < m_StatObjectList.size() && nObjIndex >= 0); + assert(nObjIndex < m_StatObjectList.size()); const SStatObj* pStatObjInfo = &(m_StatObjectList[nObjIndex]); diff --git a/Code/Editor/ViewPane.cpp b/Code/Editor/ViewPane.cpp index a932f05c79..421db8394e 100644 --- a/Code/Editor/ViewPane.cpp +++ b/Code/Editor/ViewPane.cpp @@ -769,7 +769,9 @@ namespace void PySetViewPaneLayout(unsigned int layoutId) { + AZ_PUSH_DISABLE_WARNING(4296, "-Wunknown-warning-option") if ((layoutId >= ET_Layout0) && (layoutId <= ET_Layout8)) + AZ_POP_DISABLE_WARNING { CLayoutWnd* layout = GetIEditor()->GetViewManager()->GetLayout(); if (layout) diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/Streamer/StreamerContext_WinAPI.cpp b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/Streamer/StreamerContext_WinAPI.cpp index cda0a3f056..8f46bc5eba 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/Streamer/StreamerContext_WinAPI.cpp +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/Streamer/StreamerContext_WinAPI.cpp @@ -49,7 +49,7 @@ namespace AZ::Platform AZ_Assert(m_events[0], "There is no synchronization event created for the main streamer thread to use to suspend."); DWORD result = ::WaitForMultipleObjects(m_handleCount, m_events, false, INFINITE); - if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + m_handleCount) + if (result < WAIT_OBJECT_0 + m_handleCount) { DWORD index = result - WAIT_OBJECT_0; ::ResetEvent(m_events[index]); diff --git a/Code/Framework/AzCore/Tests/AZStd/VectorAndArray.cpp b/Code/Framework/AzCore/Tests/AZStd/VectorAndArray.cpp index dd10d20ef8..933db73c3f 100644 --- a/Code/Framework/AzCore/Tests/AZStd/VectorAndArray.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/VectorAndArray.cpp @@ -36,12 +36,23 @@ using namespace UnitTestInternal; /** * Validate a vector for certain number of elements. */ -#define AZ_TEST_VALIDATE_VECTOR(_Vector, _NumElements) \ - EXPECT_TRUE(_Vector.validate()); \ - EXPECT_EQ(_NumElements, _Vector.size()); \ - EXPECT_TRUE((_NumElements > 0) ? !_Vector.empty() : _Vector.empty()); \ - EXPECT_TRUE((_NumElements > 0) ? _Vector.capacity() >= _NumElements : true); \ - EXPECT_TRUE((_NumElements > 0) ? _Vector.begin() != _Vector.end() : _Vector.begin() == _Vector.end()); \ +#define AZ_TEST_VALIDATE_VECTOR(_Vector, _NumElements) \ + EXPECT_NE(_NumElements, 0); \ + EXPECT_TRUE(_Vector.validate()); \ + EXPECT_EQ(_NumElements, _Vector.size()); \ + EXPECT_TRUE(!_Vector.empty()); \ + EXPECT_TRUE(_Vector.capacity() >= _NumElements); \ + EXPECT_TRUE(_Vector.begin() != _Vector.end()); \ + EXPECT_NE(nullptr, _Vector.data()) + + /** + * Validate a vector for 0 number of elements. The above macro creates expressions that are always true for size == 0 + */ +#define AZ_TEST_VALIDATE_VECTOR_0(_Vector) \ + EXPECT_TRUE(_Vector.validate()); \ + EXPECT_EQ(0, _Vector.size()); \ + EXPECT_TRUE(_Vector.empty()); \ + EXPECT_TRUE(_Vector.begin() == _Vector.end()); \ EXPECT_NE(nullptr, _Vector.data()) namespace UnitTest @@ -312,7 +323,7 @@ namespace UnitTest // erase int_vector1.erase(int_vector1.begin(), int_vector1.end()); - AZ_TEST_VALIDATE_VECTOR(int_vector1, 0); // Zero elements but valid capacity. + AZ_TEST_VALIDATE_VECTOR_0(int_vector1); // Zero elements but valid capacity. int_vector1.push_back(10); int_vector1.push_back(20); @@ -324,11 +335,11 @@ namespace UnitTest // clear int_vector1.clear(); - AZ_TEST_VALIDATE_VECTOR(int_vector1, 0); // Zero elements but valid capacity. + AZ_TEST_VALIDATE_VECTOR_0(int_vector1); // Zero elements but valid capacity. // swap int_vector1.swap(int_vector); - AZ_TEST_VALIDATE_VECTOR(int_vector, 0); + AZ_TEST_VALIDATE_VECTOR_0(int_vector); AZ_TEST_VALIDATE_VECTOR(int_vector1, 33); AZ_TEST_ASSERT(int_vector1.front() == 55); @@ -524,11 +535,11 @@ namespace UnitTest // Default vector (integral type). fixed_vector int_vector_default; - AZ_TEST_VALIDATE_VECTOR(int_vector_default, 0); + AZ_TEST_VALIDATE_VECTOR_0(int_vector_default); // Default vector (non-integral type). fixed_vector myclass_vector_default; - AZ_TEST_VALIDATE_VECTOR(myclass_vector_default, 0); + AZ_TEST_VALIDATE_VECTOR_0(myclass_vector_default); // Create a vector (using fill ctor, with memset optimization to set the values) typedef fixed_vector char_10_type; @@ -633,7 +644,7 @@ namespace UnitTest // erase int_vector1.erase(int_vector1.begin(), int_vector1.end()); - AZ_TEST_VALIDATE_VECTOR(int_vector1, 0); + AZ_TEST_VALIDATE_VECTOR_0(int_vector1); int_vector1.push_back(10); int_vector1.push_back(20); @@ -645,11 +656,11 @@ namespace UnitTest // clear int_vector1.clear(); - AZ_TEST_VALIDATE_VECTOR(int_vector1, 0); + AZ_TEST_VALIDATE_VECTOR_0(int_vector1); // swap int_vector1.swap(int_vector); - AZ_TEST_VALIDATE_VECTOR(int_vector, 0); + AZ_TEST_VALIDATE_VECTOR_0(int_vector); AZ_TEST_VALIDATE_VECTOR(int_vector1, 33); AZ_TEST_ASSERT(int_vector1.front() == 55); @@ -963,7 +974,7 @@ namespace UnitTest AZ_TEST_VALIDATE_VECTOR(deep_vec_2, 12); deep_vec_2.clear(); - AZ_TEST_VALIDATE_VECTOR(deep_vec_2, 0); + AZ_TEST_VALIDATE_VECTOR_0(deep_vec_2); } #endif // AZ_UNIT_TEST_SKIP_STD_VECTOR_AND_ARRAY_TESTS diff --git a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp index 75b43100c5..25bc31b760 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp +++ b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp @@ -1081,16 +1081,6 @@ namespace AZ return ResultCode::Error; } - //bound check - //note that seeking beyond end or before beginning is system dependent - //therefore we will define that on all platforms it is not allowed - if (newFilePosition < 0) - { - AZ_TracePrintf(RemoteFileIOChannel, "RemoteFileIO::Seek(fileHandle=%u, offset=%i, type=%s) seek to a position before the begining of a file!", fileHandle, offset, type == SeekType::SeekFromCurrent ? "SeekFromCurrent" : type == SeekType::SeekFromEnd ? "SeekFromEnd" : type == SeekType::SeekFromStart ? "SeekFromStart" : "Unknown"); - REMOTEFILE_LOG_APPEND(AZStd::string::format("RemoteFileIO::Seek(fileHandle=%u, offset=%i, type=%s) seek to a position before the begining of a file!", fileHandle, offset, type == SeekType::SeekFromCurrent ? "SeekFromCurrent" : type == SeekType::SeekFromEnd ? "SeekFromEnd" : type == SeekType::SeekFromStart ? "SeekFromStart" : "Unknown").c_str()); - newFilePosition = 0; - } - else { AZ::u64 fileSize = 0; Size(fileHandle, fileSize); diff --git a/Code/Legacy/CryCommon/IXml.h b/Code/Legacy/CryCommon/IXml.h index 80c2415f9c..2434b44664 100644 --- a/Code/Legacy/CryCommon/IXml.h +++ b/Code/Legacy/CryCommon/IXml.h @@ -745,7 +745,7 @@ private: void Update() { - if (m_index >= 0 && m_index < m_parentNode->getChildCount()) + if (m_index < m_parentNode->getChildCount()) { m_currentChildNode = m_parentNode->getChild(static_cast(m_index)); } diff --git a/Code/Tools/AssetProcessor/native/resourcecompiler/rcjoblistmodel.cpp b/Code/Tools/AssetProcessor/native/resourcecompiler/rcjoblistmodel.cpp index d22823b496..a64e3bf5b9 100644 --- a/Code/Tools/AssetProcessor/native/resourcecompiler/rcjoblistmodel.cpp +++ b/Code/Tools/AssetProcessor/native/resourcecompiler/rcjoblistmodel.cpp @@ -197,11 +197,11 @@ namespace AssetProcessor m_jobsInFlight.insert(rcJob); - for(size_t jobIndex = m_jobs.size() - 1; jobIndex >= 0; --jobIndex) + for(int jobIndex = static_cast(m_jobs.size()) - 1; jobIndex >= 0; --jobIndex) { if(m_jobs[jobIndex] == rcJob) { - Q_EMIT dataChanged(index(aznumeric_caster(jobIndex), 0, QModelIndex()), index(aznumeric_caster(jobIndex), 0, QModelIndex())); + Q_EMIT dataChanged(index(jobIndex, 0, QModelIndex()), index(jobIndex, 0, QModelIndex())); return; } } @@ -240,7 +240,7 @@ namespace AssetProcessor foundInQueue = m_jobsInQueueLookup.erase(foundInQueue); } - for (size_t jobIndex = m_jobs.size() - 1; jobIndex >= 0; --jobIndex) + for (int jobIndex = static_cast(m_jobs.size()) - 1; jobIndex >= 0; --jobIndex) { if(m_jobs[jobIndex] == rcJob) { @@ -251,7 +251,7 @@ namespace AssetProcessor #if defined(DEBUG_RCJOB_MODEL) AZ_TracePrintf(AssetProcessor::DebugChannel, "JobTrace =>JobCompleted(%i %s,%s,%s)\n", rcJob, rcJob->GetJobEntry().m_databaseSourceName.toUtf8().constData(), rcJob->GetPlatformInfo().m_identifier.c_str(), rcJob->GetJobKey().toUtf8().constData()); #endif - beginRemoveRows(QModelIndex(), aznumeric_caster(jobIndex), aznumeric_caster(jobIndex)); + beginRemoveRows(QModelIndex(), jobIndex, jobIndex); m_jobs.erase(m_jobs.begin() + jobIndex); endRemoveRows(); diff --git a/Code/Tools/AssetProcessor/native/utilities/ByteArrayStream.cpp b/Code/Tools/AssetProcessor/native/utilities/ByteArrayStream.cpp index 187c872e08..4a7128be88 100644 --- a/Code/Tools/AssetProcessor/native/utilities/ByteArrayStream.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/ByteArrayStream.cpp @@ -52,7 +52,6 @@ namespace AssetProcessor SizeType finalPosition = GenericStream::ComputeSeekPosition(bytes, mode); AZ_Assert(finalPosition < INT_MAX, "Overflow of SizeType to int in ByteArrayStream."); - AZ_Assert(finalPosition >= 0, "underflow in seek in ByteArrayStream"); AZ_Assert(finalPosition <= m_activeArray->size(), "You cant seek beyond end of file"); // safety clamp! diff --git a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp index 5e005c117d..72a036bdaa 100644 --- a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp @@ -72,11 +72,6 @@ namespace AssetUtilsInternal bool FileCopyMoveWithTimeout(QString sourceFile, QString outputFile, bool isCopy, unsigned int waitTimeInSeconds) { - if (waitTimeInSeconds < 0) - { - AZ_Warning("Asset Processor", waitTimeInSeconds >= 0, "Invalid timeout specified by the user"); - waitTimeInSeconds = 0; - } bool failureOccurredOnce = false; // used for logging. bool operationSucceeded = false; QFile outFile(outputFile); diff --git a/Code/Tools/Standalone/Source/Driller/AreaChart.cpp b/Code/Tools/Standalone/Source/Driller/AreaChart.cpp index fef31aaaf3..a0eccc7d45 100644 --- a/Code/Tools/Standalone/Source/Driller/AreaChart.cpp +++ b/Code/Tools/Standalone/Source/Driller/AreaChart.cpp @@ -173,10 +173,7 @@ namespace AreaChart void AreaChart::ConfigureVerticalAxis(QString label, unsigned int minimumHeight) { - if (minimumHeight >= 0) - { - SetMinimumValueRange(minimumHeight); - } + SetMinimumValueRange(minimumHeight); if (m_verticalAxis == nullptr) { @@ -323,7 +320,7 @@ namespace AreaChart // Need to handle the areas right at the edge of the polygons for (int i = -1; i <= 1; ++i) { - if ((counter+i) < 0 || (counter + i) >= m_hitAreas.size()) + if ((counter + i) >= m_hitAreas.size()) { continue; } diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.cpp index 16d0cf4241..0332ea7a76 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.cpp @@ -90,7 +90,7 @@ namespace AWSGameLift { auto gameliftCreateSessionRequest = azrtti_cast(&createSessionRequest); - return gameliftCreateSessionRequest && gameliftCreateSessionRequest->m_maxPlayer >= 0 && + return gameliftCreateSessionRequest && (!gameliftCreateSessionRequest->m_aliasId.empty() || !gameliftCreateSessionRequest->m_fleetId.empty()); } } // namespace CreateSessionActivity diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.cpp index 1ac9c7db1c..52be365ea5 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.cpp @@ -79,7 +79,7 @@ namespace AWSGameLift auto gameliftCreateSessionOnQueueRequest = azrtti_cast(&createSessionRequest); - return gameliftCreateSessionOnQueueRequest && gameliftCreateSessionOnQueueRequest->m_maxPlayer >= 0 && + return gameliftCreateSessionOnQueueRequest && !gameliftCreateSessionOnQueueRequest->m_queueName.empty() && !gameliftCreateSessionOnQueueRequest->m_placementId.empty(); } } // namespace CreateSessionOnQueueActivity diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SphericalHarmonics/SphericalHarmonicsUtility.inl b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SphericalHarmonics/SphericalHarmonicsUtility.inl index fb1e70b2a0..7446d2fa8f 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SphericalHarmonics/SphericalHarmonicsUtility.inl +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SphericalHarmonics/SphericalHarmonicsUtility.inl @@ -499,7 +499,7 @@ namespace AZ // outSH -> output SH coefficient array void EvalSHRotationFast(const float R[9], const uint32_t maxBand, const float* inSH, float* outSH) { - if (maxBand >= 0 && maxBand <= 2) + if (maxBand <= 2) { ZHF3(R, maxBand, inSH, outSH); } @@ -514,10 +514,7 @@ namespace AZ // outSH -> output SH coefficient array void EvalSHRotation(const float R[9], const uint32_t maxBand, const double* inSH, double* outSH) { - if (maxBand >= 0) - { - WignerD(R, maxBand, inSH, outSH); - } + WignerD(R, maxBand, inSH, outSH); } // Fast evaluation for first 3 bands diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantTreeAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantTreeAsset.cpp index bd0cad9f4d..b4a0e2e068 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantTreeAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantTreeAsset.cpp @@ -199,7 +199,6 @@ namespace AZ if ((shaderVariantId.m_mask & option.GetBitMask()).any()) { optionValues.push_back(option.DecodeBits(shaderVariantId.m_key)); - AZ_Assert(optionValues.back() >= 0, "Invalid shader variant key"); } else { diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl index e6bde136f8..eb5a5cea10 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl @@ -834,8 +834,10 @@ namespace AZ { // Check whether it should be sorted by name. const uint32_t sortType = static_cast(m_sortType); + AZ_PUSH_DISABLE_WARNING(4296, "-Wunknown-warning-option") bool sortByName = (sortType >= static_cast(ProfilerSortType::Alphabetical) && (sortType < static_cast(ProfilerSortType::AlphabeticalCount))); + AZ_POP_DISABLE_WARNING if (ImGui::Selectable("Pass Names", sortByName)) { @@ -1011,7 +1013,7 @@ namespace AZ const uint32_t countNumerical = static_cast(count); const uint32_t offset = static_cast(m_sortType) - startNumerical; - if (offset < countNumerical && offset >= 0u) + if (offset < countNumerical) { // Change the sorting order. m_sortType = static_cast(((offset + 1u) % countNumerical) + startNumerical); diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphConnectionCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphConnectionCommands.cpp index b6a3870073..8396ad7b83 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphConnectionCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphConnectionCommands.cpp @@ -497,13 +497,13 @@ namespace CommandSystem } // verify port ranges - if (m_sourcePort >= static_cast(sourceNode->GetOutputPorts().size()) || m_sourcePort < 0) + if (m_sourcePort >= static_cast(sourceNode->GetOutputPorts().size())) { outResult = AZStd::string::format("The output port number is not valid for the given node. Node '%s' only has %zu output ports.", sourceNode->GetName(), sourceNode->GetOutputPorts().size()); return false; } - if (m_targetPort >= static_cast(targetNode->GetInputPorts().size()) || m_targetPort < 0) + if (m_targetPort >= static_cast(targetNode->GetInputPorts().size())) { outResult = AZStd::string::format("The input port number is not valid for the given node. Node '%s' only has %zu input ports.", targetNode->GetName(), targetNode->GetInputPorts().size()); return false; diff --git a/Gems/EMotionFX/Code/MCore/Source/StringConversions.cpp b/Gems/EMotionFX/Code/MCore/Source/StringConversions.cpp index c6b84a9e04..88a22db245 100644 --- a/Gems/EMotionFX/Code/MCore/Source/StringConversions.cpp +++ b/Gems/EMotionFX/Code/MCore/Source/StringConversions.cpp @@ -30,7 +30,7 @@ namespace MCore // find the last letter index from the right size_t lastIndex = AZStd::string::npos; const size_t numCharacters = prefixString.size(); - for (size_t i = numCharacters - 1; i >= 0; --i) + for (int i = static_cast(numCharacters) - 1; i >= 0; --i) { if (!AZStd::is_digit(prefixString[i])) { diff --git a/Gems/GraphModel/Code/Tests/TestEnvironment.cpp b/Gems/GraphModel/Code/Tests/TestEnvironment.cpp index 67d2e7af80..b7724c6799 100644 --- a/Gems/GraphModel/Code/Tests/TestEnvironment.cpp +++ b/Gems/GraphModel/Code/Tests/TestEnvironment.cpp @@ -51,7 +51,7 @@ namespace GraphModelIntegrationTest GraphModel::DataTypePtr TestGraphContext::GetDataType(GraphModel::DataType::Enum typeEnum) const { - if (0 <= typeEnum && typeEnum < m_dataTypes.size()) + if (typeEnum < m_dataTypes.size()) { return m_dataTypes[typeEnum]; } diff --git a/Gems/LandscapeCanvas/Code/Source/Editor/Core/GraphContext.cpp b/Gems/LandscapeCanvas/Code/Source/Editor/Core/GraphContext.cpp index 9011a82069..615139333c 100644 --- a/Gems/LandscapeCanvas/Code/Source/Editor/Core/GraphContext.cpp +++ b/Gems/LandscapeCanvas/Code/Source/Editor/Core/GraphContext.cpp @@ -102,7 +102,7 @@ namespace LandscapeCanvas GraphModel::DataTypePtr GraphContext::GetDataType(GraphModel::DataType::Enum typeEnum) const { - if (0 <= typeEnum && typeEnum < m_dataTypes.size()) + if (typeEnum < m_dataTypes.size()) { return m_dataTypes[typeEnum]; } diff --git a/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp b/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp index 9da32d757a..39e84d24a7 100644 --- a/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp @@ -294,7 +294,7 @@ unsigned int CAnimPostFXNode::GetParamCount() const //----------------------------------------------------------------------------- CAnimParamType CAnimPostFXNode::GetParamType(unsigned int nIndex) const { - if (nIndex >= 0 && nIndex < (int)m_pDescription->m_nodeParams.size()) + if (nIndex < m_pDescription->m_nodeParams.size()) { return m_pDescription->m_nodeParams[nIndex].paramType; } diff --git a/Gems/Maestro/Code/Source/Cinematics/AnimScreenFaderNode.cpp b/Gems/Maestro/Code/Source/Cinematics/AnimScreenFaderNode.cpp index 62cffcefb1..975e31d8cb 100644 --- a/Gems/Maestro/Code/Source/Cinematics/AnimScreenFaderNode.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/AnimScreenFaderNode.cpp @@ -304,7 +304,7 @@ unsigned int CAnimScreenFaderNode::GetParamCount() const //----------------------------------------------------------------------------- CAnimParamType CAnimScreenFaderNode::GetParamType(unsigned int nIndex) const { - if (nIndex >= 0 && nIndex < (int)s_screenFaderNodeParams.size()) + if (nIndex < s_screenFaderNodeParams.size()) { return s_screenFaderNodeParams[nIndex].paramType; } diff --git a/Gems/Maestro/Code/Source/Cinematics/CommentNode.cpp b/Gems/Maestro/Code/Source/Cinematics/CommentNode.cpp index fc58b91723..98bfef78a0 100644 --- a/Gems/Maestro/Code/Source/Cinematics/CommentNode.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/CommentNode.cpp @@ -120,7 +120,7 @@ unsigned int CCommentNode::GetParamCount() const //----------------------------------------------------------------------------- CAnimParamType CCommentNode::GetParamType(unsigned int nIndex) const { - if (nIndex >= 0 && nIndex < (int)s_nodeParameters.size()) + if (nIndex < s_nodeParameters.size()) { return s_nodeParameters[nIndex].paramType; } diff --git a/Gems/Maestro/Code/Source/Cinematics/LayerNode.cpp b/Gems/Maestro/Code/Source/Cinematics/LayerNode.cpp index 8c518f5a54..e2a9e816c6 100644 --- a/Gems/Maestro/Code/Source/Cinematics/LayerNode.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/LayerNode.cpp @@ -144,7 +144,7 @@ unsigned int CLayerNode::GetParamCount() const //----------------------------------------------------------------------------- CAnimParamType CLayerNode::GetParamType(unsigned int nIndex) const { - if (nIndex >= 0 && nIndex < (int)s_nodeParams.size()) + if (nIndex < (int)s_nodeParams.size()) { return s_nodeParams[nIndex].paramType; } diff --git a/Gems/Maestro/Code/Source/Cinematics/MaterialNode.cpp b/Gems/Maestro/Code/Source/Cinematics/MaterialNode.cpp index 08d4d92e8b..74b0fb1063 100644 --- a/Gems/Maestro/Code/Source/Cinematics/MaterialNode.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/MaterialNode.cpp @@ -180,7 +180,7 @@ unsigned int CAnimMaterialNode::GetParamCount() const ////////////////////////////////////////////////////////////////////////// CAnimParamType CAnimMaterialNode::GetParamType(unsigned int nIndex) const { - if (nIndex >= 0 && nIndex < (int)s_nodeParams.size()) + if (nIndex < s_nodeParams.size()) { return s_nodeParams[nIndex].paramType; } diff --git a/Gems/Maestro/Code/Source/Cinematics/SceneNode.cpp b/Gems/Maestro/Code/Source/Cinematics/SceneNode.cpp index d4b894dc92..79841e671b 100644 --- a/Gems/Maestro/Code/Source/Cinematics/SceneNode.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/SceneNode.cpp @@ -260,7 +260,7 @@ unsigned int CAnimSceneNode::GetParamCount() const ////////////////////////////////////////////////////////////////////////// CAnimParamType CAnimSceneNode::GetParamType(unsigned int nIndex) const { - if (nIndex >= 0 && nIndex < (int)s_nodeParams.size()) + if (nIndex < s_nodeParams.size()) { return s_nodeParams[nIndex].paramType; } diff --git a/Gems/Maestro/Code/Source/Cinematics/ShadowsSetupNode.cpp b/Gems/Maestro/Code/Source/Cinematics/ShadowsSetupNode.cpp index fd5e30199e..817c37483e 100644 --- a/Gems/Maestro/Code/Source/Cinematics/ShadowsSetupNode.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/ShadowsSetupNode.cpp @@ -87,7 +87,7 @@ unsigned int CShadowsSetupNode::GetParamCount() const //----------------------------------------------------------------------------- CAnimParamType CShadowsSetupNode::GetParamType(unsigned int nIndex) const { - if (nIndex >= 0 && nIndex < (int)ShadowSetupNode::s_shadowSetupParams.size()) + if (nIndex < ShadowSetupNode::s_shadowSetupParams.size()) { return ShadowSetupNode::s_shadowSetupParams[nIndex].paramType; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeFunctionGeneric.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeFunctionGeneric.h index e9586ac83a..90acd4fdc9 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeFunctionGeneric.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeFunctionGeneric.h @@ -104,7 +104,9 @@ namespace ScriptCanvas private:\ static AZStd::string_view GetName(size_t i)\ {\ + AZ_PUSH_DISABLE_WARNING(4296, "-Wunknown-warning-option")\ static_assert(s_numArgs <= s_numNames, "Number of arguments is greater than number of names in " #NODE_NAME );\ + AZ_POP_DISABLE_WARNING\ /*static_assert(s_numResults <= s_numNames, "Number of results is greater than number of names in " #NODE_NAME );*/\ /*static_assert((s_numResults + s_numArgs) == s_numNames, "Argument name count + result name count != name count in " #NODE_NAME );*/\ static const AZStd::array s_names = {{ __VA_ARGS__ }};\ diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNodeOverloaded.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNodeOverloaded.cpp index 92039d3394..58af3a75de 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNodeOverloaded.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNodeOverloaded.cpp @@ -575,7 +575,7 @@ namespace ScriptCanvas const SlotExecution::Map* slotExecutionMap = GetSlotExecutionMap(); const auto& executionIns = slotExecutionMap->GetIns(); - if (methodIndex < 0 || methodIndex >= executionIns.size()) + if (methodIndex >= executionIns.size()) { return; } @@ -655,7 +655,7 @@ namespace ScriptCanvas AZ::Outcome NodeableNodeOverloaded::IsValidConfiguration(size_t methodIndex, const DataIndexMapping& inputMapping, const DataIndexMapping& outputMapping) { - if (methodIndex < 0 || methodIndex >= m_methodConfigurations.size()) + if (methodIndex >= m_methodConfigurations.size()) { return AZ::Failure(AZStd::string("Trying to access unknown method index.")); } @@ -716,7 +716,7 @@ namespace ScriptCanvas const SlotExecution::Map* slotExecutionMap = GetSlotExecutionMap(); const auto& executionIns = slotExecutionMap->GetIns(); - if (methodIndex < 0 || methodIndex >= executionIns.size()) + if (methodIndex >= executionIns.size()) { return AZ::Failure(AZStd::string("Invalid method index given to Nodeable"));; } @@ -785,7 +785,7 @@ namespace ScriptCanvas return AZ::Success(); } - if (methodIndex < 0 || methodIndex >= m_methodConfigurations.size()) + if (methodIndex >= m_methodConfigurations.size()) { return AZ::Failure(AZStd::string("Invalid Method index given to Nodeable Node Overloaded.")); } @@ -826,7 +826,7 @@ namespace ScriptCanvas { static const DataTypeSet k_emptySet; - if (methodIndex >= 0 && methodIndex < m_methodSelections.size()) + if (methodIndex < m_methodSelections.size()) { const OverloadConfiguration& overloadConfiguration = m_methodConfigurations[methodIndex]; size_t startIndex = NodeableNodeOverloadedCpp::AdjustForHiddenNodeableThisPointer(overloadConfiguration, 0); @@ -845,7 +845,7 @@ namespace ScriptCanvas return AZ::Success(); } - if (methodIndex < 0 || methodIndex >= m_methodConfigurations.size()) + if (methodIndex >= m_methodConfigurations.size()) { return AZ::Failure(AZStd::string("Invalid Method index given to Nodeable Node Overloaded.")); } @@ -883,7 +883,7 @@ namespace ScriptCanvas { static const DataTypeSet k_emptySet; - if (methodIndex >= 0 && methodIndex < m_methodSelections.size()) + if (methodIndex < m_methodSelections.size()) { return m_methodSelections[methodIndex].FindPossibleInputTypes(index); } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SubgraphInterface.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SubgraphInterface.cpp index 9d1626fb73..5a88036a0f 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SubgraphInterface.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SubgraphInterface.cpp @@ -37,7 +37,7 @@ namespace SubgraphInterfaceCpp AZ_INLINE const char* GetTabs(size_t tabs) { - AZ_Assert(tabs >= 0 && tabs <= k_maxTabs, "invalid argument to GetTabs"); + AZ_Assert(tabs <= k_maxTabs, "invalid argument to GetTabs"); static const char* const k_tabs[] = { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/String/StringGenerics.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/String/StringGenerics.h index b3a4faae30..d5ee52cdb1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/String/StringGenerics.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/String/StringGenerics.h @@ -34,7 +34,7 @@ namespace ScriptCanvas { length = AZ::GetClamp(length, 0, aznumeric_cast(sourceString.size())); - if (length == 0 || index < 0 || index >= sourceString.size()) + if (length == 0 || index >= sourceString.size()) { return {}; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationUtilities.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationUtilities.cpp index 7c03102a71..a9ca526373 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationUtilities.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationUtilities.cpp @@ -30,7 +30,7 @@ namespace TranslationUtilitiesCPP AZ_INLINE const char* GetTabs(size_t tabs) { - AZ_Assert(tabs >= 0 && tabs <= k_maxTabs, "invalid argument to GetTabs"); + AZ_Assert(tabs <= k_maxTabs, "invalid argument to GetTabs"); static const char* const k_tabs[] = { diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventBroadcast.cpp b/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventBroadcast.cpp index c55495efad..1e5e741b5d 100644 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventBroadcast.cpp +++ b/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventBroadcast.cpp @@ -111,7 +111,7 @@ namespace ScriptEvents { // Iterate from end of parameters and count the number of consecutive valid BehaviorValue objects size_t numDefaultArguments = 0; - for (size_t i = GetNumArguments() - 1; i >= 0 && GetDefaultValue(i); --i, ++numDefaultArguments) + for (int i = static_cast(GetNumArguments()) - 1; i >= 0 && GetDefaultValue(static_cast(i)); --i, ++numDefaultArguments) { } return GetNumArguments() - numDefaultArguments; diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventMethod.cpp b/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventMethod.cpp index 37f437670d..7153fda8bd 100644 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventMethod.cpp +++ b/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventMethod.cpp @@ -121,7 +121,7 @@ namespace ScriptEvents { // Iterate from end of parameters and count the number of consecutive valid BehaviorValue objects size_t numDefaultArguments = 0; - for (size_t i = GetNumArguments() - 1; i >= 0 && GetDefaultValue(i); --i, ++numDefaultArguments) + for (int i = static_cast(GetNumArguments()) - 1; i >= 0 && GetDefaultValue(static_cast(i)); --i, ++numDefaultArguments) { } return GetNumArguments() - numDefaultArguments; diff --git a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake index 0119f8d8bc..9353e4eb1c 100644 --- a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake +++ b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake @@ -39,11 +39,11 @@ ly_append_configurations_options( # Enabling warnings that are disabled by default from /W4 # https://docs.microsoft.com/en-us/cpp/preprocessor/compiler-warnings-that-are-off-by-default?view=vs-2019 - # /we4296 # 'operator': expression is always false + /we4296 # 'operator': expression is always false # /we4426 # optimization flags changed after including header, may be due to #pragma optimize() # /we4464 # relative include path contains '..' # /we4619 # #pragma warning: there is no warning number 'number' - # /we4777 # 'function' : format string 'string' requires an argument of type 'type1', but variadic argument number has type 'type2' looks useful + # /we4777 # 'function' : format string 'string' requires an argument of type 'type1', but variadic argument number has type 'type2' # /we5031 # #pragma warning(pop): likely mismatch, popping warning state pushed in different file # /WE5032 # detected #pragma warning(push) with no corresponding #pragma warning(pop) From ec351c9fcebe3b0bd922456c619d9af3503fddbe Mon Sep 17 00:00:00 2001 From: puvvadar Date: Thu, 19 Aug 2021 16:27:04 -0700 Subject: [PATCH 37/54] Correct jinja logic slightly Signed-off-by: puvvadar --- Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index 8010d1bfc2..bf1b80345a 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -318,7 +318,7 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(par constexpr AzNetworking::ReliabilityType isReliable = Multiplayer::ReliabilityType::Unreliable; {% endif %} -{% if (InvokeFrom == 'Server' or InvokeFrom =="Client") and HandleOn == 'Authority' %} +{% if InvokeFrom == 'Server' or InvokeFrom =='Client' %} const Multiplayer::NetComponentId netComponentId = GetNetComponentId(); {% else %} const Multiplayer::NetComponentId netComponentId = GetParent().GetNetComponentId(); From cbf612d4e7a31b7405e54103ea3602b9cd1fd9b9 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Thu, 19 Aug 2021 16:36:41 -0700 Subject: [PATCH 38/54] Update naming to match other functions in jinja Signed-off-by: puvvadar --- .../Code/Source/AutoGen/AutoComponent_Source.jinja | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index bf1b80345a..bfaf1c2be0 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -349,9 +349,9 @@ void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.jo {# #} -{% macro DefineRpcInvocations(Component, ClassName, InvokeFrom, HandleOn, ProctectedSection) %} +{% macro DefineRpcInvocations(Component, ClassName, InvokeFrom, HandleOn, IsProtected) %} {% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, InvokeFrom, HandleOn) %} -{% if Property.attrib['IsPublic']|booleanTrue == ProctectedSection %} +{% if Property.attrib['IsPublic']|booleanTrue == IsProtected %} {{ DefineRpcInvocation(Component, ClassName, Property, InvokeFrom, HandleOn) -}} {% if Property.attrib['GenerateEventBindings']|booleanTrue == true %} {{ DefineRpcSignal(Component, ClassName, Property, InvokeFrom) -}} From 99317a4ad12f0a707d4892752656ff1280b9f41a Mon Sep 17 00:00:00 2001 From: puvvadar Date: Thu, 19 Aug 2021 16:39:11 -0700 Subject: [PATCH 39/54] Update naming to match other functions in jinja header Signed-off-by: puvvadar --- .../Code/Source/AutoGen/AutoComponent_Header.jinja | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja index cff4c57e98..b8a2c3dca5 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja @@ -130,9 +130,9 @@ void {{ PropertyName }}({{ ', '.join(paramDefines) }}); {# #} -{% macro DeclareRpcInvocations(Component, Section, HandleOn, ProctectedSection) %} +{% macro DeclareRpcInvocations(Component, Section, HandleOn, IsProtected) %} {% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, Section, HandleOn) %} -{% if Property.attrib['IsPublic']|booleanTrue != ProctectedSection %} +{% if Property.attrib['IsPublic']|booleanTrue != IsProtected %} {{ DeclareRpcInvocation(Property, HandleOn) -}} {% endif %} {% endcall %} From 41ec5c6ddd41b29e50986fe887e8c106664079a3 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Thu, 19 Aug 2021 17:08:01 -0700 Subject: [PATCH 40/54] Fix one more jinja issue with IsProtected in RPCs Signed-off-by: puvvadar --- Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index bfaf1c2be0..bfd1ceb305 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -351,7 +351,7 @@ void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.jo #} {% macro DefineRpcInvocations(Component, ClassName, InvokeFrom, HandleOn, IsProtected) %} {% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, InvokeFrom, HandleOn) %} -{% if Property.attrib['IsPublic']|booleanTrue == IsProtected %} +{% if Property.attrib['IsPublic']|booleanTrue != IsProtected %} {{ DefineRpcInvocation(Component, ClassName, Property, InvokeFrom, HandleOn) -}} {% if Property.attrib['GenerateEventBindings']|booleanTrue == true %} {{ DefineRpcSignal(Component, ClassName, Property, InvokeFrom) -}} From 5997313bb594122bc1058985fee76c2cf8cc7aca Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 19 Aug 2021 19:27:50 -0500 Subject: [PATCH 41/54] AtomTools: moved more startup code from main cpp files into the base application class Deleted a bunch of unused headers Signed-off-by: Guthrie Adams --- .../Application/AtomToolsApplication.h | 3 ++ .../Application/AtomToolsApplication.cpp | 18 ++++++++- .../Tools/MaterialEditor/Code/Source/main.cpp | 35 ++---------------- .../Code/Source/main.cpp | 37 +++---------------- 4 files changed, 28 insertions(+), 65 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h index 6421c877b0..d55755a242 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -113,6 +114,8 @@ namespace AtomToolsFramework AzToolsFramework::TraceLogger m_traceLogger; + AZStd::unique_ptr m_styleManager; + //! Local user settings are used to store material browser tree expansion state AZ::UserSettingsProvider m_localUserSettings; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp index 4cc98a15aa..b8426f7528 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp @@ -21,6 +21,8 @@ #include #include +#include + #include #include #include @@ -61,14 +63,26 @@ namespace AtomToolsFramework : Application(argc, argv) , AzQtApplication(*argc, *argv) { + // Suppress spam from the Source Control system + m_traceLogger.AddWindowFilter(AzToolsFramework::SCC_WINDOW); + + installEventFilter(new AzQtComponents::GlobalEventFilter(this)); + + AZ::IO::FixedMaxPath engineRootPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + + m_styleManager.reset(new AzQtComponents::StyleManager(this)); + m_styleManager->initialize(this, engineRootPath); + connect(&m_timer, &QTimer::timeout, this, [&]() { this->PumpSystemEventLoopUntilEmpty(); this->Tick(); }); - // Suppress spam from the Source Control system - m_traceLogger.AddWindowFilter(AzToolsFramework::SCC_WINDOW); } AtomToolsApplication ::~AtomToolsApplication() diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp index de29c27b71..05a044db0b 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp @@ -6,46 +6,19 @@ * */ -#if !defined(Q_MOC_RUN) #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#endif - int main(int argc, char** argv) { AzQtComponents::AzQtApplication::InitializeDpiScaling(); MaterialEditor::MaterialEditorApplication app(&argc, &argv); - if (!app.LaunchLocalServer()) + if (app.LaunchLocalServer()) { - return 0; + app.Start(AZ::ComponentApplication::Descriptor{}); + app.exec(); + app.Stop(); } - app.installEventFilter(new AzQtComponents::GlobalEventFilter(&app)); - - AZ::IO::FixedMaxPath engineRootPath; - if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) - { - settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); - } - - AzQtComponents::StyleManager styleManager(&app); - styleManager.initialize(&app, engineRootPath); - - app.Start(AZ::ComponentApplication::Descriptor{}); - app.exec(); - app.Stop(); return 0; } diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp index cf3f25cf6c..8291ce587e 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp @@ -6,46 +6,19 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include +#include int main(int argc, char** argv) { AzQtComponents::AzQtApplication::InitializeDpiScaling(); ShaderManagementConsole::ShaderManagementConsoleApplication app(&argc, &argv); - if (!app.LaunchLocalServer()) + if (app.LaunchLocalServer()) { - return 0; + app.Start(AZ::ComponentApplication::Descriptor{}); + app.exec(); + app.Stop(); } - app.installEventFilter(new AzQtComponents::GlobalEventFilter(&app)); - - AZ::IO::FixedMaxPath engineRootPath; - if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) - { - settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); - } - - AzQtComponents::StyleManager styleManager(&app); - styleManager.initialize(&app, engineRootPath); - - app.Start(AZ::ComponentApplication::Descriptor{}); - app.exec(); - app.Stop(); return 0; } From 83f8d90e28ef4588e03ed4d8f9901237b11e50f3 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 19 Aug 2021 18:28:18 -0700 Subject: [PATCH 42/54] PR comments Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Editor/Util/3DConnexionDriver.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Code/Editor/Util/3DConnexionDriver.cpp b/Code/Editor/Util/3DConnexionDriver.cpp index 73e7954c88..9dc1600185 100644 --- a/Code/Editor/Util/3DConnexionDriver.cpp +++ b/Code/Editor/Util/3DConnexionDriver.cpp @@ -58,11 +58,6 @@ bool C3DConnexionDriver::InitDevice() //Doc says RIM_TYPEHID: Data comes from an HID that is not a keyboard or a mouse. if (m_pRawInputDeviceList[i].dwType == RIM_TYPEHID) { - UINT nchars = 300; - TCHAR deviceName[300]; - GetRawInputDeviceInfo(m_pRawInputDeviceList[i].hDevice, - RIDI_DEVICENAME, deviceName, &nchars); - RID_DEVICE_INFO dinfo; UINT sizeofdinfo = sizeof(dinfo); dinfo.cbSize = sizeofdinfo; From 69c6e63249a4629130e9563f4a32513b424f5d33 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 20 Aug 2021 10:41:03 -0500 Subject: [PATCH 43/54] Fixed console variables crash. Signed-off-by: Chris Galvan --- Code/Legacy/CrySystem/XConsole.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Code/Legacy/CrySystem/XConsole.cpp b/Code/Legacy/CrySystem/XConsole.cpp index 2293352f7e..46eea1528c 100644 --- a/Code/Legacy/CrySystem/XConsole.cpp +++ b/Code/Legacy/CrySystem/XConsole.cpp @@ -3133,6 +3133,9 @@ char* CXConsole::GetCheatVarAt(uint32 nOffset) ////////////////////////////////////////////////////////////////////////// size_t CXConsole::GetSortedVars(AZStd::vector& pszArray, const char* szPrefix) { + // This method used to insert instead of push_back, so we need to clear first + pszArray.clear(); + size_t iPrefixLen = szPrefix ? strlen(szPrefix) : 0; // variables From cef82f0313868e930c8eda17ee38153af82f8b51 Mon Sep 17 00:00:00 2001 From: bosnichd Date: Fri, 20 Aug 2021 09:58:33 -0600 Subject: [PATCH 44/54] Fix the GameStateSamples Gem and remove an unused variable from DebugConsole.h (#3347) Signed-off-by: bosnichd --- .../ImguiAtom/Code/Source/DebugConsole.h | 1 - Gems/GameState/Code/CMakeLists.txt | 6 ++---- Gems/GameStateSamples/Code/CMakeLists.txt | 8 +++++--- .../Code/Source/GameStateSamplesModule.cpp | 18 ++++++++++++++++++ 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Gems/AtomLyIntegration/ImguiAtom/Code/Source/DebugConsole.h b/Gems/AtomLyIntegration/ImguiAtom/Code/Source/DebugConsole.h index bdfc28c34c..d4855306be 100644 --- a/Gems/AtomLyIntegration/ImguiAtom/Code/Source/DebugConsole.h +++ b/Gems/AtomLyIntegration/ImguiAtom/Code/Source/DebugConsole.h @@ -122,7 +122,6 @@ namespace AZ int m_currentHistoryIndex = -1; //!< The current index into the input history when browsing. int m_maxEntriesToDisplay = DefaultMaxEntriesToDisplay; //!< The maximum entries to display. int m_maxInputHistorySize = DefaultMaxInputHistorySize; //!< The maximum input history size. - int m_logLevelToSet = 0; //!< The minimum log level to set (see AZ::LogLevel). bool m_isShowing = false; //!< Is the debug console currently being displayed? bool m_autoScroll = true; //!< Should we auto-scroll as new entries are added? bool m_forceScroll = false; //!< Do we need to force scroll after input entered? diff --git a/Gems/GameState/Code/CMakeLists.txt b/Gems/GameState/Code/CMakeLists.txt index 7aa99446cb..debedd8500 100644 --- a/Gems/GameState/Code/CMakeLists.txt +++ b/Gems/GameState/Code/CMakeLists.txt @@ -17,8 +17,8 @@ ly_add_target( PUBLIC Include BUILD_DEPENDENCIES - PRIVATE - Legacy::CryCommon + PUBLIC + AZ::AzCore ) ly_add_target( @@ -33,7 +33,6 @@ ly_add_target( Include BUILD_DEPENDENCIES PRIVATE - Legacy::CryCommon Gem::GameState.Static ) @@ -58,7 +57,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) BUILD_DEPENDENCIES PRIVATE AZ::AzTest - Legacy::CryCommon Gem::GameState.Static ) ly_add_googletest( diff --git a/Gems/GameStateSamples/Code/CMakeLists.txt b/Gems/GameStateSamples/Code/CMakeLists.txt index 34132e67b1..5d1d180de0 100644 --- a/Gems/GameStateSamples/Code/CMakeLists.txt +++ b/Gems/GameStateSamples/Code/CMakeLists.txt @@ -21,6 +21,7 @@ ly_add_target( INTERFACE Gem::GameState Gem::LocalUser + Gem::LyShine.Static Gem::SaveData.Static Gem::MessagePopup.Static Legacy::CryCommon @@ -47,6 +48,7 @@ ly_add_target( Gem::LmbrCentral ) -# Clients and Servers use the above module. There is no editor or tools module required. -ly_create_alias(NAME GameStateSamples.Clients NAMESPACE Gem TARGETS GameStateSamples) -ly_create_alias(NAME GameStateSamples.Servers NAMESPACE Gem TARGETS GameStateSamples) +# Clients and Servers use the above module, and it contains assets so is needed by builders. +ly_create_alias(NAME GameStateSamples.Clients NAMESPACE Gem TARGETS Gem::GameStateSamples) +ly_create_alias(NAME GameStateSamples.Servers NAMESPACE Gem TARGETS Gem::GameStateSamples) +ly_create_alias(NAME GameStateSamples.Builders NAMESPACE Gem TARGETS Gem::UiBasics.Builders Gem::LyShineExamples.Builders) diff --git a/Gems/GameStateSamples/Code/Source/GameStateSamplesModule.cpp b/Gems/GameStateSamples/Code/Source/GameStateSamplesModule.cpp index 24a29c97ab..f175619bf4 100644 --- a/Gems/GameStateSamples/Code/Source/GameStateSamplesModule.cpp +++ b/Gems/GameStateSamples/Code/Source/GameStateSamplesModule.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -55,6 +56,7 @@ namespace GameStateSamples //! class GameStateSamplesModule : public CryHooksModule + , public AZ::TickBus::Handler , public GameOptionRequestBus::Handler { public: @@ -86,6 +88,22 @@ namespace GameStateSamples { CryHooksModule::OnCrySystemInitialized(system, systemInitParams); + AZ::TickBus::Handler::BusConnect(); + } + + void OnTick([[maybe_unused]]float deltaTime, [[maybe_unused]]AZ::ScriptTimePoint scriptTimePoint) override + { + // Ideally this would be called at startup (either above in OnCrySystemInitialized, or better during AZ system component + // initialisation), but because the initial game state depends on loading a UI canvas using LYShine we need to wait until + // the first tick, because LyShine in turn is not properly initialized until UiRenderer::OnBootstrapSceneReady has been + // called, which doesn't happen until a queued tick event that gets called right at the end of initialisation before we + // enter the main game loop. + CreateAndPushInitialGameState(); + AZ::TickBus::Handler::BusDisconnect(); + } + + void CreateAndPushInitialGameState() + { REGISTER_INT("sys_primaryUserSelectionEnabled", 2, VF_NULL, "Controls whether the game forces selection of a primary user at startup.\n" "0 : Skip selection of a primary user at startup on all platform.\n" From 8d6df19592abafdf0f9ff196ac9c4f152fc424bb Mon Sep 17 00:00:00 2001 From: evanchia Date: Fri, 20 Aug 2021 09:15:14 -0700 Subject: [PATCH 45/54] fixes a flaky lytesttools unit test Signed-off-by: evanchia --- Tools/LyTestTools/tests/unit/test_builtin_helpers.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tools/LyTestTools/tests/unit/test_builtin_helpers.py b/Tools/LyTestTools/tests/unit/test_builtin_helpers.py index 63dd051a62..9eb8a1703d 100755 --- a/Tools/LyTestTools/tests/unit/test_builtin_helpers.py +++ b/Tools/LyTestTools/tests/unit/test_builtin_helpers.py @@ -7,6 +7,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT Unit tests for ly_test_tools.builtin.helpers functions. """ import unittest.mock as mock +import os import pytest @@ -41,6 +42,8 @@ class MockedWorkspaceManager(ly_test_tools._internal.managers.workspace.Abstract ) +@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator._find_project_json', + mock.MagicMock(return_value=os.path.join("mocked", "path"))) @mock.patch( 'ly_test_tools._internal.managers.abstract_resource_locator.AbstractResourceLocator', mock.MagicMock(return_value=MockedAbstractResourceLocator) From bf42e3f02a935fca3fb63ebd65b68cfeb123b593 Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Fri, 20 Aug 2021 11:31:19 -0500 Subject: [PATCH 46/54] Non-terrain-gem changes in support of upcoming terrain work. (#3345) In preparation for a prototype Terrain Gem to get submitted, there are a few changes that are needed outside of the Terrain Gem as well: The TerrainDataNotificationBus lives in AzFramework/Terrain, and needed to be extended to contain an optional OnTerrainDataChanged event to notify other systems when a terrain region has changed. The HeightmapUpdateNotificationBus was removed, as this was a legacy file from the old already-removed terrain system. The EditorWrappedComponentBase<> wrapper received a small optimization to ensure that ConfigurationChanged() is only called when the value of visibility actually changes. With prefabs, it appears that sometimes OnEntityVisibilityChanged could be called multiple times in a row with the same visibility value. The TerrainSurfaceDataSystemComponent was updated to use the correct busses, and is ready to be moved to the Terrain Gem in a subsequent PR. Signed-off-by: Mike Balfour 82224783+mbalfour-amzn@users.noreply.github.com --- .../Terrain/TerrainDataRequestBus.h | 22 ++++- .../HeightmapUpdateNotificationBus.h | 34 ------- Code/Legacy/CryCommon/crycommon_files.cmake | 1 - .../Component/EditorWrappedComponentBase.inl | 7 +- .../SurfaceData/Utility/SurfaceDataUtility.h | 1 - .../Code/Source/SurfaceDataModule.cpp | 4 +- .../TerrainSurfaceDataSystemComponent.cpp | 90 +++++++++---------- .../TerrainSurfaceDataSystemComponent.h | 26 ++---- 8 files changed, 75 insertions(+), 110 deletions(-) delete mode 100644 Code/Legacy/CryCommon/HeightmapUpdateNotificationBus.h diff --git a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h index 2e7cd1d170..08e238434e 100644 --- a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h +++ b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h @@ -102,11 +102,25 @@ namespace AzFramework static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; ////////////////////////////////////////////////////////////////////////// - virtual void OnTerrainDataCreateBegin() {}; - virtual void OnTerrainDataCreateEnd() {}; + enum TerrainDataChangedMask : uint8_t + { + None = 0b00000000, + Settings = 0b00000001, + HeightData = 0b00000010, + ColorData = 0b00000100, + SurfaceData = 0b00001000 + }; - virtual void OnTerrainDataDestroyBegin() {}; - virtual void OnTerrainDataDestroyEnd() {}; + virtual void OnTerrainDataCreateBegin() {} + virtual void OnTerrainDataCreateEnd() {} + + virtual void OnTerrainDataDestroyBegin() {} + virtual void OnTerrainDataDestroyEnd() {} + + virtual void OnTerrainDataChanged( + [[maybe_unused]] const AZ::Aabb& dirtyRegion, [[maybe_unused]] TerrainDataChangedMask dataChangedMask) + { + } }; using TerrainDataNotificationBus = AZ::EBus; diff --git a/Code/Legacy/CryCommon/HeightmapUpdateNotificationBus.h b/Code/Legacy/CryCommon/HeightmapUpdateNotificationBus.h deleted file mode 100644 index 618131159e..0000000000 --- a/Code/Legacy/CryCommon/HeightmapUpdateNotificationBus.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include - -namespace AZ -{ - /** - * the EBus is used to request information about potential vegetation surfaces - */ - class HeightmapUpdateNotification - : public AZ::EBusTraits - { - public: - //////////////////////////////////////////////////////////////////////// - // EBusTraits - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - //////////////////////////////////////////////////////////////////////// - - // Occurs when the terrain height map is modified. - virtual void HeightmapModified(const AZ::Aabb& bounds) = 0; - }; - - typedef AZ::EBus HeightmapUpdateNotificationBus; -} diff --git a/Code/Legacy/CryCommon/crycommon_files.cmake b/Code/Legacy/CryCommon/crycommon_files.cmake index b8f73d064f..ba11de0215 100644 --- a/Code/Legacy/CryCommon/crycommon_files.cmake +++ b/Code/Legacy/CryCommon/crycommon_files.cmake @@ -53,7 +53,6 @@ set(FILES HMDBus.h VRCommon.h StereoRendererBus.h - HeightmapUpdateNotificationBus.h INavigationSystem.h IMNM.h SFunctor.h diff --git a/Gems/LmbrCentral/Code/include/LmbrCentral/Component/EditorWrappedComponentBase.inl b/Gems/LmbrCentral/Code/include/LmbrCentral/Component/EditorWrappedComponentBase.inl index 2c49710ddd..6a9fceabbf 100644 --- a/Gems/LmbrCentral/Code/include/LmbrCentral/Component/EditorWrappedComponentBase.inl +++ b/Gems/LmbrCentral/Code/include/LmbrCentral/Component/EditorWrappedComponentBase.inl @@ -212,8 +212,11 @@ namespace LmbrCentral template void EditorWrappedComponentBase::OnEntityVisibilityChanged(bool visibility) { - m_visible = visibility; - ConfigurationChanged(); + if (m_visible != visibility) + { + m_visible = visibility; + ConfigurationChanged(); + } } template diff --git a/Gems/SurfaceData/Code/Include/SurfaceData/Utility/SurfaceDataUtility.h b/Gems/SurfaceData/Code/Include/SurfaceData/Utility/SurfaceDataUtility.h index c72f725a07..29b3fac8c7 100644 --- a/Gems/SurfaceData/Code/Include/SurfaceData/Utility/SurfaceDataUtility.h +++ b/Gems/SurfaceData/Code/Include/SurfaceData/Utility/SurfaceDataUtility.h @@ -14,7 +14,6 @@ #include #include #include -#include namespace AZ { diff --git a/Gems/SurfaceData/Code/Source/SurfaceDataModule.cpp b/Gems/SurfaceData/Code/Source/SurfaceDataModule.cpp index 6c96ee9d27..4eef54669a 100644 --- a/Gems/SurfaceData/Code/Source/SurfaceDataModule.cpp +++ b/Gems/SurfaceData/Code/Source/SurfaceDataModule.cpp @@ -20,7 +20,7 @@ namespace SurfaceData SurfaceDataSystemComponent::CreateDescriptor(), SurfaceDataColliderComponent::CreateDescriptor(), SurfaceDataShapeComponent::CreateDescriptor(), - TerrainSurfaceDataSystemComponent::CreateDescriptor(), + Terrain::TerrainSurfaceDataSystemComponent::CreateDescriptor(), }); } @@ -28,7 +28,7 @@ namespace SurfaceData { return AZ::ComponentTypeList{ azrtti_typeid(), - azrtti_typeid(), + azrtti_typeid(), }; } } diff --git a/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.cpp b/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.cpp index 0f6eec73cd..a60bbc4034 100644 --- a/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.cpp +++ b/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.cpp @@ -6,20 +6,16 @@ * */ -#include "TerrainSurfaceDataSystemComponent.h" +#include #include #include #include #include -#include -#include #include #include #include -#include - -namespace SurfaceData +namespace Terrain { ////////////////////////////////////////////////////////////////////////// // TerrainSurfaceDataSystemConfig @@ -98,26 +94,23 @@ namespace SurfaceData void TerrainSurfaceDataSystemComponent::Activate() { - m_providerHandle = InvalidSurfaceDataRegistryHandle; - m_system = GetISystem(); - CrySystemEventBus::Handler::BusConnect(); - AZ::HeightmapUpdateNotificationBus::Handler::BusConnect(); + m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle; + AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect(); UpdateTerrainData(AZ::Aabb::CreateNull()); } void TerrainSurfaceDataSystemComponent::Deactivate() { - if (m_providerHandle != InvalidSurfaceDataRegistryHandle) + if (m_providerHandle != SurfaceData::InvalidSurfaceDataRegistryHandle) { - SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::UnregisterSurfaceDataProvider, m_providerHandle); - m_providerHandle = InvalidSurfaceDataRegistryHandle; + SurfaceData::SurfaceDataSystemRequestBus::Broadcast( + &SurfaceData::SurfaceDataSystemRequestBus::Events::UnregisterSurfaceDataProvider, m_providerHandle); + m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle; } - SurfaceDataProviderRequestBus::Handler::BusDisconnect(); - AZ::HeightmapUpdateNotificationBus::Handler::BusDisconnect(); - CrySystemEventBus::Handler::BusDisconnect(); - m_system = nullptr; + SurfaceData::SurfaceDataProviderRequestBus::Handler::BusDisconnect(); + AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect(); // Clear the cached terrain bounds data { @@ -146,17 +139,8 @@ namespace SurfaceData return false; } - void TerrainSurfaceDataSystemComponent::OnCrySystemInitialized(ISystem& system, [[maybe_unused]] const SSystemInitParams& systemInitParams) - { - m_system = &system; - } - - void TerrainSurfaceDataSystemComponent::OnCrySystemShutdown([[maybe_unused]] ISystem& system) - { - m_system = nullptr; - } - - void TerrainSurfaceDataSystemComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const + void TerrainSurfaceDataSystemComponent::GetSurfacePoints( + const AZ::Vector3& inPosition, SurfaceData::SurfacePointList& surfacePointList) const { if (m_terrainBoundsIsValid) { @@ -168,12 +152,13 @@ namespace SurfaceData const float terrainHeight = terrain->GetHeight(inPosition, AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, &isTerrainValidAtPoint); const bool isHole = !isTerrainValidAtPoint; - SurfacePoint point; + SurfaceData::SurfacePoint point; point.m_entityId = GetEntityId(); point.m_position = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), terrainHeight); point.m_normal = terrain->GetNormal(inPosition); - const AZ::Crc32 terrainTag = isHole ? Constants::s_terrainHoleTagCrc : Constants::s_terrainTagCrc; - AddMaxValueForMasks(point.m_masks, terrainTag, 1.0f); + const AZ::Crc32 terrainTag = + isHole ? SurfaceData::Constants::s_terrainHoleTagCrc : SurfaceData::Constants::s_terrainTagCrc; + SurfaceData::AddMaxValueForMasks(point.m_masks, terrainTag, 1.0f); surfacePointList.push_back(point); } // Only one handler should exist. @@ -189,11 +174,11 @@ namespace SurfaceData return terrain ? terrain->GetTerrainAabb() : AZ::Aabb::CreateNull(); } - SurfaceTagVector TerrainSurfaceDataSystemComponent::GetSurfaceTags() const + SurfaceData::SurfaceTagVector TerrainSurfaceDataSystemComponent::GetSurfaceTags() const { - SurfaceTagVector tags; - tags.push_back(Constants::s_terrainHoleTagCrc); - tags.push_back(Constants::s_terrainTagCrc); + SurfaceData::SurfaceTagVector tags; + tags.push_back(SurfaceData::Constants::s_terrainHoleTagCrc); + tags.push_back(SurfaceData::Constants::s_terrainTagCrc); return tags; } @@ -203,7 +188,7 @@ namespace SurfaceData bool terrainValidAfterUpdate = false; AZ::Aabb terrainBoundsBeforeUpdate = m_terrainBounds; - SurfaceDataRegistryEntry registryEntry; + SurfaceData::SurfaceDataRegistryEntry registryEntry; registryEntry.m_entityId = GetEntityId(); registryEntry.m_bounds = GetSurfaceAabb(); registryEntry.m_tags = GetSurfaceTags(); @@ -215,38 +200,44 @@ namespace SurfaceData if (terrainValidBeforeUpdate && terrainValidAfterUpdate) { - AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle"); + AZ_Assert((m_providerHandle != SurfaceData::InvalidSurfaceDataRegistryHandle), "Invalid surface data handle"); // Our terrain was valid before and after, it just changed in some way. If we have a valid dirty region passed in // then it's possible that the heightmap has been modified in the Editor. Otherwise, just notify that the entire // terrain has changed in some way. if (dirtyRegion.IsValid()) { - SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::RefreshSurfaceData, dirtyRegion); + SurfaceData::SurfaceDataSystemRequestBus::Broadcast( + &SurfaceData::SurfaceDataSystemRequestBus::Events::RefreshSurfaceData, dirtyRegion); } else { - SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::UpdateSurfaceDataProvider, m_providerHandle, registryEntry); + SurfaceData::SurfaceDataSystemRequestBus::Broadcast( + &SurfaceData::SurfaceDataSystemRequestBus::Events::UpdateSurfaceDataProvider, m_providerHandle, registryEntry); } } else if (!terrainValidBeforeUpdate && terrainValidAfterUpdate) { // Our terrain has become valid, so register as a provider and save off the registry handles - AZ_Assert((m_providerHandle == InvalidSurfaceDataRegistryHandle), "Surface Provider data handle is initialized before our terrain became valid"); - SurfaceDataSystemRequestBus::BroadcastResult(m_providerHandle, &SurfaceDataSystemRequestBus::Events::RegisterSurfaceDataProvider, registryEntry); + AZ_Assert( + (m_providerHandle == SurfaceData::InvalidSurfaceDataRegistryHandle), + "Surface Provider data handle is initialized before our terrain became valid"); + SurfaceData::SurfaceDataSystemRequestBus::BroadcastResult( + m_providerHandle, &SurfaceData::SurfaceDataSystemRequestBus::Events::RegisterSurfaceDataProvider, registryEntry); // Start listening for surface data events - AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle"); - SurfaceDataProviderRequestBus::Handler::BusConnect(m_providerHandle); + AZ_Assert((m_providerHandle != SurfaceData::InvalidSurfaceDataRegistryHandle), "Invalid surface data handle"); + SurfaceData::SurfaceDataProviderRequestBus::Handler::BusConnect(m_providerHandle); } else if (terrainValidBeforeUpdate && !terrainValidAfterUpdate) { // Our terrain has stopped being valid, so unregister and stop listening for surface data events - AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle"); - SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::UnregisterSurfaceDataProvider, m_providerHandle); - m_providerHandle = InvalidSurfaceDataRegistryHandle; + AZ_Assert((m_providerHandle != SurfaceData::InvalidSurfaceDataRegistryHandle), "Invalid surface data handle"); + SurfaceData::SurfaceDataSystemRequestBus::Broadcast( + &SurfaceData::SurfaceDataSystemRequestBus::Events::UnregisterSurfaceDataProvider, m_providerHandle); + m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle; - SurfaceDataProviderRequestBus::Handler::BusDisconnect(); + SurfaceData::SurfaceDataProviderRequestBus::Handler::BusDisconnect(); } else { @@ -255,8 +246,9 @@ namespace SurfaceData } - void TerrainSurfaceDataSystemComponent::HeightmapModified(const AZ::Aabb& bounds) + void TerrainSurfaceDataSystemComponent::OnTerrainDataChanged( + const AZ::Aabb& dirtyRegion, [[maybe_unused]] TerrainDataChangedMask dataChangedMask) { - UpdateTerrainData(bounds); + UpdateTerrainData(dirtyRegion); } } diff --git a/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.h b/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.h index aa5f4ab04c..a742eab78c 100644 --- a/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.h +++ b/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.h @@ -10,12 +10,11 @@ #include #include #include -#include -#include +#include #include #include -namespace SurfaceData +namespace Terrain { class TerrainSurfaceDataSystemConfig : public AZ::ComponentConfig @@ -31,9 +30,8 @@ namespace SurfaceData */ class TerrainSurfaceDataSystemComponent : public AZ::Component - , private SurfaceDataProviderRequestBus::Handler - , private AZ::HeightmapUpdateNotificationBus::Handler - , private CrySystemEventBus::Handler + , private SurfaceData::SurfaceDataProviderRequestBus::Handler + , private AzFramework::Terrain::TerrainDataNotificationBus::Handler { friend class EditorTerrainSurfaceDataSystemComponent; TerrainSurfaceDataSystemComponent(const TerrainSurfaceDataSystemConfig&); @@ -58,25 +56,19 @@ namespace SurfaceData ////////////////////////////////////////////////////////////////////////// // SurfaceDataProviderRequestBus - void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const; - - //////////////////////////////////////////////////////////////////////////// - // CrySystemEvents - void OnCrySystemInitialized(ISystem& system, const SSystemInitParams& systemInitParams) override; - void OnCrySystemShutdown(ISystem& system) override; + void GetSurfacePoints(const AZ::Vector3& inPosition, SurfaceData::SurfacePointList& surfacePointList) const; ////////////////////////////////////////////////////////////////////////// - // AZ::HeightmapUpdateNotificationBus - void HeightmapModified(const AZ::Aabb& bounds) override; + // AzFramework::Terrain::TerrainDataNotificationBus + void OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) override; private: void UpdateTerrainData(const AZ::Aabb& dirtyRegion); AZ::Aabb GetSurfaceAabb() const; - SurfaceTagVector GetSurfaceTags() const; - SurfaceDataRegistryHandle m_providerHandle = InvalidSurfaceDataRegistryHandle; + SurfaceData::SurfaceTagVector GetSurfaceTags() const; + SurfaceData::SurfaceDataRegistryHandle m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle; TerrainSurfaceDataSystemConfig m_configuration; - ISystem* m_system = nullptr; AZ::Aabb m_terrainBounds = AZ::Aabb::CreateNull(); AZStd::atomic_bool m_terrainBoundsIsValid{ false }; From 6005fdda28ece541ba2b055485e39c255c295e45 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 20 Aug 2021 09:40:22 -0700 Subject: [PATCH 47/54] fixing wwise warns/compilation errors (#3353) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Code/Source/Engine/AudioSystemImpl_wwise.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Gems/AudioEngineWwise/Code/Source/Engine/AudioSystemImpl_wwise.cpp b/Gems/AudioEngineWwise/Code/Source/Engine/AudioSystemImpl_wwise.cpp index 738806a912..9a95f8bfa0 100644 --- a/Gems/AudioEngineWwise/Code/Source/Engine/AudioSystemImpl_wwise.cpp +++ b/Gems/AudioEngineWwise/Code/Source/Engine/AudioSystemImpl_wwise.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -1779,8 +1780,8 @@ namespace Audio AK::MemoryMgr::CategoryStats categoryStats; AK::MemoryMgr::GetCategoryStats(memInfo.m_poolId, categoryStats); - memInfo.m_memoryUsed = categoryStats.uUsed; - memInfo.m_peakUsed = categoryStats.uPeakUsed; + memInfo.m_memoryUsed = static_cast(categoryStats.uUsed); + memInfo.m_peakUsed = static_cast(categoryStats.uPeakUsed); memInfo.m_numAllocs = categoryStats.uAllocs; memInfo.m_numFrees = categoryStats.uFrees; } @@ -1789,9 +1790,9 @@ namespace Audio AK::MemoryMgr::GetGlobalStats(globalStats); auto& memInfo = m_debugMemoryInfo.back(); - memInfo.m_memoryReserved = globalStats.uReserved; - memInfo.m_memoryUsed = globalStats.uUsed; - memInfo.m_peakUsed = globalStats.uMax; + memInfo.m_memoryReserved = static_cast(globalStats.uReserved); + memInfo.m_memoryUsed = static_cast(globalStats.uUsed); + memInfo.m_peakUsed = static_cast(globalStats.uMax); // return the memory infos... return m_debugMemoryInfo; From 992f87b03d64463ed0894dee1f8e944a6587189e Mon Sep 17 00:00:00 2001 From: Artur K <96597+nemerle@users.noreply.github.com> Date: Fri, 20 Aug 2021 18:49:19 +0200 Subject: [PATCH 48/54] Remove `std::bind` usages from Code/Editor (#3358) A few small modernizations as well ( override ) Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> --- .../AzAssetBrowserRequestHandler.cpp | 4 +- .../PropertyMiscCtrl.cpp | 2 +- .../ReflectedPropertyItem.cpp | 4 +- .../test_ModularViewportCameraController.cpp | 2 +- .../test_ViewportManipulatorController.cpp | 10 ++--- Code/Editor/MainWindow.cpp | 2 +- Code/Editor/Objects/BaseObject.cpp | 4 +- Code/Editor/Objects/EntityObject.cpp | 45 ++++++++++--------- .../TrackView/TrackViewKeyPropertiesDlg.cpp | 2 +- 9 files changed, 39 insertions(+), 36 deletions(-) diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp b/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp index cb97632e07..b164323238 100644 --- a/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp +++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp @@ -675,14 +675,14 @@ void AzAssetBrowserRequestHandler::OpenAssetInAssociatedEditor(const AZ::Data::A firstValidOpener = &openerDetails; } // bind a callback such that when the menu item is clicked, it sets that as the opener to use. - menu.addAction(openerDetails.m_iconToUse, QObject::tr(openerDetails.m_displayText.c_str()), mainWindow, AZStd::bind(switchToOpener, &openerDetails)); + menu.addAction(openerDetails.m_iconToUse, QObject::tr(openerDetails.m_displayText.c_str()), mainWindow, [switchToOpener, details = &openerDetails] { return switchToOpener(details); }); } } if (numValidOpeners > 1) // more than one option was added { menu.addSeparator(); - menu.addAction(QObject::tr("Cancel"), AZStd::bind(switchToOpener, nullptr)); // just something to click on to avoid doing anything. + menu.addAction(QObject::tr("Cancel"), [switchToOpener] { return switchToOpener(nullptr); }); // just something to click on to avoid doing anything. menu.exec(QCursor::pos()); } else if (numValidOpeners == 1) diff --git a/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.cpp b/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.cpp index 92c33aefc2..b9f7e12e95 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.cpp @@ -145,7 +145,7 @@ bool UserPopupWidgetHandler::ReadValuesIntoGUI(size_t index, UserPropertyEditor* QWidget* FloatCurveHandler::CreateGUI(QWidget *pParent) { CSplineCtrl *cSpline = new CSplineCtrl(pParent); - cSpline->SetUpdateCallback(AZStd::bind(&FloatCurveHandler::OnSplineChange, this, AZStd::placeholders::_1)); + cSpline->SetUpdateCallback([this](CSplineCtrl* spl) { OnSplineChange(spl); }); cSpline->SetTimeRange(0, 1); cSpline->SetValueRange(0, 1); cSpline->SetGrid(12, 12); diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp index 303f86d270..af418c6e0d 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp @@ -172,8 +172,8 @@ ReflectedPropertyItem::ReflectedPropertyItem(ReflectedPropertyControl *control, if (parent) parent->AddChild(this); - m_onSetCallback = AZStd::bind(&ReflectedPropertyItem::OnVariableChange, this, AZStd::placeholders::_1); - m_onSetEnumCallback = AZStd::bind(&ReflectedPropertyItem::OnVariableEnumChange, this, AZStd::placeholders::_1); + m_onSetCallback = [this](IVariable* var) { OnVariableChange(var); }; + m_onSetEnumCallback = [this](IVariable* var) { OnVariableEnumChange(var); }; } ReflectedPropertyItem::~ReflectedPropertyItem() diff --git a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp index c994458baa..6fcf3faffd 100644 --- a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp +++ b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp @@ -37,7 +37,7 @@ namespace UnitTest m_inputChannelMapper = AZStd::make_unique(m_rootWidget.get(), TestViewportId); } - void TearDown() + void TearDown() override { m_inputChannelMapper.reset(); diff --git a/Code/Editor/Lib/Tests/test_ViewportManipulatorController.cpp b/Code/Editor/Lib/Tests/test_ViewportManipulatorController.cpp index 9dc7e65cef..8c7023634e 100644 --- a/Code/Editor/Lib/Tests/test_ViewportManipulatorController.cpp +++ b/Code/Editor/Lib/Tests/test_ViewportManipulatorController.cpp @@ -24,10 +24,10 @@ namespace UnitTest void Disconnect(); // EditorInteractionSystemViewportSelectionRequestBus overrides ... - void SetHandler(const AzToolsFramework::ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder); - void SetDefaultHandler(); - bool InternalHandleMouseViewportInteraction(const MouseInteractionEvent& mouseInteraction); - bool InternalHandleMouseManipulatorInteraction(const MouseInteractionEvent& mouseInteraction); + void SetHandler(const AzToolsFramework::ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder) override; + void SetDefaultHandler() override; + bool InternalHandleMouseViewportInteraction(const MouseInteractionEvent& mouseInteraction) override; + bool InternalHandleMouseManipulatorInteraction(const MouseInteractionEvent& mouseInteraction) override; AZStd::function m_internalHandleMouseViewportInteraction; AZStd::function m_internalHandleMouseManipulatorInteraction; @@ -92,7 +92,7 @@ namespace UnitTest m_inputChannelMapper = AZStd::make_unique(m_rootWidget.get(), TestViewportId); } - void TearDown() + void TearDown() override { m_inputChannelMapper.reset(); diff --git a/Code/Editor/MainWindow.cpp b/Code/Editor/MainWindow.cpp index fbd8e85482..fa2e792cc8 100644 --- a/Code/Editor/MainWindow.cpp +++ b/Code/Editor/MainWindow.cpp @@ -1767,7 +1767,7 @@ void MainWindow::RegisterOpenWndCommands() cmdUI.tooltip = (QString("Open ") + className).toUtf8().data(); cmdUI.iconFilename = className.toUtf8().data(); GetIEditor()->GetCommandManager()->RegisterUICommand("editor", openCommandName.toUtf8().data(), - "", "", AZStd::bind(&CEditorOpenViewCommand::Execute, pCmd), cmdUI); + "", "", [pCmd] { pCmd->Execute(); }, cmdUI); GetIEditor()->GetCommandManager()->GetUIInfo("editor", openCommandName.toUtf8().data(), cmdUI); } } diff --git a/Code/Editor/Objects/BaseObject.cpp b/Code/Editor/Objects/BaseObject.cpp index 8eb3bb83c1..89e905aa21 100644 --- a/Code/Editor/Objects/BaseObject.cpp +++ b/Code/Editor/Objects/BaseObject.cpp @@ -1515,8 +1515,8 @@ void CBaseObject::Serialize(CObjectArchive& ar) SetFrozen(bFrozen); SetHidden(bHidden); - ar.SetResolveCallback(this, parentId, AZStd::bind(&CBaseObject::ResolveParent, this, AZStd::placeholders::_1 )); - ar.SetResolveCallback(this, lookatId, AZStd::bind(&CBaseObject::SetLookAt, this, AZStd::placeholders::_1)); + ar.SetResolveCallback(this, parentId, [this](CBaseObject* parent) { ResolveParent(parent); }); + ar.SetResolveCallback(this, lookatId, [this](CBaseObject* target) { SetLookAt(target); }); InvalidateTM(0); SetModified(false); diff --git a/Code/Editor/Objects/EntityObject.cpp b/Code/Editor/Objects/EntityObject.cpp index d2a2ae7d18..53c36ccf07 100644 --- a/Code/Editor/Objects/EntityObject.cpp +++ b/Code/Editor/Objects/EntityObject.cpp @@ -230,25 +230,25 @@ CEntityObject::CEntityObject() m_attachmentType = eAT_Pivot; // cache all the variable callbacks, must match order of enum defined in header - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnAreaHeightChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnAreaLightChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnAreaLightSizeChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnAreaWidthChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxHeightChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxLengthChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxProjectionChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxSizeXChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxSizeYChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxSizeZChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxWidthChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnColorChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnInnerRadiusChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnOuterRadiusChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnProjectInAllDirsChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnProjectorFOVChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnProjectorTextureChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnPropertyChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnRadiusChange, this, AZStd::placeholders::_1)); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnAreaHeightChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnAreaLightChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnAreaLightSizeChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnAreaWidthChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxHeightChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxLengthChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxProjectionChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxSizeXChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxSizeYChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxSizeZChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxWidthChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnColorChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnInnerRadiusChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnOuterRadiusChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnProjectInAllDirsChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnProjectorFOVChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnProjectorTextureChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnPropertyChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnRadiusChange(var); }); } CEntityObject::~CEntityObject() @@ -938,11 +938,14 @@ void CEntityObject::Serialize(CObjectArchive& ar) eventTarget->getAttr("TargetId", targetId); eventTarget->getAttr("Event", et.event); eventTarget->getAttr("SourceEvent", et.sourceEvent); - m_eventTargets.push_back(et); + m_eventTargets.emplace_back(AZStd::move(et)); if (targetId != GUID_NULL) { using namespace AZStd::placeholders; - ar.SetResolveCallback(this, targetId, AZStd::bind(&CEntityObject::ResolveEventTarget, this, _1, _2), i); + ar.SetResolveCallback( + this, targetId, + [this](CBaseObject* object, unsigned int index) { ResolveEventTarget(object, index); }, + i); } } } diff --git a/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.cpp b/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.cpp index 6a5c5b6427..2fd46b0fc5 100644 --- a/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.cpp +++ b/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.cpp @@ -110,7 +110,7 @@ void CTrackViewKeyPropertiesDlg::PopulateVariables() m_wndProps->RemoveAllItems(); m_wndProps->AddVarBlock(m_pVarBlock); - m_wndProps->SetUpdateCallback(AZStd::bind(&CTrackViewKeyPropertiesDlg::OnVarChange, this, AZStd::placeholders::_1)); + m_wndProps->SetUpdateCallback([this](IVariable* var) { OnVarChange(var); }); //m_wndProps->m_props.ExpandAll(); From b0fe07158ca9a7a38ab769b97d2bd8387b247dd0 Mon Sep 17 00:00:00 2001 From: amzn-phist <52085794+amzn-phist@users.noreply.github.com> Date: Fri, 20 Aug 2021 12:43:56 -0500 Subject: [PATCH 49/54] Fixes AZ_PROFILE markers that failed release build (#3364) Removes a ToString function that wasn't really needed, it was only defined for release builds, but AZ_PROFILE macros are still defined to something in release. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> --- .../Source/Engine/AudioInternalInterfaces.h | 118 ------------------ .../Code/Source/Engine/AudioSystem.cpp | 6 +- 2 files changed, 3 insertions(+), 121 deletions(-) diff --git a/Gems/AudioSystem/Code/Source/Engine/AudioInternalInterfaces.h b/Gems/AudioSystem/Code/Source/Engine/AudioInternalInterfaces.h index feb1cd8c0f..35d656c337 100644 --- a/Gems/AudioSystem/Code/Source/Engine/AudioInternalInterfaces.h +++ b/Gems/AudioSystem/Code/Source/Engine/AudioInternalInterfaces.h @@ -769,124 +769,6 @@ namespace Audio return (eStatus == eARS_SUCCESS || eStatus == eARS_FAILURE); } -#if !defined(AUDIO_RELEASE) - // Debug Logging Helper - AZStd::string ToString() - { - static const AZStd::unordered_map managerRequests - { - { eAMRT_INIT_AUDIO_IMPL, "INIT IMPL" }, - { eAMRT_RELEASE_AUDIO_IMPL, "RELEASE IMPL" }, - { eAMRT_RESERVE_AUDIO_OBJECT_ID, "RESERVE OBJECT ID" }, - { eAMRT_CREATE_SOURCE, "CREATE SOURCE" }, - { eAMRT_DESTROY_SOURCE, "DESTROY SOURCE" }, - { eAMRT_PARSE_CONTROLS_DATA, "PARSE CONTROLS" }, - { eAMRT_PARSE_PRELOADS_DATA, "PARSE PRELOADS" }, - { eAMRT_CLEAR_CONTROLS_DATA, "CLEAR CONTROLS" }, - { eAMRT_CLEAR_PRELOADS_DATA, "CLEAR PRELOADS" }, - { eAMRT_PRELOAD_SINGLE_REQUEST, "PRELOAD SINGLE" }, - { eAMRT_UNLOAD_SINGLE_REQUEST, "UNLOAD SINGLE" }, - { eAMRT_UNLOAD_AFCM_DATA_BY_SCOPE, "UNLOAD SCOPE" }, - { eAMRT_REFRESH_AUDIO_SYSTEM, "REFRESH AUDIO SYSTEM" }, - { eAMRT_LOSE_FOCUS, "LOSE FOCUS" }, - { eAMRT_GET_FOCUS, "GET FOCUS" }, - { eAMRT_MUTE_ALL, "MUTE" }, - { eAMRT_UNMUTE_ALL, "UNMUTE" }, - { eAMRT_STOP_ALL_SOUNDS, "STOP ALL" }, - { eAMRT_DRAW_DEBUG_INFO, "DRAW DEBUG" }, - { eAMRT_CHANGE_LANGUAGE, "CHANGE LANGUAGE" }, - { eAMRT_SET_AUDIO_PANNING_MODE, "SET PANNING MODE" }, - }; - static const AZStd::unordered_map callbackRequests - { - { eACMRT_REPORT_STARTED_EVENT, "STARTED EVENT" }, - { eACMRT_REPORT_FINISHED_EVENT, "FINISHED EVENT" }, - { eACMRT_REPORT_FINISHED_TRIGGER_INSTANCE, "FINISHED TRIGGER INSTANCE" }, - }; - static const AZStd::unordered_map listenerRequests - { - { eALRT_SET_POSITION, "SET POSITION" }, - }; - static const AZStd::unordered_map objectRequests - { - { eAORT_PREPARE_TRIGGER, "PREPARE TRIGGER" }, - { eAORT_UNPREPARE_TRIGGER, "UNPREPARE TRIGGER" }, - { eAORT_EXECUTE_TRIGGER, "EXECUTE TRIGGER" }, - { eAORT_STOP_TRIGGER, "STOP TRIGGER" }, - { eAORT_STOP_ALL_TRIGGERS, "STOP ALL" }, - { eAORT_SET_POSITION, "SET POSITION" }, - { eAORT_SET_RTPC_VALUE, "SET RTPC" }, - { eAORT_SET_SWITCH_STATE, "SET SWITCH" }, - { eAORT_SET_ENVIRONMENT_AMOUNT, "SET ENV AMOUNT" }, - { eAORT_RESET_ENVIRONMENTS, "RESET ENVS" }, - { eAORT_RESET_RTPCS, "RESET RTPCS" }, - { eAORT_RELEASE_OBJECT, "RELEASE OBJECT" }, - { eAORT_EXECUTE_SOURCE_TRIGGER, "EXECUTE SOURCE TRIGGER" }, - { eAORT_SET_MULTI_POSITIONS, "SET MULTI POSITIONS" }, - }; - - std::stringstream ss; - - ss << "AudioRequest("; - - if (pData->eRequestType == eART_AUDIO_MANAGER_REQUEST) - { - ss << "AUDIO MANAGER : "; - auto requestStr = managerRequests.at(static_cast(pData.get())->eType); - ss << requestStr.c_str(); - } - - if (pData->eRequestType == eART_AUDIO_CALLBACK_MANAGER_REQUEST) - { - ss << "AUDIO CALLBACK MGR : "; - auto requestStr = callbackRequests.at(static_cast(pData.get())->eType); - ss << requestStr.c_str(); - } - - if (pData->eRequestType == eART_AUDIO_LISTENER_REQUEST) - { - ss << "AUDIO LISTENER : "; - auto requestStr = listenerRequests.at(static_cast(pData.get())->eType); - ss << requestStr.c_str(); - } - if (pData->eRequestType == eART_AUDIO_OBJECT_REQUEST) - { - ss << "AUDIO OBJECT : "; - auto requestStr = objectRequests.at(static_cast(pData.get())->eType); - ss << requestStr.c_str(); - } - - ss << "): ["; - if (nFlags & eARF_PRIORITY_NORMAL) - { - ss << "PRIORITY NORMAL, "; - } - if (nFlags & eARF_PRIORITY_HIGH) - { - ss << "PRIORITY HIGH, "; - } - if (nFlags & eARF_EXECUTE_BLOCKING) - { - ss << "EXECUTE BLOCKING, "; - } - if (nFlags & eARF_SYNC_CALLBACK) - { - ss << "SYNC CALLBACK, "; - } - if (nFlags & eARF_SYNC_FINISHED_CALLBACK) - { - ss << "SYNC FINISHED CALLBACK, "; - } - if (nFlags & eARF_THREAD_SAFE_PUSH) - { - ss << "THREAD SAFE PUSH, "; - } - ss << "]"; - - return AZStd::string(ss.str().c_str()); - } -#endif // !AUDIO_RELEASE - TATLEnumFlagsType nFlags; TAudioObjectID nAudioObjectID; void* pOwner; diff --git a/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp b/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp index 43ab47266a..af1dfedfaa 100644 --- a/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp +++ b/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp @@ -616,7 +616,7 @@ namespace Audio void CAudioSystem::ProcessRequestThreadSafe(CAudioRequestInternal request) { // Audio Thread! - AZ_PROFILE_SCOPE(Audio, "Thread-Safe Request: %s", request.ToString().c_str()); + AZ_PROFILE_SCOPE(Audio, "Process Thread-Safe Request"); if (m_oATL.CanProcessRequests()) { @@ -641,7 +641,7 @@ namespace Audio { // Todo: This should handle request priority, use request priority as bus Address and process in priority order. - AZ_PROFILE_SCOPE(Audio, "Normal Request: %s", request.ToString().c_str()); + AZ_PROFILE_SCOPE(Audio, "Process Normal Request"); AZ_Assert(g_mainThreadId != AZStd::this_thread::get_id(), "AudioSystem::ProcessRequestByPriority - called from Main thread!"); @@ -672,7 +672,7 @@ namespace Audio { if (!(request.nInternalInfoFlags & eARIF_WAITING_FOR_REMOVAL)) { - AZ_PROFILE_SCOPE(Audio, "Blocking Request: %s", request.ToString().c_str()); + AZ_PROFILE_SCOPE(Audio, "Process Blocking Request"); if (request.eStatus == eARS_NONE) { From aa68122002cbb693b487917daa5a0b64643a07b3 Mon Sep 17 00:00:00 2001 From: moudgils <47460854+moudgils@users.noreply.github.com> Date: Fri, 20 Aug 2021 10:58:40 -0700 Subject: [PATCH 50/54] Atom starter game ios fixes (#3297) * Various fixes for AtomStarterGame on ios - Use low end pipeline on ioos by default for BoootStrapComponent - Track the need to bind null heap within Argument buffers - Only bind the null heap if its needed - Track its usage for Vertex/Fragment stages - Increase null dummy buffer to 1K to address GPU crash oon thee first frame Signed-off-by: moudgils --- Gems/Atom/Bootstrap/Code/CMakeLists.txt | 5 ++++ .../Code/Source/BootstrapSystemComponent.cpp | 19 ++++++++------ .../Code/Source/BootstrapSystemComponent.h | 5 +--- ...BootstrapSystemComponent_Traits_Platform.h | 9 +++++++ .../Android/bootstrap_android_files.cmake | 12 +++++++++ ...BootstrapSystemComponent_Traits_Platform.h | 9 +++++++ .../Linux/bootstrap_linux_files.cmake | 12 +++++++++ ...BootstrapSystemComponent_Traits_Platform.h | 9 +++++++ .../Platform/Mac/bootstrap_mac_files.cmake | 12 +++++++++ ...BootstrapSystemComponent_Traits_Platform.h | 9 +++++++ .../Windows/bootstrap_windows_files.cmake | 12 +++++++++ ...BootstrapSystemComponent_Traits_Platform.h | 9 +++++++ .../Platform/iOS/bootstrap_ios_files.cmake | 12 +++++++++ .../Passes/LowEndRenderPipeline.azasset | 15 +++++++++++ .../Metal/Code/Source/RHI/ArgumentBuffer.cpp | 26 +++++++++++++++++++ .../Metal/Code/Source/RHI/ArgumentBuffer.h | 3 +++ .../RHI/Metal/Code/Source/RHI/CommandList.cpp | 19 +++++++++++--- .../Metal/Code/Source/RHI/CommandListBase.cpp | 25 +++++++++++------- .../Metal/Code/Source/RHI/CommandListBase.h | 6 +++-- .../Code/Source/RHI/NullDescriptorManager.cpp | 4 +-- .../Code/Source/RHI/ShaderResourceGroup.cpp | 5 ++++ .../Code/Source/RHI/ShaderResourceGroup.h | 3 ++- 22 files changed, 210 insertions(+), 30 deletions(-) create mode 100644 Gems/Atom/Bootstrap/Code/Source/Platform/Android/BootstrapSystemComponent_Traits_Platform.h create mode 100644 Gems/Atom/Bootstrap/Code/Source/Platform/Android/bootstrap_android_files.cmake create mode 100644 Gems/Atom/Bootstrap/Code/Source/Platform/Linux/BootstrapSystemComponent_Traits_Platform.h create mode 100644 Gems/Atom/Bootstrap/Code/Source/Platform/Linux/bootstrap_linux_files.cmake create mode 100644 Gems/Atom/Bootstrap/Code/Source/Platform/Mac/BootstrapSystemComponent_Traits_Platform.h create mode 100644 Gems/Atom/Bootstrap/Code/Source/Platform/Mac/bootstrap_mac_files.cmake create mode 100644 Gems/Atom/Bootstrap/Code/Source/Platform/Windows/BootstrapSystemComponent_Traits_Platform.h create mode 100644 Gems/Atom/Bootstrap/Code/Source/Platform/Windows/bootstrap_windows_files.cmake create mode 100644 Gems/Atom/Bootstrap/Code/Source/Platform/iOS/BootstrapSystemComponent_Traits_Platform.h create mode 100644 Gems/Atom/Bootstrap/Code/Source/Platform/iOS/bootstrap_ios_files.cmake create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/LowEndRenderPipeline.azasset diff --git a/Gems/Atom/Bootstrap/Code/CMakeLists.txt b/Gems/Atom/Bootstrap/Code/CMakeLists.txt index af09f3a288..1787af04ed 100644 --- a/Gems/Atom/Bootstrap/Code/CMakeLists.txt +++ b/Gems/Atom/Bootstrap/Code/CMakeLists.txt @@ -6,6 +6,8 @@ # # +ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) + ly_add_target( NAME Atom_Bootstrap.Headers HEADERONLY NAMESPACE Gem @@ -21,9 +23,12 @@ ly_add_target( NAMESPACE Gem FILES_CMAKE bootstrap_files.cmake + ${pal_dir}/bootstrap_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + PLATFORM_INCLUDE_FILES INCLUDE_DIRECTORIES PRIVATE Source + ${pal_dir} PUBLIC Include BUILD_DEPENDENCIES diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp index f9d6ac63f7..11758138e0 100644 --- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp +++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp @@ -38,6 +38,10 @@ #include #include +#include +#include + +AZ_CVAR(AZ::CVarFixedString, r_default_pipeline_name, AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Default Render pipeline name"); namespace AZ { @@ -50,8 +54,7 @@ namespace AZ if (SerializeContext* serialize = azrtti_cast(context)) { serialize->Class() - ->Version(0) - ->Field("DefaultRenderPipelineAssetFile", &BootstrapSystemComponent::m_defaultPipelineAssetPath) + ->Version(1) ; if (EditContext* ec = serialize->GetEditContext()) @@ -60,8 +63,6 @@ namespace AZ ->ClassElement(Edit::ClassElements::EditorData, "") ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b)) ->Attribute(Edit::Attributes::AutoExpand, true) - ->DataElement(Edit::UIHandlers::Default, &BootstrapSystemComponent::m_defaultPipelineAssetPath, "Default RenderPipeline Asset", - "The asset file path of default render pipeline for default window") ; } } @@ -314,13 +315,15 @@ namespace AZ // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene. // When running with no Asset Processor (for example in release), CompileAssetSync will return AssetStatus_Unknown. AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown; - AzFramework::AssetSystemRequestBus::BroadcastResult( - status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, m_defaultPipelineAssetPath); - AZ_Assert(status == AzFramework::AssetSystem::AssetStatus_Compiled || status == AzFramework::AssetSystem::AssetStatus_Unknown, "Could not compile the default render pipeline at '%s'", m_defaultPipelineAssetPath.c_str()); + const AZ::CVarFixedString pipelineName = static_cast(r_default_pipeline_name); + AzFramework::AssetSystemRequestBus::BroadcastResult(status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, pipelineName.data()); + + AZ_Assert(status == AzFramework::AssetSystem::AssetStatus_Compiled || status == AzFramework::AssetSystem::AssetStatus_Unknown, "Could not compile the default render pipeline at '%s'", pipelineName.c_str()); - Data::Asset pipelineAsset = RPI::AssetUtils::LoadAssetByProductPath(m_defaultPipelineAssetPath.c_str(), RPI::AssetUtils::TraceLevel::Error); + Data::Asset pipelineAsset = RPI::AssetUtils::LoadAssetByProductPath(pipelineName.data(), RPI::AssetUtils::TraceLevel::Error); RPI::RenderPipelineDescriptor renderPipelineDescriptor = *RPI::GetDataFromAnyAsset(pipelineAsset); renderPipelineDescriptor.m_name = AZStd::string::format("%s_%i", renderPipelineDescriptor.m_name.c_str(), viewportContext->GetId()); + if (!scene->GetRenderPipeline(AZ::Name(renderPipelineDescriptor.m_name))) { RPI::RenderPipelinePtr renderPipeline = RPI::RenderPipeline::CreateRenderPipelineForWindow(renderPipelineDescriptor, *viewportContext->GetWindowContext().get()); diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h index 142b2d8769..bd5d417b8f 100644 --- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h +++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h @@ -112,10 +112,7 @@ namespace AZ // The id of the render pipeline created by this component RPI::RenderPipelineId m_renderPipelineId; - - // Variables which are system component configuration - AZStd::string m_defaultPipelineAssetPath = "passes/MainRenderPipeline.azasset"; - + // Save a reference to the image created by the BRDF pipeline so it doesn't get auto deleted if it's ref count goes to zero // For example, if we delete all the passes, we won't have to recreate the BRDF pipeline to recreate the BRDF texture Data::Instance m_brdfTexture; diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Android/BootstrapSystemComponent_Traits_Platform.h b/Gems/Atom/Bootstrap/Code/Source/Platform/Android/BootstrapSystemComponent_Traits_Platform.h new file mode 100644 index 0000000000..da63106e29 --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Android/BootstrapSystemComponent_Traits_Platform.h @@ -0,0 +1,9 @@ +/* + * 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. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/LowEndRenderPipeline.azasset" diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Android/bootstrap_android_files.cmake b/Gems/Atom/Bootstrap/Code/Source/Platform/Android/bootstrap_android_files.cmake new file mode 100644 index 0000000000..bae11b561e --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Android/bootstrap_android_files.cmake @@ -0,0 +1,12 @@ +# +# 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. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + BootstrapSystemComponent_Traits_Platform.h +) + diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Linux/BootstrapSystemComponent_Traits_Platform.h b/Gems/Atom/Bootstrap/Code/Source/Platform/Linux/BootstrapSystemComponent_Traits_Platform.h new file mode 100644 index 0000000000..d467de5e53 --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Linux/BootstrapSystemComponent_Traits_Platform.h @@ -0,0 +1,9 @@ +/* + * 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. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/MainRenderPipeline.azasset" diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Linux/bootstrap_linux_files.cmake b/Gems/Atom/Bootstrap/Code/Source/Platform/Linux/bootstrap_linux_files.cmake new file mode 100644 index 0000000000..bae11b561e --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Linux/bootstrap_linux_files.cmake @@ -0,0 +1,12 @@ +# +# 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. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + BootstrapSystemComponent_Traits_Platform.h +) + diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Mac/BootstrapSystemComponent_Traits_Platform.h b/Gems/Atom/Bootstrap/Code/Source/Platform/Mac/BootstrapSystemComponent_Traits_Platform.h new file mode 100644 index 0000000000..d467de5e53 --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Mac/BootstrapSystemComponent_Traits_Platform.h @@ -0,0 +1,9 @@ +/* + * 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. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/MainRenderPipeline.azasset" diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Mac/bootstrap_mac_files.cmake b/Gems/Atom/Bootstrap/Code/Source/Platform/Mac/bootstrap_mac_files.cmake new file mode 100644 index 0000000000..bae11b561e --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Mac/bootstrap_mac_files.cmake @@ -0,0 +1,12 @@ +# +# 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. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + BootstrapSystemComponent_Traits_Platform.h +) + diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Windows/BootstrapSystemComponent_Traits_Platform.h b/Gems/Atom/Bootstrap/Code/Source/Platform/Windows/BootstrapSystemComponent_Traits_Platform.h new file mode 100644 index 0000000000..d467de5e53 --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Windows/BootstrapSystemComponent_Traits_Platform.h @@ -0,0 +1,9 @@ +/* + * 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. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/MainRenderPipeline.azasset" diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Windows/bootstrap_windows_files.cmake b/Gems/Atom/Bootstrap/Code/Source/Platform/Windows/bootstrap_windows_files.cmake new file mode 100644 index 0000000000..bae11b561e --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Windows/bootstrap_windows_files.cmake @@ -0,0 +1,12 @@ +# +# 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. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + BootstrapSystemComponent_Traits_Platform.h +) + diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/iOS/BootstrapSystemComponent_Traits_Platform.h b/Gems/Atom/Bootstrap/Code/Source/Platform/iOS/BootstrapSystemComponent_Traits_Platform.h new file mode 100644 index 0000000000..da63106e29 --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/iOS/BootstrapSystemComponent_Traits_Platform.h @@ -0,0 +1,9 @@ +/* + * 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. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/LowEndRenderPipeline.azasset" diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/iOS/bootstrap_ios_files.cmake b/Gems/Atom/Bootstrap/Code/Source/Platform/iOS/bootstrap_ios_files.cmake new file mode 100644 index 0000000000..bae11b561e --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/iOS/bootstrap_ios_files.cmake @@ -0,0 +1,12 @@ +# +# 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. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + BootstrapSystemComponent_Traits_Platform.h +) + diff --git a/Gems/Atom/Feature/Common/Assets/Passes/LowEndRenderPipeline.azasset b/Gems/Atom/Feature/Common/Assets/Passes/LowEndRenderPipeline.azasset new file mode 100644 index 0000000000..fd0c9bd0ed --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/LowEndRenderPipeline.azasset @@ -0,0 +1,15 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "RenderPipelineDescriptor", + "ClassData": { + "Name": "LowEndPipeline", + "MainViewTag": "MainCamera", + "RootPassTemplate": "LowEndPipelineTemplate", + "RenderSettings": { + "MultisampleState": { + "samples": 1 + } + } + } +} diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp index 383c5e5a79..05107128ad 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp @@ -204,6 +204,7 @@ namespace AZ { RHI::Ptr nullMtlImagePtr = m_device->GetNullDescriptorManager().GetNullImage(shaderInputImage.m_type).GetMemory(); mtlTextures[imageArrayLen] = nullMtlImagePtr->GetGpuAddress>(); + m_useNullDescriptorHeap = true; } imageArrayLen++; } @@ -282,12 +283,16 @@ namespace AZ { RHI::Ptr nullMtlBufferMemPtr = nullDescriptorManager.GetNullImageBuffer().GetMemory(); mtlTextures[bufferArrayLen] = nullMtlBufferMemPtr->GetGpuAddress>(); + m_useNullDescriptorHeap = true; } else { RHI::Ptr nullMtlBufferMemPtr = nullDescriptorManager.GetNullBuffer().GetMemory(); mtlBuffers[bufferArrayLen] = nullMtlBufferMemPtr->GetGpuAddress>(); mtlBufferOffsets[bufferArrayLen] = nullDescriptorManager.GetNullBuffer().GetOffset(); + m_resourceBindings[shaderInputBuffer.m_name].insert( + ResourceBindingData{nullMtlBufferMemPtr, .m_bufferAccess = shaderInputBuffer.m_access} + ); } } @@ -499,5 +504,26 @@ namespace AZ resourcesToMakeResidentMap[key].emplace(mtlResourceToBind); } } + + bool ArgumentBuffer::IsNullHeapNeededForVertexStage(const ShaderResourceGroupVisibility& srgResourcesVisInfo) const + { + bool isUsedByVertexStage = false; + + //Iterate over all the SRG entries + for (const auto& it : srgResourcesVisInfo.m_resourcesStageMask) + { + //Only the ones not added to m_resourceBindings would require null heap + if( m_resourceBindings.find(it.first) == m_resourceBindings.end()) + { + isUsedByVertexStage |= RHI::CheckBitsAny(it.second, RHI::ShaderStageMask::Vertex); + } + } + return isUsedByVertexStage; + } + + bool ArgumentBuffer::IsNullDescHeapNeeded() const + { + return m_useNullDescriptorHeap; + } } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h index cf229aeb75..a680516dc6 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h @@ -104,6 +104,8 @@ namespace AZ GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentGraphics) const; void ClearResourceTracking(); + bool IsNullHeapNeededForVertexStage(const ShaderResourceGroupVisibility& srgResourcesVisInfo) const; + bool IsNullDescHeapNeeded() const; ////////////////////////////////////////////////////////////////////////// // RHI::DeviceObject @@ -153,6 +155,7 @@ namespace AZ MemoryView m_argumentBuffer; MemoryView m_constantBuffer; #endif + bool m_useNullDescriptorHeap = false; }; } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp index 2614addfe3..3c45e69d8b 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp @@ -245,6 +245,8 @@ namespace AZ bool CommandList::SetArgumentBuffers(const PipelineState* pipelineState, RHI::PipelineStateType stateType) { + bool bindNullDescriptorHeap = false; + MTLRenderStages mtlRenderStagesForNullDescHeap = 0; ShaderResourceBindings& bindings = GetShaderResourceBindingsByPipelineType(stateType); const PipelineLayout& pipelineLayout = pipelineState->GetPipelineLayout(); @@ -280,7 +282,8 @@ namespace AZ uint32_t srgVisIndex = pipelineLayout.GetIndexBySlot(shaderResourceGroup->GetBindingSlot()); const RHI::ShaderStageMask& srgVisInfo = pipelineLayout.GetSrgVisibility(srgVisIndex); - + const ShaderResourceGroupVisibility& srgResourcesVisInfo = pipelineLayout.GetSrgResourcesVisibility(srgVisIndex); + bool isSrgUpdatd = bindings.m_srgsByIndex[slot] != shaderResourceGroup; if(isSrgUpdatd) { @@ -291,6 +294,9 @@ namespace AZ if(srgVisInfo != RHI::ShaderStageMask::None) { + bool isNullDescHeapNeeded = compiledArgBuffer.IsNullDescHeapNeeded(); + bindNullDescriptorHeap |= isNullDescHeapNeeded; + //For graphics and compute shader stages, cache all the argument buffers, offsets and track the min/max indices if(m_commandEncoderType == CommandEncoderType::Render) { @@ -300,7 +306,9 @@ namespace AZ mtlVertexArgBuffers[slotIndex] = argBuffer; mtlVertexArgBufferOffsets[slotIndex] = argBufferOffset; bufferVertexRegisterIdMin = AZStd::min(slotIndex, bufferVertexRegisterIdMin); - bufferVertexRegisterIdMax = AZStd::max(slotIndex, bufferVertexRegisterIdMax); + bufferVertexRegisterIdMax = AZStd::max(slotIndex, bufferVertexRegisterIdMax); + mtlRenderStagesForNullDescHeap = shaderResourceGroup->IsNullHeapNeededForVertexStage(srgResourcesVisInfo) ? + mtlRenderStagesForNullDescHeap | MTLRenderStageVertex : mtlRenderStagesForNullDescHeap; } if( numBitsSet > 1 || srgVisInfo == RHI::ShaderStageMask::Fragment) @@ -309,6 +317,7 @@ namespace AZ mtlFragmentOrComputeArgBufferOffsets[slotIndex] = argBufferOffset; bufferFragmentOrComputeRegisterIdMin = AZStd::min(slotIndex, bufferFragmentOrComputeRegisterIdMin); bufferFragmentOrComputeRegisterIdMax = AZStd::max(slotIndex, bufferFragmentOrComputeRegisterIdMax); + mtlRenderStagesForNullDescHeap = isNullDescHeapNeeded ? mtlRenderStagesForNullDescHeap | MTLRenderStageFragment : mtlRenderStagesForNullDescHeap; } } else if(m_commandEncoderType == CommandEncoderType::Compute) @@ -329,7 +338,7 @@ namespace AZ bindings.m_srgVisHashByIndex[slot] = srgResourcesVisHash; if(srgVisInfo != RHI::ShaderStageMask::None) { - const ShaderResourceGroupVisibility& srgResourcesVisInfo = pipelineLayout.GetSrgResourcesVisibility(srgVisIndex); + //For graphics and compute encoder make the resource resident (call UseResource) for the duration //of the work associated with the current scope and ensure that it's in a @@ -396,6 +405,10 @@ namespace AZ stages: key.first.second]; } + if(bindNullDescriptorHeap) + { + MakeHeapsResident(mtlRenderStagesForNullDescHeap); + } return true; } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.cpp index b3dd209926..e386c25515 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.cpp @@ -64,6 +64,7 @@ namespace AZ { [m_encoder endEncoding]; m_encoder = nil; + m_isNullDescHeapBound = false; #if AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING if (m_supportsInterDrawTimestamps) { @@ -73,18 +74,25 @@ namespace AZ } } - void CommandListBase::MakeHeapsResident() + void CommandListBase::MakeHeapsResident(MTLRenderStages renderStages) { + if(m_isNullDescHeapBound) + { + return; + } + switch(m_commandEncoderType) { case CommandEncoderType::Render: { - id renderEncoder = GetEncoder>(); - for (id residentHeap : *m_residentHeaps) + if(renderStages != 0) { - //MTLRenderStageVertex is not added to this as it was causing an immediate gpu crash on ios (first buffer commit) - [renderEncoder useHeap : residentHeap - stages : MTLRenderStageFragment]; + id renderEncoder = GetEncoder>(); + for (id residentHeap : *m_residentHeaps) + { + [renderEncoder useHeap : residentHeap + stages : renderStages]; + } } break; } @@ -102,6 +110,7 @@ namespace AZ AZ_Assert(false, "Encoder Type not supported"); } } + m_isNullDescHeapBound = true; } void CommandListBase::CreateEncoder(CommandEncoderType encoderType) @@ -119,16 +128,12 @@ namespace AZ m_commandEncoderType = CommandEncoderType::Render; m_encoder = [m_mtlCommandBuffer renderCommandEncoderWithDescriptor : m_renderPassDescriptor]; m_renderPassDescriptor = nil; - MakeHeapsResident(); - break; } case CommandEncoderType::Compute: { m_commandEncoderType = CommandEncoderType::Compute; m_encoder = [m_mtlCommandBuffer computeCommandEncoder]; - MakeHeapsResident(); - break; } case CommandEncoderType::Blit: diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.h index b2c548c9c5..2f8905d61c 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.h @@ -89,12 +89,14 @@ namespace AZ /// Cache multisample state. Used mainly to validate the MSAA image descriptor against the one passed into the pipelinestate RHI::MultisampleState m_renderPassMultiSampleState; + //! Go through all the heaps and call UseHeap on them to make them resident for the upcoming pass. + void MakeHeapsResident(MTLRenderStages renderStages); private: - //! Go through all the heaps and call UseHeap on them to make them resident for the upcoming pass. - void MakeHeapsResident(); + bool m_isEncoded = false; + bool m_isNullDescHeapBound = false; RHI::HardwareQueueClass m_hardwareQueueClass = RHI::HardwareQueueClass::Graphics; NSString* m_encoderScopeName = nullptr; id m_mtlCommandBuffer = nil; diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/NullDescriptorManager.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/NullDescriptorManager.cpp index 5288ec8e5a..e86ba3c2c3 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/NullDescriptorManager.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/NullDescriptorManager.cpp @@ -126,10 +126,10 @@ namespace AZ Device& device = static_cast(GetDevice()); m_nullBuffer.m_name = "NULL_DESCRIPTOR_BUFFER"; - m_nullBuffer.m_bufferDescriptor.m_byteCount = 64; + m_nullBuffer.m_bufferDescriptor.m_byteCount = 1024; m_nullBuffer.m_bufferDescriptor.m_bindFlags = RHI::BufferBindFlags::ShaderWrite; m_nullBuffer.m_memoryView = device.CreateBufferCommitted(m_nullBuffer.m_bufferDescriptor); - + m_nullBuffer.m_memoryView.SetName( m_nullBuffer.m_name.c_str()); if(!m_nullBuffer.m_memoryView.IsValid()) { AZ_Assert(false, "Couldnt create a null buffer for ArgumentTable"); diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.cpp index 9c4e13f713..1cba62b988 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.cpp @@ -36,5 +36,10 @@ namespace AZ { GetCompiledArgumentBuffer().CollectUntrackedResources(commandEncoder, srgResourcesVisInfo, resourcesToMakeResidentCompute, resourcesToMakeResidentGraphics); } + + bool ShaderResourceGroup::IsNullHeapNeededForVertexStage(const ShaderResourceGroupVisibility& srgResourcesVisInfo) const + { + return GetCompiledArgumentBuffer().IsNullHeapNeededForVertexStage(srgResourcesVisInfo); + } } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.h index 52ffabe106..cb69c0975e 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.h @@ -47,7 +47,8 @@ namespace AZ const ShaderResourceGroupVisibility& srgResourcesVisInfo, ArgumentBuffer::ComputeResourcesToMakeResidentMap& resourcesToMakeResidentCompute, ArgumentBuffer::GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentGraphics) const; - + bool IsNullHeapNeededForVertexStage(const ShaderResourceGroupVisibility& srgResourcesVisInfo) const; + private: ShaderResourceGroup() = default; From b406129fd2128ed8a792132061f887c66505b9ae Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 20 Aug 2021 11:41:46 -0700 Subject: [PATCH 51/54] Another warning fixes Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Gems/BarrierInput/Code/Source/BarrierInputKeyboard.cpp | 2 +- Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Gems/BarrierInput/Code/Source/BarrierInputKeyboard.cpp b/Gems/BarrierInput/Code/Source/BarrierInputKeyboard.cpp index 5e486df680..93c485a790 100644 --- a/Gems/BarrierInput/Code/Source/BarrierInputKeyboard.cpp +++ b/Gems/BarrierInput/Code/Source/BarrierInputKeyboard.cpp @@ -147,7 +147,7 @@ namespace BarrierInput { inputChannelId = InputChannelIdByScanCodeTable[scanCode]; } - else if (0 <= (scanCode - 0x100) && scanCode < InputChannelIdByScanCodeWithExtendedPrefixTable.size()) + else if (0x100 <= scanCode && scanCode < InputChannelIdByScanCodeWithExtendedPrefixTable.size()) { inputChannelId = InputChannelIdByScanCodeWithExtendedPrefixTable[scanCode - 0x100]; } diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index 1ddb5d9d65..079cac329b 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -1254,10 +1254,12 @@ namespace {{ Component.attrib['Namespace'] }} bool {{ RecordName }}::CanAttachRecord(Multiplayer::ReplicationRecord& replicationRecord) { bool canAttach{ true }; + AZ_PUSH_DISABLE_WARNING(4296, "-Wunknown-warning-option") // expression is always true canAttach &= replicationRecord.ContainsAuthorityToClientBits() ? (replicationRecord.GetRemainingAuthorityToClientBits() >= static_cast({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Client') }}::Count)) : true; canAttach &= replicationRecord.ContainsAuthorityToServerBits() ? (replicationRecord.GetRemainingAuthorityToServerBits() >= static_cast({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Server') }}::Count)) : true; canAttach &= replicationRecord.ContainsAuthorityToAutonomousBits() ? (replicationRecord.GetRemainingAuthorityToAutonomousBits() >= static_cast({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Autonomous') }}::Count)) : true; canAttach &= replicationRecord.ContainsAutonomousToAuthorityBits() ? (replicationRecord.GetRemainingAutonomousToAuthorityBits() >= static_cast({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Autonomous', 'Authority') }}::Count)) : true; + AZ_POP_DISABLE_WARNING return canAttach; } From b2b68863381cadb50ad82b64442c89e1ca15cbb0 Mon Sep 17 00:00:00 2001 From: moudgils <47460854+moudgils@users.noreply.github.com> Date: Fri, 20 Aug 2021 13:31:35 -0700 Subject: [PATCH 52/54] Fixes asserts related to buffer allocation using null rhi (#3367) Fixes GPU crashes when releasing Indirect draw and query related dx12 objects Fixes imgui profiler related to viewing buffer allocations Signed-off-by: moudgils --- .../Source/CoreLights/CapsuleLightFeatureProcessor.cpp | 3 +-- .../Common/Code/Source/Decals/DecalFeatureProcessor.cpp | 3 +-- .../Source/Decals/DecalTextureArrayFeatureProcessor.cpp | 3 +-- Gems/Atom/RHI/Code/Include/Atom/RHI/BufferPool.h | 3 +++ Gems/Atom/RHI/Code/Source/RHI/BufferPool.cpp | 7 ++++++- Gems/Atom/RHI/Code/Source/RHI/BufferPoolBase.cpp | 2 +- .../RHI/DX12/Code/Source/RHI/IndirectBufferSignature.cpp | 2 ++ Gems/Atom/RHI/DX12/Code/Source/RHI/QueryPool.cpp | 9 +++++++++ Gems/Atom/RHI/DX12/Code/Source/RHI/QueryPool.h | 1 + Gems/Atom/RHI/Null/Code/Source/RHI/BufferPool.h | 3 ++- Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/Buffer.cpp | 8 +------- .../RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp | 1 + .../Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl | 5 +++-- 13 files changed, 32 insertions(+), 18 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.cpp index b75f0481ec..683295cf5b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.cpp @@ -107,8 +107,7 @@ namespace AZ if (m_deviceBufferNeedsUpdate) { - [[maybe_unused]] bool success = m_lightBufferHandler.UpdateBuffer(m_capsuleLightData.GetDataVector()); - AZ_Error(FeatureProcessorName, success, "Unable to update buffer during Simulate()."); + m_lightBufferHandler.UpdateBuffer(m_capsuleLightData.GetDataVector()); m_deviceBufferNeedsUpdate = false; } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp index b03d456505..4954ffc01c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp @@ -112,8 +112,7 @@ namespace AZ if (m_deviceBufferNeedsUpdate) { - [[maybe_unused]] bool success = m_decalBufferHandler.UpdateBuffer(m_decalData.GetDataVector<0>()); - AZ_Error(FeatureProcessorName, success, "Unable to update buffer during Simulate()."); + m_decalBufferHandler.UpdateBuffer(m_decalData.GetDataVector<0>()); m_deviceBufferNeedsUpdate = false; } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp index 10dab85dcb..4ecfd7fc09 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp @@ -150,8 +150,7 @@ namespace AZ if (m_deviceBufferNeedsUpdate) { - [[maybe_unused]] bool success = m_decalBufferHandler.UpdateBuffer(m_decalData.GetDataVector()); - AZ_Error(FeatureProcessorName, success, "Unable to update buffer during Simulate()."); + m_decalBufferHandler.UpdateBuffer(m_decalData.GetDataVector()); m_deviceBufferNeedsUpdate = false; } } diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/BufferPool.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/BufferPool.h index abbd316bc7..2d226407c7 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/BufferPool.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/BufferPool.h @@ -223,6 +223,9 @@ namespace AZ /// Called when a buffer is being streamed asynchronously. virtual ResultCode StreamBufferInternal(const BufferStreamRequest& request); + //Called in order to do a simple mem copy allowing Null rhi to opt out + virtual void BufferCopy(void* destination, const void* source, size_t num); + ////////////////////////////////////////////////////////////////////////// BufferPoolDescriptor m_descriptor; diff --git a/Gems/Atom/RHI/Code/Source/RHI/BufferPool.cpp b/Gems/Atom/RHI/Code/Source/RHI/BufferPool.cpp index 3c0359bf8a..9849db254e 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/BufferPool.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/BufferPool.cpp @@ -143,7 +143,7 @@ namespace AZ resultCode = MapBufferInternal(mapRequest, mapResponse); if (resultCode == ResultCode::Success) { - memcpy(mapResponse.m_data, initRequest.m_initialData, initRequest.m_descriptor.m_byteCount); + BufferCopy(mapResponse.m_data, initRequest.m_initialData, initRequest.m_descriptor.m_byteCount); UnmapBufferInternal(*initRequest.m_buffer); } } @@ -219,6 +219,11 @@ namespace AZ return m_descriptor; } + void BufferPool::BufferCopy(void* destination, const void* source, size_t num) + { + memcpy(destination, source, num); + } + ResultCode BufferPool::StreamBufferInternal([[maybe_unused]] const BufferStreamRequest& request) { return ResultCode::Unimplemented; diff --git a/Gems/Atom/RHI/Code/Source/RHI/BufferPoolBase.cpp b/Gems/Atom/RHI/Code/Source/RHI/BufferPoolBase.cpp index 8d61617da5..64f4454f0f 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/BufferPoolBase.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/BufferPoolBase.cpp @@ -34,7 +34,7 @@ namespace AZ if (!isDataValid) { - AZ_Warning("BufferPoolBase", false, "Failed to map buffer '%s'.", buffer.GetName().GetCStr()); + AZ_Error("BufferPoolBase", false, "Failed to map buffer '%s'.", buffer.GetName().GetCStr()); } ++buffer.m_mapRefCount; ++m_mapRefCount; diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/IndirectBufferSignature.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/IndirectBufferSignature.cpp index 42c5f91817..526c913085 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/IndirectBufferSignature.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/IndirectBufferSignature.cpp @@ -111,6 +111,8 @@ namespace AZ void IndirectBufferSignature::ShutdownInternal() { + auto& device = static_cast(GetDevice()); + device.QueueForRelease(m_signature); m_signature = nullptr; m_stride = 0; } diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/QueryPool.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/QueryPool.cpp index 5bb2be662d..f5eacfc576 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/QueryPool.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/QueryPool.cpp @@ -237,5 +237,14 @@ namespace AZ static constexpr D3D12_RANGE InvalidRange = {0,0}; m_readBackBuffer->Unmap(0, &InvalidRange); } + + void QueryPool::ShutdownInternal() + { + auto& device = static_cast(GetDevice()); + device.QueueForRelease(m_queryHeap); + m_queryHeap = nullptr; + device.QueueForRelease(m_readBackBuffer); + m_readBackBuffer = nullptr; + } } } diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/QueryPool.h b/Gems/Atom/RHI/DX12/Code/Source/RHI/QueryPool.h index eca040b724..7b0ab512cc 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/QueryPool.h +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/QueryPool.h @@ -44,6 +44,7 @@ namespace AZ RHI::ResultCode InitInternal(RHI::Device& device, const RHI::QueryPoolDescriptor& descriptor) override; RHI::ResultCode InitQueryInternal(RHI::Query& query) override; RHI::ResultCode GetResultsInternal(uint32_t startIndex, uint32_t queryCount, uint64_t* results, uint32_t resultsCount, RHI::QueryResultFlagBits flags) override; + void ShutdownInternal() override; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// diff --git a/Gems/Atom/RHI/Null/Code/Source/RHI/BufferPool.h b/Gems/Atom/RHI/Null/Code/Source/RHI/BufferPool.h index 8d1936fc56..5b69c765f2 100644 --- a/Gems/Atom/RHI/Null/Code/Source/RHI/BufferPool.h +++ b/Gems/Atom/RHI/Null/Code/Source/RHI/BufferPool.h @@ -39,9 +39,10 @@ namespace AZ RHI::ResultCode InitBufferInternal([[maybe_unused]] RHI::Buffer& buffer, [[maybe_unused]] const RHI::BufferDescriptor& rhiDescriptor) override{ return RHI::ResultCode::Success;} void ShutdownResourceInternal([[maybe_unused]] RHI::Resource& resource) override {} RHI::ResultCode OrphanBufferInternal([[maybe_unused]] RHI::Buffer& buffer) override { return RHI::ResultCode::Success;} - RHI::ResultCode MapBufferInternal([[maybe_unused]] const RHI::BufferMapRequest& mapRequest, [[maybe_unused]] RHI::BufferMapResponse& response) override { return RHI::ResultCode::Unimplemented;} + RHI::ResultCode MapBufferInternal([[maybe_unused]] const RHI::BufferMapRequest& mapRequest, [[maybe_unused]] RHI::BufferMapResponse& response) override { return RHI::ResultCode::Success;} void UnmapBufferInternal([[maybe_unused]] RHI::Buffer& buffer) override {} RHI::ResultCode StreamBufferInternal([[maybe_unused]] const RHI::BufferStreamRequest& request) override { return RHI::ResultCode::Success;} + void BufferCopy([[maybe_unused]] void* destination, [[maybe_unused]] const void* source, [[maybe_unused]] size_t num) override {} ////////////////////////////////////////////////////////////////////////// }; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/Buffer.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/Buffer.cpp index 87e7605c71..2d812c602f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/Buffer.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/Buffer.cpp @@ -176,8 +176,7 @@ namespace AZ return RHI::ResultCode::Success; } - // ResultCode::Unimplemented is used by Null Renderer and hence is a valid use case - AZ_Error("Buffer", resultCode == AZ::RHI::ResultCode::Unimplemented, "Buffer::Init() failed to initialize RHI buffer. Error code: %d", static_cast(resultCode)); + AZ_Error("Buffer", false, "Buffer::Init() failed to initialize RHI buffer. Error code: %d", static_cast(resultCode)); return resultCode; } @@ -241,11 +240,6 @@ namespace AZ { return response.m_data; } - else if (result == RHI::ResultCode::Unimplemented) - { - // ResultCode::Unimplemented is used by Null Renderer and hence is a valid use case - return nullptr; - } else { AZ_Error("RPI::Buffer", false, "Failed to update RHI buffer. Error code: %d", result); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp index bb66526ea0..77e32cd040 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp @@ -136,6 +136,7 @@ namespace AZ return false; } + bufferPool->SetName(Name(AZStd::string::format("RPI::CommonBufferPool_%i", static_cast(poolType)))); RHI::ResultCode resultCode = bufferPool->Init(*device, bufferPoolDesc); if (resultCode != RHI::ResultCode::Success) { diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl index e6bde136f8..b7329b5dcc 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl @@ -1107,7 +1107,7 @@ namespace AZ { ImGui::TableSetupColumn("Parent pool"); ImGui::TableSetupColumn("Name"); - ImGui::TableSetupColumn("Size (MB)", 0, 100.0f); + ImGui::TableSetupColumn("Size (MB)"); ImGui::TableSetupColumn("BindFlags", ImGuiTableColumnFlags_NoSort); ImGui::TableHeadersRow(); ImGui::TableNextColumn(); @@ -1133,7 +1133,7 @@ namespace AZ ImGui::TableNextColumn(); ImGui::Text(tableRow.m_bufImgName.GetCStr()); ImGui::TableNextColumn(); - ImGui::Text("%.2f", 1.0f * tableRow.m_sizeInBytes / GpuProfilerImGuiHelper::MB); + ImGui::Text("%.4f", 1.0f * tableRow.m_sizeInBytes / GpuProfilerImGuiHelper::MB); ImGui::TableNextColumn(); ImGui::Text(tableRow.m_bindFlags.c_str()); ImGui::TableNextColumn(); @@ -1271,6 +1271,7 @@ namespace AZ m_nameFilter.Draw("Search"); DrawTable(); } + ImGui::End(); } // --- ImGuiGpuProfiler --- From 8bc9ed3d01613092b71e1346535ca138e2023f4d Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 20 Aug 2021 13:39:51 -0700 Subject: [PATCH 53/54] removing some rad leftovers (#3366) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../azcore_profile_telemetry_files.cmake | 12 --- .../RPI/Code/Source/RPI.Public/Culling.cpp | 2 +- .../ly_test_tools/report/rad_telemetry.py | 98 ------------------- .../tests/unit/test_rad_telemetry.py | 88 ----------------- cmake/3rdParty/FindRadTelemetry.cmake | 14 --- .../Platform/iOS/cmake_ios_files.cmake | 1 - cmake/3rdParty/cmake_files.cmake | 1 - .../3rdParty/package_filelists/3rdParty.json | 1 - 8 files changed, 1 insertion(+), 216 deletions(-) delete mode 100644 Code/Framework/AzCore/Platform/Common/azcore_profile_telemetry_files.cmake delete mode 100755 Tools/LyTestTools/ly_test_tools/report/rad_telemetry.py delete mode 100755 Tools/LyTestTools/tests/unit/test_rad_telemetry.py delete mode 100644 cmake/3rdParty/FindRadTelemetry.cmake diff --git a/Code/Framework/AzCore/Platform/Common/azcore_profile_telemetry_files.cmake b/Code/Framework/AzCore/Platform/Common/azcore_profile_telemetry_files.cmake deleted file mode 100644 index d23f8df790..0000000000 --- a/Code/Framework/AzCore/Platform/Common/azcore_profile_telemetry_files.cmake +++ /dev/null @@ -1,12 +0,0 @@ -# -# 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. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -set(FILES - RadTelemetry/ProfileTelemetry.h - RadTelemetry/ProfileTelemetryBus.h -) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index 841607404a..f07262f2ca 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -31,7 +31,7 @@ #include #endif -//Enables more inner-loop profiling scopes (can create high overhead in RadTelemetry if there are many-many objects in a scene) +//Enables more inner-loop profiling scopes (can create high overhead in telemetry if there are many-many objects in a scene) //#define AZ_CULL_PROFILE_DETAILED //Enables more detailed profiling descriptions within the culling system, but adds some performance overhead. diff --git a/Tools/LyTestTools/ly_test_tools/report/rad_telemetry.py b/Tools/LyTestTools/ly_test_tools/report/rad_telemetry.py deleted file mode 100755 index 865cc4671c..0000000000 --- a/Tools/LyTestTools/ly_test_tools/report/rad_telemetry.py +++ /dev/null @@ -1,98 +0,0 @@ -""" -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. - -SPDX-License-Identifier: Apache-2.0 OR MIT - -Helpers for RAD Telemetry, currently only for Windows -""" - -import logging -import subprocess -import os - -import ly_test_tools.environment.process_utils as process_utils -from ly_test_tools import WINDOWS - -_RAD_DEFAULT_PORT = 4719 - -_CREATE_NEW_PROCESS_GROUP = 0x00000200 -_DETACHED_PROCESS = 0x00000008 -_WINDOWS_FLAGS = _CREATE_NEW_PROCESS_GROUP | _DETACHED_PROCESS - -RAD_TOOLS_SUBPATH = os.path.join("dev", "Gems", "RADTelemetry", "Tools") - -log = logging.getLogger(__name__) - - -def __set_firewall_rule(direction, port): - """ - Adds a Windows firewall rule if one does not yet exist. Requires administrator privilege. - - :param direction: Must be 'in' or 'out' - :param port: target port to open - :return: None - """ - - assert WINDOWS, "Only implemented for Windows platforms" - log.info(f"Setting firewall rule on port '{port}' for direction '{direction}'") - - show_rule = ['netsh', 'advfirewall', 'firewall', 'show', 'rule', 'name=RADTelemetry', f'dir={direction}'] - show_result = process_utils.safe_check_call(show_rule) - - if show_result == 0: - log.debug("Rule already exists") - else: - add_rule = ['netsh', 'advfirewall', 'firewall', 'add', 'rule', 'name=RADTelemetry', f'dir={direction}', - 'action=allow', 'protocol=TCP', f'localport={port}'] - process_utils.check_call(add_rule) - log.debug("Added new rule") - - -def set_firewall_rules(): - """ - Opens firewall ports necessary for a remote device to communicate with the RAD Telemetry server. - Requires administrator privilege. - - :return: None - """ - assert WINDOWS, "Only implemented for Windows platforms" - __set_firewall_rule(direction="in", port=_RAD_DEFAULT_PORT) - __set_firewall_rule(direction="out", port=_RAD_DEFAULT_PORT) - - -def launch_server(dev_path): - """ - Launches the RAD Telemetry server to collect telemetry captures. - - :param dev_path: path to the folder containing engineroot.txt - :return: None - """ - assert WINDOWS, "Only implemented for Windows platforms" - server_path = os.path.join(dev_path, RAD_TOOLS_SUBPATH, "tm_server.exe") - subprocess.Popen([server_path], creationflags=_WINDOWS_FLAGS, close_fds=True) - log.info(f"Launched RAD Server from {server_path}") - - -def terminate_servers(dev_path): - """ - Terminate the RAD Telemetry server and all related tools, important before collecting any of its captures - - :param dev_path: path to the folder containing engineroot.txt - :return: None - """ - assert WINDOWS, "Only implemented for Windows platforms" - rad_path = os.path.join(dev_path, RAD_TOOLS_SUBPATH) - process_utils.kill_processes_started_from(rad_path) - - -def get_capture_path(dev_path): - """ - Returns the path of the tm_server.exe file - - :return: path to the folder containing output for local servers - """ - assert WINDOWS, "Only implemented for Windows platforms" - get_folder_path = os.path.join(dev_path, RAD_TOOLS_SUBPATH, "tm_server.exe") - output = process_utils.check_output([get_folder_path]) - return output.strip() diff --git a/Tools/LyTestTools/tests/unit/test_rad_telemetry.py b/Tools/LyTestTools/tests/unit/test_rad_telemetry.py deleted file mode 100755 index 76db056215..0000000000 --- a/Tools/LyTestTools/tests/unit/test_rad_telemetry.py +++ /dev/null @@ -1,88 +0,0 @@ -""" -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. - -SPDX-License-Identifier: Apache-2.0 OR MIT - -Unit Tests for ~/ly_test_tools/report/rad_telemetry.py -""" - -import unittest.mock as mock -import os -import pytest - -import ly_test_tools.report.rad_telemetry -from ly_test_tools import WINDOWS - -pytestmark = pytest.mark.SUITE_smoke - - -_RAD_DEFAULT_PORT = 4719 - -_CREATE_NEW_PROCESS_GROUP = 0x00000200 -_DETACHED_PROCESS = 0x00000008 -_WINDOWS_FLAGS = _CREATE_NEW_PROCESS_GROUP | _DETACHED_PROCESS - -RAD_TOOLS_SUBPATH = os.path.join("dev", "Gems", "RADTelemetry", "Tools") - - -@pytest.mark.skipif( - not WINDOWS, - reason="tests.unit.test_rad_telemetry is restricted to the Windows platform.") -class TestRADTelemetry: - - @mock.patch('ly_test_tools.environment.process_utils.check_call') - @mock.patch('ly_test_tools.environment.process_utils.safe_check_call') - def test_SetFirewallRules_ShowRuleResultNotZero_CallsAddRule(self, mock_safe_call, mock_call): - ly_test_tools.report.rad_telemetry.set_firewall_rules() - - mock_safe_call.call_args_list = [ - mock.call(['netsh', 'advfirewall', 'firewall', 'show', 'rule', 'name=RADTelemetry', 'dir=in']), - mock.call(['netsh', 'advfirewall', 'firewall', 'show', 'rule', 'name=RADTelemetry', 'dir=out']), - ] - mock_call.call_args_list = [ - mock.call( - ['netsh', 'advfirewall', 'firewall', 'add', 'rule', 'name=RADTelemetry', 'dir=in', - 'action=allow', 'protocol=TCP', 'localport={}'.format(_RAD_DEFAULT_PORT)]), - mock.call( - ['netsh', 'advfirewall', 'firewall', 'add', 'rule', 'name=RADTelemetry', 'dir=out', - 'action=allow', 'protocol=TCP', 'localport={}'.format(_RAD_DEFAULT_PORT)]), - ] - - assert mock_call.call_count == 2 - assert mock_safe_call.call_count == 2 - - @mock.patch('ly_test_tools.environment.process_utils.check_call') - @mock.patch('ly_test_tools.environment.process_utils.safe_check_call') - def test_SetFirewallRules_ShowRuleResultEqualsZero_AddRuleNotCalled(self, mock_safe_call, mock_call): - mock_safe_call.return_value = 0 - ly_test_tools.report.rad_telemetry.set_firewall_rules() - - mock_call.assert_not_called() - assert mock_safe_call.call_count == 2 - - @mock.patch('subprocess.Popen') - def test_LaunchServer_ValidDevPath_PopenSuccess(self, mock_popen): - mock_server_path = os.path.join('dev_path', RAD_TOOLS_SUBPATH, "tm_server.exe") - - ly_test_tools.report.rad_telemetry.launch_server('dev_path') - - mock_popen.assert_called_once_with([mock_server_path], creationflags=_WINDOWS_FLAGS, close_fds=True) - - @mock.patch('ly_test_tools.environment.process_utils.kill_processes_started_from') - def test_TerminateServer_ValidDevPath_KillsRADProcess(self, mock_kill_process): - mock_rad_path = os.path.join('dev_path', RAD_TOOLS_SUBPATH) - - ly_test_tools.report.rad_telemetry.terminate_servers('dev_path') - - mock_kill_process.assert_called_once_with(mock_rad_path) - - @mock.patch('ly_test_tools.environment.process_utils.check_output') - def test_TerminateServer_ValidDevPath_KillsRADProcess(self, mock_call): - mock_get_folder_path = os.path.join('dev_path', RAD_TOOLS_SUBPATH, "tm_server.exe") - mock_call.return_value = 'test' - - under_test = ly_test_tools.report.rad_telemetry.get_capture_path('dev_path') - - mock_call.assert_called_once_with([mock_get_folder_path]) - assert under_test == 'test' diff --git a/cmake/3rdParty/FindRadTelemetry.cmake b/cmake/3rdParty/FindRadTelemetry.cmake deleted file mode 100644 index 4af7423526..0000000000 --- a/cmake/3rdParty/FindRadTelemetry.cmake +++ /dev/null @@ -1,14 +0,0 @@ -# -# 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. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -ly_add_external_target( - NAME RadTelemetry - 3RDPARTY_ROOT_DIRECTORY "${LY_RAD_TELEMETRY_INSTALL_ROOT}" - VERSION 3.5.0.17 - INCLUDE_DIRECTORIES Include -) diff --git a/cmake/3rdParty/Platform/iOS/cmake_ios_files.cmake b/cmake/3rdParty/Platform/iOS/cmake_ios_files.cmake index dc02644f5b..10e3ad7ec2 100644 --- a/cmake/3rdParty/Platform/iOS/cmake_ios_files.cmake +++ b/cmake/3rdParty/Platform/iOS/cmake_ios_files.cmake @@ -8,6 +8,5 @@ set(FILES BuiltInPackages_ios.cmake - RadTelemetry_ios.cmake Wwise_ios.cmake ) diff --git a/cmake/3rdParty/cmake_files.cmake b/cmake/3rdParty/cmake_files.cmake index cf56031db6..5f67355965 100644 --- a/cmake/3rdParty/cmake_files.cmake +++ b/cmake/3rdParty/cmake_files.cmake @@ -10,7 +10,6 @@ set(FILES BuiltInPackages.cmake FindOpenGLInterface.cmake FindPIX.cmake - FindRadTelemetry.cmake FindVkValidation.cmake FindWwise.cmake ) diff --git a/scripts/build/package/Platform/3rdParty/package_filelists/3rdParty.json b/scripts/build/package/Platform/3rdParty/package_filelists/3rdParty.json index a9ed45daca..915368dd0b 100644 --- a/scripts/build/package/Platform/3rdParty/package_filelists/3rdParty.json +++ b/scripts/build/package/Platform/3rdParty/package_filelists/3rdParty.json @@ -12,7 +12,6 @@ "FbxSdk/2016.1.2-az.1/**": "#include", "OpenSSL/1.1.1b-noasm-az/**": "#include", "Qt/5.15.1.2-az/**": "#include", - "RadTelemetry/3.5.0.17/**": "#include", "tiff/3.9.5-az.3/**": "#include", "Wwise/2019.2.8.7432/**": "#include" } From 57a8e4fb4e5fa724096840070a367e2208078a90 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 20 Aug 2021 13:40:46 -0700 Subject: [PATCH 54/54] build fixes (#3369) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Frontend/Console/Code/Source/TestImpactConsoleUtils.cpp | 1 + Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/Code/Tools/TestImpactFramework/Frontend/Console/Code/Source/TestImpactConsoleUtils.cpp b/Code/Tools/TestImpactFramework/Frontend/Console/Code/Source/TestImpactConsoleUtils.cpp index 47cdca11b1..61fb0a1707 100644 --- a/Code/Tools/TestImpactFramework/Frontend/Console/Code/Source/TestImpactConsoleUtils.cpp +++ b/Code/Tools/TestImpactFramework/Frontend/Console/Code/Source/TestImpactConsoleUtils.cpp @@ -7,6 +7,7 @@ */ #include +#include namespace TestImpact { diff --git a/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp b/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp index bfb1254e52..07113e09d3 100644 --- a/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp +++ b/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include