From 99a009bb770e363d2fb94419ea98a7a9cb7aaa21 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 17 Sep 2021 12:36:09 -0700 Subject: [PATCH 01/77] WIP checkpoint Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Legacy/CryCommon/ProjectDefines.h | 3 - Code/Legacy/CryCommon/platform_impl.cpp | 3 - cmake/Packaging.cmake | 89 ++++++++++++------- cmake/Platform/Common/Install_common.cmake | 51 +++++++---- .../Packaging/BootstrapperTheme.xml.in | 15 ++-- .../Platform/Windows/Packaging_windows.cmake | 5 +- cmake/Projects.cmake | 2 +- 7 files changed, 101 insertions(+), 67 deletions(-) diff --git a/Code/Legacy/CryCommon/ProjectDefines.h b/Code/Legacy/CryCommon/ProjectDefines.h index 203bd304c9..2c3df4e37f 100644 --- a/Code/Legacy/CryCommon/ProjectDefines.h +++ b/Code/Legacy/CryCommon/ProjectDefines.h @@ -81,9 +81,6 @@ #include AZ_RESTRICTED_FILE(ProjectDefines_h) #else #define PROJECTDEFINES_H_TRAIT_DISABLE_MONOLITHIC_PROFILING_MARKERS 1 - #if !defined(LINUX) && !defined(APPLE) - #define PROJECTDEFINES_H_TRAIT_ENABLE_SOFTCODE_SYSTEM 1 - #endif #if defined(WIN32) || defined(WIN64) || defined(LINUX) || defined(APPLE) #define PROJECTDEFINES_H_TRAIT_USE_GPU_PARTICLES 1 #endif diff --git a/Code/Legacy/CryCommon/platform_impl.cpp b/Code/Legacy/CryCommon/platform_impl.cpp index 323d3daf65..a68a5150db 100644 --- a/Code/Legacy/CryCommon/platform_impl.cpp +++ b/Code/Legacy/CryCommon/platform_impl.cpp @@ -71,7 +71,6 @@ void InitCRTHandlers() void InitCRTHandlers() {} #endif -#ifndef SOFTCODE ////////////////////////////////////////////////////////////////////////// // This is an entry to DLL initialization function that must be called for each loaded module ////////////////////////////////////////////////////////////////////////// @@ -136,8 +135,6 @@ void* GetDetachEnvironmentSymbol() return reinterpret_cast(&DetachEnvironment); } -#endif // !defined(SOFTCODE) - bool g_bProfilerEnabled = false; ////////////////////////////////////////////////////////////////////////// diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 477a5f24ea..d13293db40 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -89,37 +89,42 @@ endif() set(_cmake_package_dest ${CPACK_BINARY_DIR}/${CPACK_CMAKE_PACKAGE_FILE}) -string(REPLACE "." ";" _version_componets "${CPACK_DESIRED_CMAKE_VERSION}") -list(GET _version_componets 0 _major_version) -list(GET _version_componets 1 _minor_version) - -set(_url_version_tag "v${_major_version}.${_minor_version}") -set(_package_url "https://cmake.org/files/${_url_version_tag}/${CPACK_CMAKE_PACKAGE_FILE}") - -message(STATUS "Downloading CMake ${CPACK_DESIRED_CMAKE_VERSION} for packaging...") -download_file( - URL ${_package_url} - TARGET_FILE ${_cmake_package_dest} - EXPECTED_HASH ${CPACK_CMAKE_PACKAGE_HASH} - RESULTS _results -) -list(GET _results 0 _status_code) - -if (${_status_code} EQUAL 0 AND EXISTS ${_cmake_package_dest}) - message(STATUS "Package found and verified!") +if(EXISTS ${_cmake_package_dest}) + message(STATUS "CMake ${CPACK_DESIRED_CMAKE_VERSION} found") else() - file(REMOVE ${_cmake_package_dest}) - list(REMOVE_AT _results 0) + # download it + string(REPLACE "." ";" _version_componets "${CPACK_DESIRED_CMAKE_VERSION}") + list(GET _version_componets 0 _major_version) + list(GET _version_componets 1 _minor_version) - set(_error_message "An error occurred, code ${_status_code}. URL ${_package_url} - ${_results}") + set(_url_version_tag "v${_major_version}.${_minor_version}") + set(_package_url "https://cmake.org/files/${_url_version_tag}/${CPACK_CMAKE_PACKAGE_FILE}") - if(${_status_code} EQUAL 1) - string(APPEND _error_message - " Please double check the CPACK_CMAKE_PACKAGE_FILE and " - "CPACK_CMAKE_PACKAGE_HASH properties before trying again.") + message(STATUS "Downloading CMake ${CPACK_DESIRED_CMAKE_VERSION} for packaging...") + download_file( + URL ${_package_url} + TARGET_FILE ${_cmake_package_dest} + EXPECTED_HASH ${CPACK_CMAKE_PACKAGE_HASH} + RESULTS _results + ) + list(GET _results 0 _status_code) + + if (${_status_code} EQUAL 0 AND EXISTS ${_cmake_package_dest}) + message(STATUS "CMake ${CPACK_DESIRED_CMAKE_VERSION} found") + else() + file(REMOVE ${_cmake_package_dest}) + list(REMOVE_AT _results 0) + + set(_error_message "An error occurred, code ${_status_code}. URL ${_package_url} - ${_results}") + + if(${_status_code} EQUAL 1) + string(APPEND _error_message + " Please double check the CPACK_CMAKE_PACKAGE_FILE and " + "CPACK_CMAKE_PACKAGE_HASH properties before trying again.") + endif() + + message(FATAL_ERROR ${_error_message}) endif() - - message(FATAL_ERROR ${_error_message}) endif() install(FILES ${_cmake_package_dest} @@ -192,17 +197,19 @@ include(CPack REQUIRED) function(ly_configure_cpack_component ly_configure_cpack_component_NAME) - set(options REQUIRED) - set(oneValueArgs DISPLAY_NAME DESCRIPTION LICENSE_NAME LICENSE_FILE) + set(options REQUIRED DISABLED) + set(oneValueArgs DISPLAY_NAME DESCRIPTION LICENSE_NAME LICENSE_FILE DEPENDS) set(multiValueArgs) cmake_parse_arguments(ly_configure_cpack_component "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - # default to optional - set(component_type DISABLED) + unset(component_type) + if(ly_configure_cpack_component_DISABLED) + list(APPEND component_type DISABLED) + endif() if(ly_configure_cpack_component_REQUIRED) - set(component_type REQUIRED) + list(APPEND component_type REQUIRED) endif() set(license_name ${DEFAULT_LICENSE_NAME}) @@ -225,9 +232,23 @@ endfunction() # configure ALL components here ly_configure_cpack_component( ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} REQUIRED - DISPLAY_NAME "${PROJECT_NAME} Core" - DESCRIPTION "${PROJECT_NAME} Headers, Libraries and Tools" + DISPLAY_NAME "${PROJECT_NAME}" + DESCRIPTION "${PROJECT_NAME} Headers, scripts and common files" ) +foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + unset(flags) + if(${conf} STREQUAL profile) + set(flags REQUIRED) + else() + set(flags DISABLED) + endif() + ly_configure_cpack_component( + ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} ${flags} + DISPLAY_NAME "${PROJECT_NAME} (${conf})" + DESCRIPTION "${PROJECT_NAME} Libraries and Tools in ${conf}" + ) +endforeach() if(LY_INSTALLER_DOWNLOAD_URL) strip_trailing_slash(${LY_INSTALLER_DOWNLOAD_URL} LY_INSTALLER_DOWNLOAD_URL) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index fdd3256d78..ab34446922 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -105,18 +105,24 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar RUNTIME_SUBDIR ${target_runtime_output_subdirectory} ) else() - install( - TARGETS ${TARGET_NAME} - ARCHIVE - DESTINATION ${archive_output_directory} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - LIBRARY - DESTINATION ${library_output_directory}/${target_library_output_subdirectory} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - RUNTIME - DESTINATION ${runtime_output_directory}/${target_runtime_output_subdirectory} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + install( + TARGETS ${TARGET_NAME} + ARCHIVE + DESTINATION ${archive_output_directory} + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} + CONFIGURATIONS ${conf} + LIBRARY + DESTINATION ${library_output_directory}/${target_library_output_subdirectory} + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} + CONFIGURATIONS ${conf} + RUNTIME + DESTINATION ${runtime_output_directory}/${target_runtime_output_subdirectory} + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} + CONFIGURATIONS ${conf} + ) + endforeach() endif() # CMakeLists.txt related files @@ -499,12 +505,15 @@ function(ly_setup_runtime_dependencies) if(COMMAND ly_install_code_function_override) ly_install_code_function_override() else() - install(CODE + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + install(CODE "function(ly_copy source_file target_directory) file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) endfunction()" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} + ) + endforeach() endif() unset(runtime_commands) @@ -543,9 +552,15 @@ endfunction()" list(REMOVE_DUPLICATES runtime_commands) list(JOIN runtime_commands " " runtime_commands_str) # the spaces are just to see the right identation in the cmake_install.cmake file - install(CODE "${runtime_commands_str}" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + install(CODE +"if(\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^(${conf})\$\") + ${runtime_commands_str} +endif()" + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} + ) + endforeach() endfunction() diff --git a/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in b/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in index eea1adc11b..cafa6c765a 100644 --- a/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in +++ b/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in @@ -21,7 +21,7 @@ #(loc.InstallHeader) -@WIX_THEME_INSTALL_LICENSE_ELEMENTS@ + @@ -33,11 +33,14 @@ #(loc.OptionsHeader) - #(loc.OptionsLocationLabel) - - - #(loc.OptionsWarningTitle) - #(loc.OptionsWarning) + Include debug SDK + Include release monolithic SDK + + #(loc.OptionsLocationLabel) + + + #(loc.OptionsWarningTitle) + #(loc.OptionsWarning) diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index 5bb9928b61..ddfaea00d1 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -23,6 +23,7 @@ set(CPACK_WIX_ROOT ${LY_INSTALLER_WIX_ROOT}) set(CPACK_GENERATOR WIX) +set(CPACK_THREADS 0) set(_cmake_package_name "cmake-${CPACK_DESIRED_CMAKE_VERSION}-windows-x86_64") set(CPACK_CMAKE_PACKAGE_FILE "${_cmake_package_name}.zip") set(CPACK_CMAKE_PACKAGE_HASH "15a49e2ab81c1822d75b1b1a92f7863f58e31f6d6aac1c4103eef2b071be3112") @@ -30,8 +31,8 @@ set(CPACK_CMAKE_PACKAGE_HASH "15a49e2ab81c1822d75b1b1a92f7863f58e31f6d6aac1c4103 # workaround for shortening the path cpack installs to by stripping the platform directory and forcing monolithic # mode to strip out component folders. this unfortunately is the closest we can get to changing the install location # as CPACK_PACKAGING_INSTALL_PREFIX/CPACK_SET_DESTDIR isn't supported for the WiX generator -set(CPACK_TOPLEVEL_TAG "") -set(CPACK_MONOLITHIC_INSTALL ON) +#set(CPACK_TOPLEVEL_TAG "") +#set(CPACK_MONOLITHIC_INSTALL ON) # CPack will generate the WiX product/upgrade GUIDs further down the chain if they weren't supplied # however, they are unique for each run. instead, let's do the auto generation here and add it to diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index 7f2ac6a4fd..85104e72f6 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -10,7 +10,7 @@ include_guard() -set(LY_PROJECTS "${LY_PROJECTS}" CACHE STRING "List of projects to enable, this can be a relative path to the engine root or an absolute path") +set(LY_PROJECTS "" CACHE STRING "List of projects to enable, this can be a relative path to the engine root or an absolute path") #! ly_add_target_dependencies: adds module load dependencies for this target. # From 642f2b37eeba821f3dacadd3a35d8efd6c02ce35 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 22 Sep 2021 18:48:26 -0700 Subject: [PATCH 02/77] able to put release monolithic into an installer Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Packaging.cmake | 13 ++ .../Packaging/BootstrapperTheme.wxl.in | 2 + .../Packaging/BootstrapperTheme.xml.in | 121 +++++++++--------- .../Platform/Windows/Packaging_windows.cmake | 4 +- .../build/Platform/Windows/build_config.json | 2 +- .../Platform/Windows/installer_windows.cmd | 2 +- 6 files changed, 79 insertions(+), 65 deletions(-) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index d13293db40..3c98c42d86 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -235,6 +235,8 @@ ly_configure_cpack_component( DISPLAY_NAME "${PROJECT_NAME}" DESCRIPTION "${PROJECT_NAME} Headers, scripts and common files" ) +#file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "set(LY_CPACK_COMPONENTS_ALL ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME})\n") + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) string(TOUPPER ${conf} UCONF) unset(flags) @@ -243,11 +245,20 @@ foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) else() set(flags DISABLED) endif() + + # Inject a check to not declare components that have not been built. We are using AzCore since that is a + # common target that will always be build, in every permutation and configuration + #file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" + # "if(EXISTS \"${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${conf}/${CMAKE_STATIC_LIBRARY_PREFIX}AzCore${CMAKE_STATIC_LIBRARY_SUFFIX}\")\n") ly_configure_cpack_component( ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} ${flags} DISPLAY_NAME "${PROJECT_NAME} (${conf})" DESCRIPTION "${PROJECT_NAME} Libraries and Tools in ${conf}" ) + #file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" +#"list(APPEND LY_CPACK_COMPONENTS_ALL ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF}) +#endif()\n") + endforeach() if(LY_INSTALLER_DOWNLOAD_URL) @@ -260,3 +271,5 @@ if(LY_INSTALLER_DOWNLOAD_URL) ALL ) endif() + +#file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "set(CPACK_COMPONENTS_ALL \${LY_CPACK_COMPONENTS_ALL})\n") diff --git a/cmake/Platform/Windows/Packaging/BootstrapperTheme.wxl.in b/cmake/Platform/Windows/Packaging/BootstrapperTheme.wxl.in index 7d221913d5..9e5f796b70 100644 --- a/cmake/Platform/Windows/Packaging/BootstrapperTheme.wxl.in +++ b/cmake/Platform/Windows/Packaging/BootstrapperTheme.wxl.in @@ -20,6 +20,8 @@ Setup will install [WixBundleName] on your computer. Click install to continue, Setup Options + Include debug SDK + Include release-monolithic SDK Install location: &Browse WARNING: diff --git a/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in b/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in index cafa6c765a..22e76ad2db 100644 --- a/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in +++ b/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in @@ -1,7 +1,7 @@ - #(loc.WindowTitle) + #(loc.WindowTitle) Segoe UI @@ -15,113 +15,112 @@ Segoe UI - + - #(loc.InstallHeader) + #(loc.InstallHeader) - - - - + + + + - #(loc.OptionsHeader) + #(loc.OptionsHeader) - Include debug SDK - Include release monolithic SDK + #(loc.IncludeDebugSDK) + #(loc.IncludeReleaseMonolithicSDK) - #(loc.OptionsLocationLabel) - - - #(loc.OptionsWarningTitle) - #(loc.OptionsWarning) + #(loc.OptionsLocationLabel) + + + #(loc.OptionsWarningTitle) + #(loc.OptionsWarning) - - - + + + - #(loc.ModifyHeader) + #(loc.ModifyHeader) - - - - + + + + - #(loc.ProgressHeader) + #(loc.ProgressHeader) - #(loc.CacheProgressLabel) - - + #(loc.CacheProgressLabel) + + 100% - #(loc.ExecuteProgressLabel) - - + #(loc.ExecuteProgressLabel) + + 100% - - + + - #(loc.FilesInUseHeader) + #(loc.FilesInUseHeader) - #(loc.FilesInUseLabel) - + #(loc.FilesInUseLabel) + + + - - - - - - + + + - #(loc.SuccessHeader) - #(loc.SuccessInstallHeader) - #(loc.SuccessRepairHeader) - #(loc.SuccessUninstallHeader) + #(loc.SuccessHeader) + #(loc.SuccessInstallHeader) + #(loc.SuccessRepairHeader) + #(loc.SuccessUninstallHeader) - - - + + + - - #(loc.FailureHeader) - #(loc.FailureInstallHeader) - #(loc.FailureUninstallHeader) - #(loc.FailureRepairHeader) + + #(loc.FailureHeader) + #(loc.FailureInstallHeader) + #(loc.FailureUninstallHeader) + #(loc.FailureRepairHeader) - #(loc.FailureHyperlinkLogText) - + #(loc.FailureHyperlinkLogText) + MessageText - - + + - #(loc.HelpHeader) + #(loc.HelpHeader) - #(loc.HelpText) + #(loc.HelpText) - - + + diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index ddfaea00d1..63f0abc6ae 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -83,8 +83,8 @@ endif() set(CPACK_WIX_PRODUCT_GUID ${LY_WIX_PRODUCT_GUID}) set(CPACK_WIX_UPGRADE_GUID ${LY_WIX_UPGRADE_GUID}) -set(CPACK_WIX_PRODUCT_LOGO ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/product_logo.png) -set(CPACK_WIX_PRODUCT_ICON ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/product_icon.ico) +set(CPACK_WIX_PRODUCT_LOGO ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/logo.png) +set(CPACK_WIX_PRODUCT_ICON ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/icon.ico) set(CPACK_WIX_TEMPLATE "${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/Template.wxs.in") diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index 3848e6f980..a90a99856b 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -359,7 +359,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_INSTALLER_WIX_ROOT=\"!WIX! \"", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_INSTALLER_WIX_ROOT=\"!WIX!\"", "EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=ON -DLY_INSTALLER_DOWNLOAD_URL=https://www.o3debinaries.org -DLY_INSTALLER_LICENSE_URL=https://www.o3debinaries.org/license", "CPACK_BUCKET": "spectra-prism-staging-us-west-2", "CMAKE_LY_PROJECTS": "", diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index 87f53adc7f..94fb8c4f42 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -52,7 +52,7 @@ IF NOT "%CPACK_BUCKET%"=="" ( ) ECHO [ci_build] "!CPACK_PATH!" -C %CONFIGURATION% %CPACK_OPTIONS% -"!CPACK_PATH!" -C %CONFIGURATION% %CPACK_OPTIONS% +REM "!CPACK_PATH!" -C %CONFIGURATION% %CPACK_OPTIONS% IF NOT %ERRORLEVEL%==0 ( REM dump the log file generated by cpack specifically for WIX ECHO **************************************************************** From a2e9b0cb6922f4276da0b547988ab48c4b74580e Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 22 Sep 2021 19:29:08 -0700 Subject: [PATCH 03/77] reverting some changes that affected the custom UI Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Packaging/BootstrapperTheme.wxl.in | 2 - .../Packaging/BootstrapperTheme.xml.in | 122 +++++++++--------- .../Platform/Windows/Packaging_windows.cmake | 4 +- 3 files changed, 62 insertions(+), 66 deletions(-) diff --git a/cmake/Platform/Windows/Packaging/BootstrapperTheme.wxl.in b/cmake/Platform/Windows/Packaging/BootstrapperTheme.wxl.in index 9e5f796b70..7d221913d5 100644 --- a/cmake/Platform/Windows/Packaging/BootstrapperTheme.wxl.in +++ b/cmake/Platform/Windows/Packaging/BootstrapperTheme.wxl.in @@ -20,8 +20,6 @@ Setup will install [WixBundleName] on your computer. Click install to continue, Setup Options - Include debug SDK - Include release-monolithic SDK Install location: &Browse WARNING: diff --git a/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in b/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in index 22e76ad2db..eea1adc11b 100644 --- a/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in +++ b/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in @@ -1,7 +1,7 @@ - #(loc.WindowTitle) + #(loc.WindowTitle) Segoe UI @@ -15,112 +15,110 @@ Segoe UI - + - #(loc.InstallHeader) + #(loc.InstallHeader) - +@WIX_THEME_INSTALL_LICENSE_ELEMENTS@ - - - - + + + + - #(loc.OptionsHeader) + #(loc.OptionsHeader) - #(loc.IncludeDebugSDK) - #(loc.IncludeReleaseMonolithicSDK) + #(loc.OptionsLocationLabel) + + + #(loc.OptionsWarningTitle) + #(loc.OptionsWarning) - #(loc.OptionsLocationLabel) - - - #(loc.OptionsWarningTitle) - #(loc.OptionsWarning) - - - - + + + - #(loc.ModifyHeader) + #(loc.ModifyHeader) - - - - + + + + - #(loc.ProgressHeader) + #(loc.ProgressHeader) - #(loc.CacheProgressLabel) - - 100% + #(loc.CacheProgressLabel) + + - #(loc.ExecuteProgressLabel) - - 100% + #(loc.ExecuteProgressLabel) + + - - + + - #(loc.FilesInUseHeader) + #(loc.FilesInUseHeader) - #(loc.FilesInUseLabel) - - - + #(loc.FilesInUseLabel) + - - - + + + + + + - #(loc.SuccessHeader) - #(loc.SuccessInstallHeader) - #(loc.SuccessRepairHeader) - #(loc.SuccessUninstallHeader) + #(loc.SuccessHeader) + #(loc.SuccessInstallHeader) + #(loc.SuccessRepairHeader) + #(loc.SuccessUninstallHeader) - - - + + + - - #(loc.FailureHeader) - #(loc.FailureInstallHeader) - #(loc.FailureUninstallHeader) - #(loc.FailureRepairHeader) + + #(loc.FailureHeader) + #(loc.FailureInstallHeader) + #(loc.FailureUninstallHeader) + #(loc.FailureRepairHeader) - #(loc.FailureHyperlinkLogText) - MessageText + #(loc.FailureHyperlinkLogText) + - - + + - #(loc.HelpHeader) + #(loc.HelpHeader) - #(loc.HelpText) + #(loc.HelpText) - - + + diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index 63f0abc6ae..ddfaea00d1 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -83,8 +83,8 @@ endif() set(CPACK_WIX_PRODUCT_GUID ${LY_WIX_PRODUCT_GUID}) set(CPACK_WIX_UPGRADE_GUID ${LY_WIX_UPGRADE_GUID}) -set(CPACK_WIX_PRODUCT_LOGO ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/logo.png) -set(CPACK_WIX_PRODUCT_ICON ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/icon.ico) +set(CPACK_WIX_PRODUCT_LOGO ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/product_logo.png) +set(CPACK_WIX_PRODUCT_ICON ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/product_icon.ico) set(CPACK_WIX_TEMPLATE "${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/Template.wxs.in") From 8ab9f89b46866cc66735260416f35bdba51dfb1e Mon Sep 17 00:00:00 2001 From: evanchia Date: Wed, 13 Oct 2021 12:43:54 -0700 Subject: [PATCH 04/77] Adding unit tests and docstrings for editor test files Signed-off-by: evanchia --- .../_internal/pytest_plugin/editor_test.py | 31 +- .../pytest_plugin/test_tools_fixtures.py | 10 +- .../ly_test_tools/o3de/editor_test.py | 357 ++++-- .../ly_test_tools/o3de/editor_test_utils.py | 24 +- .../tests/unit/test_editor_test_utils.py | 158 +++ Tools/LyTestTools/tests/unit/test_fixtures.py | 11 + .../tests/unit/test_o3de_editor_test.py | 1017 +++++++++++++++++ .../unit/test_pytest_plugin_editor_test.py | 41 + 8 files changed, 1567 insertions(+), 82 deletions(-) create mode 100644 Tools/LyTestTools/tests/unit/test_editor_test_utils.py create mode 100644 Tools/LyTestTools/tests/unit/test_o3de_editor_test.py create mode 100644 Tools/LyTestTools/tests/unit/test_pytest_plugin_editor_test.py diff --git a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/editor_test.py b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/editor_test.py index 80a562977b..2df5810047 100644 --- a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/editor_test.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/editor_test.py @@ -3,9 +3,7 @@ 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 -""" -""" Utility for specifying an Editor test, supports seamless parallelization and/or batching of tests. """ @@ -15,22 +13,41 @@ import inspect __test__ = False def pytest_addoption(parser): + # type (argparse.ArgumentParser) -> None + """ + Options when running tests in batches or parallel. + :param parser: The ArgumentParser object + :return: None + """ parser.addoption("--no-editor-batch", action="store_true", help="Don't batch multiple tests in single editor") parser.addoption("--no-editor-parallel", action="store_true", help="Don't run multiple editors in parallel") parser.addoption("--editors-parallel", type=int, action="store", help="Override the number editors to run at the same time") -# Create a custom custom item collection if the class defines pytest_custom_makeitem function -# This is used for automtically generating test functions with a custom collector def pytest_pycollect_makeitem(collector, name, obj): + # type (PyCollector, str, object) -> Collector + """ + Create a custom custom item collection if the class defines pytest_custom_makeitem function. This is used for + automtically generating test functions with a custom collector. + :param collector: The Python test collector + :param name: Name of the collector + :param obj: The custom collector, normally an EditorTestSuite.EditorTestClass object + :return: Returns the custom collector + """ if inspect.isclass(obj): for base in obj.__bases__: if hasattr(base, "pytest_custom_makeitem"): return base.pytest_custom_makeitem(collector, name, obj) -# Add custom modification of items. -# This is used for adding the runners into the item list @pytest.hookimpl(hookwrapper=True) def pytest_collection_modifyitems(session, items, config): + # type (Session, list, Config) -> None + """ + Add custom modification of items. This is used for adding the runners into the item list. + :param session: The Pytest Session + :param items: The test case functions + :param config: The Pytest Config object + :return: None + """ all_classes = set() for item in items: all_classes.add(item.instance.__class__) @@ -40,4 +57,4 @@ def pytest_collection_modifyitems(session, items, config): for cls in all_classes: if hasattr(cls, "pytest_custom_modify_items"): cls.pytest_custom_modify_items(session, items, config) - + diff --git a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py index f4bda9b293..3115c28406 100755 --- a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py @@ -55,8 +55,16 @@ def pytest_configure(config): ly_test_tools._internal.pytest_plugin.build_directory = _get_build_directory(config) ly_test_tools._internal.pytest_plugin.output_path = _get_output_path(config) - def pytest_pycollect_makeitem(collector, name, obj): + # type (PyCollector, str, object) -> Collector + """ + Create a custom custom item collection if the class defines pytest_custom_makeitem function. This is used for + automtically generating test functions with a custom collector. + :param collector: The Python test collector + :param name: Name of the collector + :param obj: The custom collector, normally an EditorTestSuite.EditorTestClass object + :return: Returns the custom collector + """ import inspect if inspect.isclass(obj): for base in obj.__bases__: diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py index 781977cf33..39413c22a3 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py @@ -25,16 +25,16 @@ import re import ly_test_tools.environment.file_system as file_system import ly_test_tools.environment.waiter as waiter import ly_test_tools.environment.process_utils as process_utils +import ly_test_tools.o3de.editor_test_utils as editor_utils from ly_test_tools.o3de.asset_processor import AssetProcessor from ly_test_tools.launchers.exceptions import WaitTimeoutError -from . import editor_test_utils as editor_utils # This file provides editor testing functionality to easily write automated editor tests for O3DE. -# For using these utilities, you can subclass your test suite from EditorTestSuite, this allows an easy way of specifying -# python test scripts that the editor will run without needing to write any boilerplace code. -# It supports out of the box parallelization(running multiple editor instances at once), batching(running multiple tests in the same editor instance) and -# crash detection. +# For using these utilities, you can subclass your test suite from EditorTestSuite, this allows an easy way of +# specifying python test scripts that the editor will run without needing to write any boilerplace code. +# It supports out of the box parallelization(running multiple editor instances at once), batching(running multiple tests +# in the same editor instance) and crash detection. # Usage example: # class MyTestSuite(EditorTestSuite): # @@ -48,7 +48,8 @@ from . import editor_test_utils as editor_utils # from . import yet_another_script_to_be_run_by_editor as test_module # # -# EditorTestSuite does introspection of the defined classes inside of it and automatically prepares the tests, parallelizing/batching as required +# EditorTestSuite does introspection of the defined classes inside of it and automatically prepares the tests, +# parallelizing/batching as required # This file contains no tests, but with this we make sure it won't be picked up by the runner since the file ends with _test __test__ = False @@ -109,12 +110,22 @@ class EditorBatchedTest(EditorSharedTest): class Result: class Base: def get_output_str(self): + # type () -> str + """ + Checks if the output attribute exists and returns it. + :return: Either the output string or a no output message + """ if hasattr(self, "output") and self.output is not None: return self.output else: return "-- No output --" def get_editor_log_str(self): + # type () -> str + """ + Checks if the editor_log attribute exists and returns it. + :return: Either the editor_log string or a no output message + """ if hasattr(self, "editor_log") and self.editor_log is not None: return self.editor_log else: @@ -122,7 +133,15 @@ class Result: class Pass(Base): @classmethod - def create(cls, test_spec : EditorTestBase, output : str, editor_log : str): + def create(cls, test_spec, output, editor_log): + # type (EditorTestBase, str, str) -> Pass + """ + Creates a Pass object with a given test spec, output string, and editor log string. + :test_spec: The type of EditorTestBase + :output: The test output + :editor_log: The editor log's output + :return: the Pass object + """ r = cls() r.test_spec = test_spec r.output = output @@ -141,7 +160,15 @@ class Result: class Fail(Base): @classmethod - def create(cls, test_spec : EditorTestBase, output, editor_log : str): + def create(cls, test_spec, output, editor_log): + # type (EditorTestBase, str, str) -> Fail + """ + Creates a Fail object with a given test spec, output string, and editor log string. + :test_spec: The type of EditorTestBase + :output: The test output + :editor_log: The editor log's output + :return: the Fail object + """ r = cls() r.test_spec = test_spec r.output = output @@ -164,7 +191,18 @@ class Result: class Crash(Base): @classmethod - def create(cls, test_spec : EditorTestBase, output : str, ret_code : int, stacktrace : str, editor_log : str): + def create(cls, test_spec, output, ret_code, stacktrace, editor_log): + # type (EditorTestBase, str, int, str, str) -> Crash + """ + Creates a Crash object with a given test spec, output string, and editor log string. This also includes the + return code and stacktrace. + :test_spec: The type of EditorTestBase + :output: The test output + :ret_code: The test's return code + :stacktrace: The test's stacktrace if available + :editor_log: The editor log's output + :return: The Crash object + """ r = cls() r.output = output r.test_spec = test_spec @@ -174,7 +212,7 @@ class Result: return r def __str__(self): - stacktrace_str = "-- No stacktrace data found --" if not self.stacktrace else self.stacktrace + stacktrace_str = "-- No stacktrace data found --\n" if not self.stacktrace else self.stacktrace output = ( f"Test CRASHED, return code {hex(self.ret_code)}\n" f"---------------\n" @@ -190,12 +228,21 @@ class Result: f"--------------\n" f"{self.get_editor_log_str()}\n" ) - crash_str = "-- No crash information found --" return output class Timeout(Base): @classmethod - def create(cls, test_spec : EditorTestBase, output : str, time_secs : float, editor_log : str): + def create(cls, test_spec, output, time_secs, editor_log): + # type (EditorTestBase, str, float, str) -> Timeout + """ + Creates a Timeout object with a given test spec, output string, and editor log string. The timeout time + should be provided in seconds + :test_spec: The type of EditorTestBase + :output: The test output + :time_secs: The timeout duration in seconds + :editor_log: The editor log's output + :return: The Timeout object + """ r = cls() r.output = output r.test_spec = test_spec @@ -219,14 +266,23 @@ class Result: class Unknown(Base): @classmethod - def create(cls, test_spec : EditorTestBase, output : str, extra_info : str, editor_log : str): + def create(cls, test_spec, output, extra_info, editor_log): + # type (EditorTestBase, str, str , str) -> Unknown + """ + Creates an Unknown test results object if something goes wrong. + :test_spec: The type of EditorTestBase + :output: The test output + :extra_info: Any extra information as a string + :editor_log: The editor log's output + :return: The Unknown object + """ r = cls() r.output = output r.test_spec = test_spec r.editor_log = editor_log r.extra_info = extra_info return r - + def __str__(self): output = ( f"Unknown test result, possible cause: {self.extra_info}\n" @@ -263,6 +319,18 @@ class EditorTestSuite(): @pytest.fixture(scope="class") def editor_test_data(self, request): + # type (request) -> TestData + """ + Yields a generator to capture the test results and an AssetProcessor object. + :request: The pytest request + :yield: The TestData object + """ + self._editor_test_data(request) + + def _editor_test_data(self, request): + """ + A wrapper function for unit testing to call directly + """ class TestData(): def __init__(self): self.results = {} # Dict of str(test_spec.__name__) -> Result @@ -445,6 +513,10 @@ class EditorTestSuite(): @classmethod def pytest_custom_modify_items(cls, session, items, config): + # type () -> None + """ + + """ # Add here the runners functions and filter the tests that will be run. # The runners will be added if they have any selected tests new_items = [] @@ -463,23 +535,53 @@ class EditorTestSuite(): @classmethod def get_single_tests(cls): + # type () -> list + """ + Grabs all of the EditorSingleTests subclassed tests from the EditorTestSuite class + Usage example: + class MyTestSuite(EditorTestSuite): + class MyFirstTest(EditorSingleTest): + from . import script_to_be_run_by_editor as test_module + :return: The list of single tests + """ single_tests = [c[1] for c in cls.__dict__.items() if inspect.isclass(c[1]) and issubclass(c[1], EditorSingleTest)] return single_tests @classmethod def get_shared_tests(cls): + # type () -> list + """ + Grabs all of the EditorSharedTests from the EditorTestSuite + Usage example: + class MyTestSuite(EditorTestSuite): + class MyFirstTest(EditorSharedTest): + from . import script_to_be_run_by_editor as test_module + :return: The list of shared tests + """ shared_tests = [c[1] for c in cls.__dict__.items() if inspect.isclass(c[1]) and issubclass(c[1], EditorSharedTest)] return shared_tests @classmethod def get_session_shared_tests(cls, session): + # type (Session) -> list[EditorTestBase] + """ + Filters and returns all of the shared tests in a given session. + :session: The test session + :return: The list of tests + """ shared_tests = cls.get_shared_tests() return cls.filter_session_shared_tests(session, shared_tests) @staticmethod def filter_session_shared_tests(session_items, shared_tests): - # Retrieve the test sub-set that was collected - # this can be less than the original set if were overriden via -k argument or similars + # type (list, list) -> list[EditorTestBase] + """ + Retrieve the test sub-set that was collected this can be less than the original set if were overriden via -k + argument or similars + :session_items: The tests in a session to run + :shared_tests: All of the shared tests + :return: The list of filtered tests + """ def will_run(item): try: skipping_pytest_runtest_setup(item) @@ -488,13 +590,20 @@ class EditorTestSuite(): return False session_items_by_name = { item.originalname:item for item in session_items } - selected_shared_tests = [test for test in shared_tests if test.__name__ in session_items_by_name.keys() and will_run(session_items_by_name[test.__name__])] + selected_shared_tests = [test for test in shared_tests if test.__name__ in session_items_by_name.keys() and + will_run(session_items_by_name[test.__name__])] return selected_shared_tests @staticmethod def filter_shared_tests(shared_tests, is_batchable=False, is_parallelizable=False): - # Retrieve the test sub-set that was collected - # this can be less than the original set if were overriden via -k argument or similars + # type (list, bool, bool) -> list + """ + Filters and returns all tests based off of if they are batchable and/or parallelizable + :shared_tests: All shared tests + :is_batchable: Filter to batchable tests + :is_parallelizable: Filter to parallelizable tests + :return: The list of filtered tests + """ return [ t for t in shared_tests if ( getattr(t, "is_batchable", None) is is_batchable @@ -504,9 +613,15 @@ class EditorTestSuite(): ] ### Utils ### - - # Prepares the asset processor for the test def _prepare_asset_processor(self, workspace, editor_test_data): + # type (AbstractWorkspace, TestData) -> None + """ + Prepares the asset processor for the test depending on whether or not the process is open and if the current + test owns it. + :workspace: The workspace object in case an AssetProcessor object needs to be created + :editor_test_data: The test data from calling editor_test_data() + :return: None + """ try: # Start-up an asset processor if we are not running one # If another AP process exist, don't kill it, as we don't own it @@ -525,14 +640,29 @@ class EditorTestSuite(): raise ex def _setup_editor_test(self, editor, workspace, editor_test_data): + # type(Editor, AbstractWorkspace, TestData) -> None + """ + Sets up an editor test by preparing the Asset Processor, killing all other O3DE processes, and configuring + :editor: The launcher Editor object + :workspace: The test Workspace object + :editor_test_data: The TestData from calling editor_test_data() + :return: None + """ self._prepare_asset_processor(workspace, editor_test_data) editor_utils.kill_all_ly_processes(include_asset_processor=False) editor.configure_settings() - # Utility function for parsing the output information from the editor. - # It deserializes the JSON content printed in the output for every test and returns that information. @staticmethod def _get_results_using_output(test_spec_list, output, editor_log_content): + # type(list, str, str) -> dict{str: Result} + """ + Utility function for parsing the output information from the editor. It deserializes the JSON content printed in + the output for every test and returns that information. + :test_spec_list: The list of EditorTests + :output: The Editor from Editor.get_output() + :editor_log_content: The contents of the editor log as a string + :return: A dict of the tests and their respective Result objects + """ results = {} pattern = re.compile(r"JSON_START\((.+?)\)JSON_END") out_matches = pattern.finditer(output) @@ -541,7 +671,8 @@ class EditorTestSuite(): try: elem = json.loads(m.groups()[0]) found_jsons[elem["name"]] = elem - except Exception: + except Exception as e: + raise e continue # Avoid to fail if the output data is corrupt # Try to find the element in the log, this is used for cutting the log contents later @@ -558,7 +689,9 @@ class EditorTestSuite(): for test_spec in test_spec_list: name = editor_utils.get_module_filename(test_spec.test_module) if name not in found_jsons.keys(): - results[test_spec.__name__] = Result.Unknown.create(test_spec, output, "Couldn't find any test run information on stdout", editor_log_content) + results[test_spec.__name__] = Result.Unknown.create(test_spec, output, + "Couldn't find any test run information on stdout", + editor_log_content) else: result = None json_result = found_jsons[name] @@ -573,7 +706,7 @@ class EditorTestSuite(): cur_log = editor_log_content[log_start : end] log_start = end - if json_result["success"]: + if "success" in json_result.keys(): result = Result.Pass.create(test_spec, json_output, cur_log) else: result = Result.Fail.create(test_spec, json_output, cur_log) @@ -581,9 +714,15 @@ class EditorTestSuite(): return results - # Fails the test if the test result is not a PASS, specifying the information @staticmethod - def _report_result(name : str, result : Result.Base): + def _report_result(name, result): + # type (str, Result) -> None + """ + Fails the test if the test result is not a PASS, specifying the information + :name: Name of the test + :result: The Result object which denotes if the test passed or not + :return: None + """ if isinstance(result, Result.Pass): output_str = f"Test {name}:\n{str(result)}" print(output_str) @@ -592,10 +731,19 @@ class EditorTestSuite(): pytest.fail(error_str) ### Running tests ### - # Starts the editor with the given test and retuns an result dict with a single element specifying the result - def _exec_editor_test(self, request, workspace, editor, run_id : int, log_name : str, - test_spec : EditorTestBase, cmdline_args : List[str] = []): - + def _exec_editor_test(self, request, workspace, editor, run_id, log_name, test_spec, cmdline_args = []): + # type (Request, AbstractWorkspace, Editor, int, str, EditorTestBase, list[str] -> dict{str: Result} + """ + Starts the editor with the given test and retuns an result dict with a single element specifying the result + :request: The pytest request + :workspace: The LyTestTools Workspace object + :editor: The LyTestTools Editor object + :run_id: The unique run id + :log_name: The name of the editor log to retrieve + :test_spec: The type of EditorTestBase + :cmdline_args: Any additional command line args + :return: a dictionary of Result objects + """ test_cmdline_args = self.global_extra_cmdline_args + cmdline_args test_spec_uses_null_renderer = getattr(test_spec, "use_null_renderer", None) if test_spec_uses_null_renderer or (test_spec_uses_null_renderer is None and self.use_null_renderer): @@ -629,12 +777,14 @@ class EditorTestSuite(): else: has_crashed = return_code != EditorTestSuite._TEST_FAIL_RETCODE if has_crashed: - test_result = Result.Crash.create(test_spec, output, return_code, editor_utils.retrieve_crash_output(run_id, workspace, self._TIMEOUT_CRASH_LOG), None) + test_result = Result.Crash.create(test_spec, output, return_code, editor_utils.retrieve_crash_output + (run_id, workspace, self._TIMEOUT_CRASH_LOG), None) editor_utils.cycle_crash_report(run_id, workspace) else: test_result = Result.Fail.create(test_spec, output, editor_log_content) except WaitTimeoutError: - editor.kill() + output = editor.get_output() + editor.kill() editor_log_content = editor_utils.retrieve_editor_log_content(run_id, log_name, workspace) test_result = Result.Timeout.create(test_spec, output, test_spec.timeout, editor_log_content) @@ -643,11 +793,21 @@ class EditorTestSuite(): results[test_spec.__name__] = test_result return results - # Starts an editor executable with a list of tests and returns a dict of the result of every test ran within that editor - # instance. In case of failure this function also parses the editor output to find out what specific tests failed - def _exec_editor_multitest(self, request, workspace, editor, run_id : int, log_name : str, - test_spec_list : List[EditorTestBase], cmdline_args=[]): - + def _exec_editor_multitest(self, request, workspace, editor, run_id, log_name, test_spec_list, cmdline_args=[]): + # type (Request, AbstractWorkspace, Editor, int, str, list[EditorTestBase], list[str]) -> dict{str: Result} + """ + Starts an editor executable with a list of tests and returns a dict of the result of every test ran within that + editor instance. In case of failure this function also parses the editor output to find out what specific tests + failed. + :request: The pytest request + :workspace: The LyTestTools Workspace object + :editor: The LyTestTools Editor object + :run_id: The unique run id + :log_name: The name of the editor log to retrieve + :test_spec_list: A list of EditorTestBase tests to run + :cmdline_args: Any additional command line args + :return: A dict of Result objects + """ test_cmdline_args = self.global_extra_cmdline_args + cmdline_args if self.use_null_renderer: test_cmdline_args += ["-rhi=null"] @@ -660,7 +820,8 @@ class EditorTestSuite(): editor_utils.cycle_crash_report(run_id, workspace) results = {} - test_filenames_str = ";".join(editor_utils.get_testcase_module_filepath(test_spec.test_module) for test_spec in test_spec_list) + test_filenames_str = ";".join(editor_utils.get_testcase_module_filepath(test_spec.test_module) for + test_spec in test_spec_list) cmdline = [ "--runpythontest", test_filenames_str, "-logfile", f"@log@/{log_name}", @@ -685,7 +846,8 @@ class EditorTestSuite(): # Scrap the output to attempt to find out which tests failed. # This function should always populate the result list, if it didn't find it, it will have "Unknown" type of result results = self._get_results_using_output(test_spec_list, output, editor_log_content) - assert len(results) == len(test_spec_list), "bug in _get_results_using_output(), the number of results don't match the tests ran" + assert len(results) == len(test_spec_list), "bug in _get_results_using_output(), the number of results" \ + "don't match the tests ran" # If the editor crashed, find out in which test it happened and update the results has_crashed = return_code != EditorTestSuite._TEST_FAIL_RETCODE @@ -695,50 +857,67 @@ class EditorTestSuite(): if isinstance(result, Result.Unknown): if not crashed_result: # The first test with "Unknown" result (no data in output) is likely the one that crashed - crash_error = editor_utils.retrieve_crash_output(run_id, workspace, self._TIMEOUT_CRASH_LOG) + crash_error = editor_utils.retrieve_crash_output(run_id, workspace, + self._TIMEOUT_CRASH_LOG) editor_utils.cycle_crash_report(run_id, workspace) - results[test_spec_name] = Result.Crash.create(result.test_spec, output, return_code, crash_error, result.editor_log) + results[test_spec_name] = Result.Crash.create(result.test_spec, output, return_code, + crash_error, result.editor_log) crashed_result = result else: - # If there are remaning "Unknown" results, these couldn't execute because of the crash, update with info about the offender - results[test_spec_name].extra_info = f"This test has unknown result, test '{crashed_result.test_spec.__name__}' crashed before this test could be executed" - + # If there are remaning "Unknown" results, these couldn't execute because of the crash, + # update with info about the offender + results[test_spec_name].extra_info = f"This test has unknown result, test " \ + f"'{crashed_result.test_spec.__name__}' crashed " \ + f"before this test could be executed" # if all the tests ran, the one that has caused the crash is the last test if not crashed_result: crash_error = editor_utils.retrieve_crash_output(run_id, workspace, self._TIMEOUT_CRASH_LOG) editor_utils.cycle_crash_report(run_id, workspace) - results[test_spec_name] = Result.Crash.create(crashed_result.test_spec, output, return_code, crash_error, crashed_result.editor_log) - - + results[test_spec_name] = Result.Crash.create(crashed_result.test_spec, output, return_code, + crash_error, crashed_result.editor_log) except WaitTimeoutError: editor.kill() - output = editor.get_output() editor_log_content = editor_utils.retrieve_editor_log_content(run_id, log_name, workspace) # The editor timed out when running the tests, get the data from the output to find out which ones ran results = self._get_results_using_output(test_spec_list, output, editor_log_content) - assert len(results) == len(test_spec_list), "bug in _get_results_using_output(), the number of results don't match the tests ran" - + assert len(results) == len(test_spec_list), "bug in _get_results_using_output(), the number of results " \ + "don't match the tests ran" # Similar logic here as crashes, the first test that has no result is the one that timed out timed_out_result = None for test_spec_name, result in results.items(): if isinstance(result, Result.Unknown): if not timed_out_result: - results[test_spec_name] = Result.Timeout.create(result.test_spec, result.output, self.timeout_editor_shared_test, result.editor_log) + results[test_spec_name] = Result.Timeout.create(result.test_spec, result.output, + self.timeout_editor_shared_test, + result.editor_log) timed_out_result = result else: - # If there are remaning "Unknown" results, these couldn't execute because of the timeout, update with info about the offender - results[test_spec_name].extra_info = f"This test has unknown result, test '{timed_out_result.test_spec.__name__}' timed out before this test could be executed" - + # If there are remaning "Unknown" results, these couldn't execute because of the timeout, + # update with info about the offender + results[test_spec_name].extra_info = f"This test has unknown result, test " \ + f"'{timed_out_result.test_spec.__name__}' timed out " \ + f"before this test could be executed" # if all the tests ran, the one that has caused the timeout is the last test, as it didn't close the editor if not timed_out_result: - results[test_spec_name] = Result.Timeout.create(timed_out_result.test_spec, results[test_spec_name].output, self.timeout_editor_shared_test, result.editor_log) + results[test_spec_name] = Result.Timeout.create(timed_out_result.test_spec, + results[test_spec_name].output, + self.timeout_editor_shared_test, result.editor_log) return results - # Runs a single test (one editor, one test) with the given specs - def _run_single_test(self, request, workspace, editor, editor_test_data, test_spec : EditorSingleTest): + def _run_single_test(self, request, workspace, editor, editor_test_data, test_spec): + # type (Request, AbstractWorkspace, Editor, TestData, EditorSingleTest) -> None + """ + Runs a single test (one editor, one test) with the given specs + :request: The Pytest Request + :workspace: The LyTestTools Workspace object + :editor: The LyTestTools Editor object + :editor_test_data: The TestData from calling editor_test_data() + :test_spec: The test class that should be a subclass of EditorSingleTest + :return: None + """ self._setup_editor_test(editor, workspace, editor_test_data) extra_cmdline_args = [] if hasattr(test_spec, "extra_cmdline_args"): @@ -749,18 +928,39 @@ class EditorTestSuite(): test_name, test_result = next(iter(results.items())) self._report_result(test_name, test_result) - # Runs a batch of tests in one single editor with the given spec list (one editor, multiple tests) - def _run_batched_tests(self, request, workspace, editor, editor_test_data, test_spec_list : List[EditorSharedTest], extra_cmdline_args=[]): + def _run_batched_tests(self, request, workspace, editor, editor_test_data, test_spec_list, extra_cmdline_args=[]): + # type (Request, AbstractWorkspace, Editor, TestData, list[EditorSharedTest], list[str]) -> None + """ + Runs a batch of tests in one single editor with the given spec list (one editor, multiple tests) + :request: The Pytest Request + :workspace: The LyTestTools Workspace object + :editor: The LyTestTools Editor object + :editor_test_data: The TestData from calling editor_test_data() + :test_spec_list: A list of EditorSharedTest tests to run + :extra_cmdline_args: Any extra command line args in a list + :return: None + """ if not test_spec_list: return self._setup_editor_test(editor, workspace, editor_test_data) - results = self._exec_editor_multitest(request, workspace, editor, 1, "editor_test.log", test_spec_list, extra_cmdline_args) + results = self._exec_editor_multitest(request, workspace, editor, 1, "editor_test.log", test_spec_list, + extra_cmdline_args) assert results is not None editor_test_data.results.update(results) - # Runs multiple editors with one test on each editor (multiple editor, one test each) - def _run_parallel_tests(self, request, workspace, editor, editor_test_data, test_spec_list : List[EditorSharedTest], extra_cmdline_args=[]): + def _run_parallel_tests(self, request, workspace, editor, editor_test_data, test_spec_list, extra_cmdline_args=[]): + # type(Request, AbstractWorkspace, Editor, TestData, list[EditorSharedTest], list[str]) -> None + """ + Runs multiple editors with one test on each editor (multiple editor, one test each) + :request: The Pytest Request + :workspace: The LyTestTools Workspace object + :editor: The LyTestTools Editor object + :editor_test_data: The TestData from calling editor_test_data() + :test_spec_list: A list of EditorSharedTest tests to run + :extra_cmdline_args: Any extra command line args in a list + :return: None + """ if not test_spec_list: return @@ -778,7 +978,8 @@ class EditorTestSuite(): for i in range(total_threads): def make_func(test_spec, index, my_editor): def run(request, workspace, extra_cmdline_args): - results = self._exec_editor_test(request, workspace, my_editor, index+1, f"editor_test.log", test_spec, extra_cmdline_args) + results = self._exec_editor_test(request, workspace, my_editor, index+1, f"editor_test.log", + test_spec, extra_cmdline_args) assert results is not None results_per_thread[index] = results return run @@ -796,8 +997,19 @@ class EditorTestSuite(): for result in results_per_thread: editor_test_data.results.update(result) - # Runs multiple editors with a batch of tests for each editor (multiple editor, multiple tests each) - def _run_parallel_batched_tests(self, request, workspace, editor, editor_test_data, test_spec_list : List[EditorSharedTest], extra_cmdline_args=[]): + def _run_parallel_batched_tests(self, request, workspace, editor, editor_test_data, test_spec_list, + extra_cmdline_args=[]): + # type(Request, AbstractWorkspace, Editor, TestData, list[EditorSharedTest], list[str] -> None + """ + Runs multiple editors with a batch of tests for each editor (multiple editor, multiple tests each) + :request: The Pytest Request + :workspace: The LyTestTools Workspace object + :editor: The LyTestTools Editor object + :editor_test_data: The TestData from calling editor_test_data() + :test_spec_list: A list of EditorSharedTest tests to run + :extra_cmdline_args: Any extra command line args in a list + :return: None + """ if not test_spec_list: return @@ -813,7 +1025,9 @@ class EditorTestSuite(): def run(request, workspace, extra_cmdline_args): results = None if len(test_spec_list_for_editor) > 0: - results = self._exec_editor_multitest(request, workspace, my_editor, index+1, f"editor_test.log", test_spec_list_for_editor, extra_cmdline_args) + results = self._exec_editor_multitest(request, workspace, my_editor, index+1, + f"editor_test.log", test_spec_list_for_editor, + extra_cmdline_args) assert results is not None else: results = {} @@ -833,8 +1047,13 @@ class EditorTestSuite(): for result in results_per_thread: editor_test_data.results.update(result) - # Retrieves the number of parallel preference cmdline overrides def _get_number_parallel_editors(self, request): + # type(Request) -> int + """ + Retrieves the number of parallel preference cmdline overrides + :request: The Pytest Request + :return: The number of parallel editors to use + """ parallel_editors_value = request.config.getoption("--editors-parallel", None) if parallel_editors_value: return int(parallel_editors_value) diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py index feff78d866..838f929cfa 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py @@ -3,6 +3,8 @@ 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 + +Utility functions for the editor_test module """ import os @@ -15,6 +17,12 @@ import ly_test_tools.environment.waiter as waiter logger = logging.getLogger(__name__) def kill_all_ly_processes(include_asset_processor=True): + # type (bool) -> None + """ + Kills all common O3DE processes such as the Editor, Game Launchers, and Asset Processor. + :param include_asset_processor: Boolean flag whether or not to kill the AP + :return: None + """ LY_PROCESSES = [ 'Editor', 'Profiler', 'RemoteConsole', ] @@ -47,7 +55,8 @@ def get_module_filename(testcase_module): """ return os.path.splitext(os.path.basename(testcase_module.__file__))[0] -def retrieve_log_path(run_id : int, workspace): +def retrieve_log_path(run_id, workspace): + # type (int, ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager) -> str """ return the log/ project path for this test run. :param run_id: editor id that will be used for differentiating paths @@ -56,7 +65,8 @@ def retrieve_log_path(run_id : int, workspace): """ return os.path.join(workspace.paths.project(), "user", f"log_test_{run_id}") -def retrieve_crash_output(run_id : int, workspace, timeout : float): +def retrieve_crash_output(run_id, workspace, timeout): + # type (int, ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager, float) -> str """ returns the crash output string for the given test run. :param run_id: editor id that will be used for differentiating paths @@ -79,7 +89,8 @@ def retrieve_crash_output(run_id : int, workspace, timeout : float): crash_info += f"\n{str(ex)}" return crash_info -def cycle_crash_report(run_id : int, workspace): +def cycle_crash_report(run_id, workspace): + # type (int, ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager) -> None """ Attempts to rename error.log and error.dmp(crash files) into new names with the timestamp on it. :param run_id: editor id that will be used for differentiating paths @@ -99,10 +110,12 @@ def cycle_crash_report(run_id : int, workspace): except Exception as ex: logger.warning(f"Couldn't cycle file {filepath}. Error: {str(ex)}") -def retrieve_editor_log_content(run_id : int, log_name : str, workspace, timeout=10): +def retrieve_editor_log_content(run_id, log_name, workspace, timeout=10): + # type (int , str, ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager, int) -> str """ Retrieves the contents of the given editor log file. :param run_id: editor id that will be used for differentiating paths + :log_name: The name of the editor log to retrieve :param workspace: Workspace fixture :timeout: Maximum time to wait for the log file to appear :return str: The contents of the log @@ -124,7 +137,8 @@ def retrieve_editor_log_content(run_id : int, log_name : str, workspace, timeout editor_info = f"-- Error reading editor.log: {str(ex)} --" return editor_info -def retrieve_last_run_test_index_from_output(test_spec_list, output : str): +def retrieve_last_run_test_index_from_output(test_spec_list, output): + # type (list, str) -> int """ Finds out what was the last test that was run by inspecting the input. This is used for determining what was the batched test has crashed the editor diff --git a/Tools/LyTestTools/tests/unit/test_editor_test_utils.py b/Tools/LyTestTools/tests/unit/test_editor_test_utils.py new file mode 100644 index 0000000000..134d1e1ad8 --- /dev/null +++ b/Tools/LyTestTools/tests/unit/test_editor_test_utils.py @@ -0,0 +1,158 @@ +""" +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 +import os +import unittest.mock as mock +import unittest + +import ly_test_tools.o3de.editor_test_utils as editor_test_utils + +pytestmark = pytest.mark.SUITE_smoke + +class TestEditorTestUtils(unittest.TestCase): + + @mock.patch('ly_test_tools.environment.process_utils.kill_processes_named') + def test_KillAllLyProcesses_IncludeAP_CallsCorrectly(self, under_test): + process_list = ['Editor', 'Profiler', 'RemoteConsole', 'AssetProcessor', 'AssetProcessorBatch', 'AssetBuilder'] + + editor_test_utils.kill_all_ly_processes(include_asset_processor=True) + under_test.assert_called_once_with(process_list, ignore_extensions=True) + + @mock.patch('ly_test_tools.environment.process_utils.kill_processes_named') + def test_KillAllLyProcesses_NotIncludeAP_CallsCorrectly(self, under_test): + process_list = ['Editor', 'Profiler', 'RemoteConsole'] + + editor_test_utils.kill_all_ly_processes(include_asset_processor=False) + under_test.assert_called_once_with(process_list, ignore_extensions=True) + + def test_GetTestcaseModuleFilepath_NoExtension_ReturnsPYExtension(self): + mock_module = mock.MagicMock() + file_path = os.path.join('path', 'under_test') + mock_module.__file__ = file_path + + assert file_path + '.py' == editor_test_utils.get_testcase_module_filepath(mock_module) + + def test_GetTestcaseModuleFilepath_PYExtension_ReturnsPYExtension(self): + mock_module = mock.MagicMock() + file_path = os.path.join('path', 'under_test.py') + mock_module.__file__ = file_path + + assert file_path == editor_test_utils.get_testcase_module_filepath(mock_module) + + def test_GetModuleFilename_PythonModule_ReturnsFilename(self): + mock_module = mock.MagicMock() + file_path = os.path.join('path', 'under_test.py') + mock_module.__file__ = file_path + + assert 'under_test' == editor_test_utils.get_module_filename(mock_module) + + def test_RetrieveLogPath_NormalProject_ReturnsLogPath(self): + mock_workspace = mock.MagicMock() + mock_workspace.paths.project.return_value = 'mock_project_path' + expected = os.path.join('mock_project_path', 'user', 'log_test_0') + + assert expected == editor_test_utils.retrieve_log_path(0, mock_workspace) + + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock()) + def test_RetrieveCrashOutput_CrashLogExists_ReturnsLogInfo(self, mock_retrieve_log_path): + mock_retrieve_log_path.return_value = 'mock_log_path' + mock_workspace = mock.MagicMock() + mock_log = 'mock crash info' + + with mock.patch('builtins.open', mock.mock_open(read_data=mock_log)) as mock_file: + assert mock_log == editor_test_utils.retrieve_crash_output(0, mock_workspace, 0) + + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock()) + def test_RetrieveCrashOutput_CrashLogNotExists_ReturnsError(self, mock_retrieve_log_path): + mock_retrieve_log_path.return_value = 'mock_log_path' + mock_workspace = mock.MagicMock() + expected = "-- No crash log available --\n[Errno 2] No such file or directory: 'mock_log_path\\\\error.log'" + + assert expected == editor_test_utils.retrieve_crash_output(0, mock_workspace, 0) + + @mock.patch('os.rename') + @mock.patch('os.path.getmtime') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('os.path.exists') + def test_CycleCrashReport_LogExists_NamedCorrectly(self, mock_exists, mock_retrieve_log_path, mock_getmtime, + under_test): + mock_exists.side_effect = [True, False] + mock_retrieve_log_path.return_value = 'mock_log_path' + mock_workspace = mock.MagicMock() + mock_getmtime.return_value = 1 + + editor_test_utils.cycle_crash_report(0, mock_workspace) + under_test.assert_called_once_with(os.path.join('mock_log_path', 'error.log'), + os.path.join('mock_log_path', 'error_1969_12_31_16_00_01.log')) + + @mock.patch('os.rename') + @mock.patch('os.path.getmtime') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('os.path.exists') + def test_CycleCrashReport_DmpExists_NamedCorrectly(self, mock_exists, mock_retrieve_log_path, mock_getmtime, + under_test): + mock_exists.side_effect = [False, True] + mock_retrieve_log_path.return_value = 'mock_log_path' + mock_workspace = mock.MagicMock() + mock_getmtime.return_value = 1 + + editor_test_utils.cycle_crash_report(0, mock_workspace) + under_test.assert_called_once_with(os.path.join('mock_log_path', 'error.dmp'), + os.path.join('mock_log_path', 'error_1969_12_31_16_00_01.dmp')) + + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock()) + def test_RetrieveEditorLogContent_CrashLogExists_ReturnsLogInfo(self, mock_retrieve_log_path): + mock_retrieve_log_path.return_value = 'mock_log_path' + mock_logname = 'mock_log.log' + mock_workspace = mock.MagicMock() + mock_log = 'mock log info' + + with mock.patch('builtins.open', mock.mock_open(read_data=mock_log)) as mock_file: + assert f'[editor.log] {mock_log}' == editor_test_utils.retrieve_editor_log_content(0, mock_logname, mock_workspace) + + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock()) + def test_RetrieveEditorLogContent_CrashLogNotExists_ReturnsError(self, mock_retrieve_log_path): + mock_retrieve_log_path.return_value = 'mock_log_path' + mock_logname = 'mock_log.log' + mock_workspace = mock.MagicMock() + expected = f"-- Error reading editor.log: [Errno 2] No such file or directory: 'mock_log_path\\\\mock_log.log' --" + + assert expected == editor_test_utils.retrieve_editor_log_content(0, mock_logname, mock_workspace) + + def test_RetrieveLastRunTestIndexFromOutput_SecondTestFailed_Returns0(self): + mock_test = mock.MagicMock() + mock_test.__name__ = 'mock_test_name' + mock_test_list = [mock_test] + mock_editor_output = 'mock_test_name\n' \ + 'mock_test_name_1' + + assert 0 == editor_test_utils.retrieve_last_run_test_index_from_output(mock_test_list, mock_editor_output) + + def test_RetrieveLastRunTestIndexFromOutput_TenthTestFailed_Returns9(self): + mock_test_list = [] + mock_editor_output = '' + for x in range(10): + mock_test = mock.MagicMock() + mock_test.__name__ = f'mock_test_name_{x}' + mock_test_list.append(mock_test) + mock_editor_output += f'{mock_test.__name__}\n' + mock_editor_output += 'mock_test_name_x' + assert 9 == editor_test_utils.retrieve_last_run_test_index_from_output(mock_test_list, mock_editor_output) + + def test_RetrieveLastRunTestIndexFromOutput_FirstItemFailed_Returns0(self): + mock_test_list = [] + mock_editor_output = '' + for x in range(10): + mock_test = mock.MagicMock() + mock_test.__name__ = f'mock_test_name_{x}' + mock_test_list.append(mock_test) + + assert 0 == editor_test_utils.retrieve_last_run_test_index_from_output(mock_test_list, mock_editor_output) diff --git a/Tools/LyTestTools/tests/unit/test_fixtures.py b/Tools/LyTestTools/tests/unit/test_fixtures.py index 32dc204bd2..911e6fef91 100755 --- a/Tools/LyTestTools/tests/unit/test_fixtures.py +++ b/Tools/LyTestTools/tests/unit/test_fixtures.py @@ -369,3 +369,14 @@ class TestFixtures(object): mock_request.addfinalizer.call_args[0][0]() mock_stop.assert_called_once() + + @mock.patch('inspect.isclass', mock.MagicMock(return_value=True)) + def test_PytestPycollectMakeitem_ValidArgs_CallsCorrectly(self): + mock_collector = mock.MagicMock() + mock_name = mock.MagicMock() + mock_obj = mock.MagicMock() + mock_base = mock.MagicMock() + mock_obj.__bases__ = [mock_base] + + test_tools_fixtures.pytest_pycollect_makeitem(mock_collector, mock_name, mock_obj) + mock_base.pytest_custom_makeitem.assert_called_once_with(mock_collector, mock_name, mock_obj) diff --git a/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py b/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py new file mode 100644 index 0000000000..ef49934887 --- /dev/null +++ b/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py @@ -0,0 +1,1017 @@ +""" +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 unittest + +import pytest +import unittest.mock as mock + +import ly_test_tools +import ly_test_tools.o3de.editor_test as editor_test + +pytestmark = pytest.mark.SUITE_smoke + +class TestEditorTestBase(unittest.TestCase): + + def test_EditorSharedTest_Init_CorrectAttributes(self): + mock_editorsharedtest = editor_test.EditorSharedTest() + assert mock_editorsharedtest.is_batchable == True + assert mock_editorsharedtest.is_parallelizable == True + + def test_EditorParallelTest_Init_CorrectAttributes(self): + mock_editorsharedtest = editor_test.EditorParallelTest() + assert mock_editorsharedtest.is_batchable == False + assert mock_editorsharedtest.is_parallelizable == True + + def test_EditorBatchedTest_Init_CorrectAttributes(self): + mock_editorsharedtest = editor_test.EditorBatchedTest() + assert mock_editorsharedtest.is_batchable == True + assert mock_editorsharedtest.is_parallelizable == False + +class TestBase(unittest.TestCase): + + def setUp(self): + self.mock_result = editor_test.Result.Base() + + def test_GetOutputStr_HasOutput_ReturnsCorrectly(self): + self.mock_result.output = 'expected output' + assert self.mock_result.get_output_str() == 'expected output' + + def test_GetOutputStr_NoOutput_ReturnsCorrectly(self): + self.mock_result.output = None + assert self.mock_result.get_output_str() == '-- No output --' + + def test_GetEditorLogStr_HasOutput_ReturnsCorrectly(self): + self.mock_result.editor_log = 'expected log output' + assert self.mock_result.get_editor_log_str() == 'expected log output' + + def test_GetEditorLogStr_NoOutput_ReturnsCorrectly(self): + self.mock_result.editor_log = None + assert self.mock_result.get_editor_log_str() == '-- No editor log found --' + +class TestPass(unittest.TestCase): + + def test_Create_ValidArgs_CorrectAttributes(self): + mock_test_spec = mock.MagicMock() + mock_output = mock.MagicMock() + mock_editor_log = mock.MagicMock() + + mock_pass = editor_test.Result.Pass.create(mock_test_spec, mock_output, mock_editor_log) + assert mock_pass.test_spec == mock_test_spec + assert mock_pass.output == mock_output + assert mock_pass.editor_log == mock_editor_log + + def test_Str_ValidString_ReturnsOutput(self): + mock_test_spec = mock.MagicMock() + mock_output = 'mock_output' + mock_editor_log = mock.MagicMock() + expected = f"Test Passed\n"\ + f"------------\n"\ + f"| Output |\n"\ + f"------------\n"\ + f"{mock_output}\n" + + mock_pass = editor_test.Result.Pass.create(mock_test_spec, mock_output, mock_editor_log) + assert str(mock_pass) == expected + +class TestFail(unittest.TestCase): + + def test_Create_ValidArgs_CorrectAttributes(self): + mock_test_spec = mock.MagicMock() + mock_output = mock.MagicMock() + mock_editor_log = mock.MagicMock() + + mock_pass = editor_test.Result.Fail.create(mock_test_spec, mock_output, mock_editor_log) + assert mock_pass.test_spec == mock_test_spec + assert mock_pass.output == mock_output + assert mock_pass.editor_log == mock_editor_log + + def test_Str_ValidString_ReturnsOutput(self): + mock_test_spec = mock.MagicMock() + mock_output = 'mock_output' + mock_editor_log = 'mock_editor_log' + expected = f"Test FAILED\n"\ + f"------------\n"\ + f"| Output |\n"\ + f"------------\n"\ + f"{mock_output}\n"\ + f"--------------\n"\ + f"| Editor log |\n"\ + f"--------------\n"\ + f"{mock_editor_log}\n" + + mock_pass = editor_test.Result.Fail.create(mock_test_spec, mock_output, mock_editor_log) + assert str(mock_pass) == expected + +class TestCrash(unittest.TestCase): + + def test_Create_ValidArgs_CorrectAttributes(self): + mock_test_spec = mock.MagicMock() + mock_output = mock.MagicMock() + mock_editor_log = mock.MagicMock() + mock_ret_code = mock.MagicMock() + mock_stacktrace = mock.MagicMock() + + mock_pass = editor_test.Result.Crash.create(mock_test_spec, mock_output, mock_ret_code, mock_stacktrace, + mock_editor_log) + assert mock_pass.test_spec == mock_test_spec + assert mock_pass.output == mock_output + assert mock_pass.editor_log == mock_editor_log + assert mock_pass.ret_code == mock_ret_code + assert mock_pass.stacktrace == mock_stacktrace + + def test_Str_ValidString_ReturnsOutput(self): + mock_test_spec = mock.MagicMock() + mock_output = 'mock_output' + mock_editor_log = 'mock_editor_log' + mock_return_code = 0 + mock_stacktrace = 'mock stacktrace' + expected = f"Test CRASHED, return code {hex(mock_return_code)}\n"\ + f"---------------\n"\ + f"| Stacktrace |\n"\ + f"---------------\n"\ + f"{mock_stacktrace}"\ + f"------------\n" \ + f"| Output |\n" \ + f"------------\n" \ + f"{mock_output}\n" \ + f"--------------\n" \ + f"| Editor log |\n" \ + f"--------------\n" \ + f"{mock_editor_log}\n" + + mock_pass = editor_test.Result.Crash.create(mock_test_spec, mock_output, mock_return_code, mock_stacktrace, + mock_editor_log) + assert str(mock_pass) == expected + + def test_Str_MissingStackTrace_ReturnsCorrectly(self): + mock_test_spec = mock.MagicMock() + mock_output = 'mock_output' + mock_editor_log = 'mock_editor_log' + mock_return_code = 0 + mock_stacktrace = None + expected = f"Test CRASHED, return code {hex(mock_return_code)}\n"\ + f"---------------\n"\ + f"| Stacktrace |\n"\ + f"---------------\n"\ + f"-- No stacktrace data found --\n"\ + f"------------\n" \ + f"| Output |\n" \ + f"------------\n" \ + f"{mock_output}\n" \ + f"--------------\n" \ + f"| Editor log |\n" \ + f"--------------\n" \ + f"{mock_editor_log}\n" + + mock_pass = editor_test.Result.Crash.create(mock_test_spec, mock_output, mock_return_code, mock_stacktrace, + mock_editor_log) + assert str(mock_pass) == expected + +class Timeout(unittest.TestCase): + + def test_Create_ValidArgs_CorrectAttributes(self): + mock_test_spec = mock.MagicMock() + mock_output = mock.MagicMock() + mock_editor_log = mock.MagicMock() + mock_timeout = mock.MagicMock() + + mock_pass = editor_test.Result.Timeout.create(mock_test_spec, mock_output, mock_timeout, mock_editor_log) + assert mock_pass.test_spec == mock_test_spec + assert mock_pass.output == mock_output + assert mock_pass.editor_log == mock_editor_log + assert mock_pass.time_secs == mock_timeout + + def test_Str_ValidString_ReturnsOutput(self): + mock_test_spec = mock.MagicMock() + mock_output = 'mock_output' + mock_editor_log = 'mock_editor_log' + mock_timeout = 0 + expected = f"Test TIMED OUT after {mock_timeout} seconds\n"\ + f"------------\n" \ + f"| Output |\n" \ + f"------------\n" \ + f"{mock_output}\n" \ + f"--------------\n" \ + f"| Editor log |\n" \ + f"--------------\n" \ + f"{mock_editor_log}\n" + + mock_pass = editor_test.Result.Timeout.create(mock_test_spec, mock_output, mock_timeout, mock_editor_log) + assert str(mock_pass) == expected + +class Unknown(unittest.TestCase): + + def test_Create_ValidArgs_CorrectAttributes(self): + mock_test_spec = mock.MagicMock() + mock_output = mock.MagicMock() + mock_editor_log = mock.MagicMock() + mock_extra_info = mock.MagicMock() + + mock_pass = editor_test.Result.Unknown.create(mock_test_spec, mock_output, mock_extra_info, mock_editor_log) + assert mock_pass.test_spec == mock_test_spec + assert mock_pass.output == mock_output + assert mock_pass.editor_log == mock_editor_log + assert mock_pass.extra_info == mock_extra_info + + def test_Str_ValidString_ReturnsOutput(self): + mock_test_spec = mock.MagicMock() + mock_output = 'mock_output' + mock_editor_log = 'mock_editor_log' + mock_extra_info = 'mock extra info' + expected = f"Unknown test result, possible cause: {mock_extra_info}\n"\ + f"------------\n" \ + f"| Output |\n" \ + f"------------\n" \ + f"{mock_output}\n" \ + f"--------------\n" \ + f"| Editor log |\n" \ + f"--------------\n" \ + f"{mock_editor_log}\n" + + mock_pass = editor_test.Result.Unknown.create(mock_test_spec, mock_output, mock_extra_info, mock_editor_log) + assert str(mock_pass) == expected + +class TestEditorTestSuite(unittest.TestCase): + + @mock.patch('ly_test_tools.o3de.editor_test_utils.kill_all_ly_processes') + def test_EditorTestData_ValidAP_TeardownProperly(self, mock_kill_processes): + mock_editor_test_suite = editor_test.EditorTestSuite() + mock_test_data_generator = mock_editor_test_suite._editor_test_data(mock.MagicMock()) + mock_asset_processor = mock.MagicMock() + for test_data in mock_test_data_generator: + test_data.asset_processor = mock_asset_processor + mock_asset_processor.stop.assert_called_once_with(1) + mock_asset_processor.teardown.assert_called() + assert test_data.asset_processor is None + mock_kill_processes.assert_called_once_with(include_asset_processor=True) + + @mock.patch('ly_test_tools.o3de.editor_test_utils.kill_all_ly_processes') + def test_EditorTestData_NoAP_TeardownProperly(self, mock_kill_processes): + mock_editor_test_suite = editor_test.EditorTestSuite() + mock_test_data_generator = mock_editor_test_suite._editor_test_data(mock.MagicMock()) + for test_data in mock_test_data_generator: + test_data.asset_processor = None + mock_kill_processes.assert_called_once_with(include_asset_processor=False) + + def test_RunnerInit_ValidArgs_InitProperly(self): + mock_name = mock.MagicMock() + mock_func = mock.MagicMock() + mock_tests = mock.MagicMock() + + mock_runner = editor_test.EditorTestSuite.Runner(mock_name, mock_func, mock_tests) + mock_runner.name = mock_name + mock_runner.func = mock_func + mock_runner.tests = mock_tests + mock_runner.run_pytestfunc = None + mock_runner.result_pytestfuncs = [] + + def test_PytestCustomMakeitem_Called_ReturnsClass(self): + mock_test_class = editor_test.EditorTestSuite.pytest_custom_makeitem(mock.MagicMock(), mock.MagicMock(), + mock.MagicMock()) + assert isinstance(mock_test_class, editor_test.EditorTestSuite.EditorTestClass) + + def test_PytestCustomModifyItems(self): + pass + + def test_GetSingleTests_NoSingleTests_EmptyList(self): + class MockTestSuite(editor_test.EditorTestSuite): + pass + mock_test_suite = MockTestSuite() + tests = mock_test_suite.get_single_tests() + assert len(tests) == 0 + + def test_GetSingleTests_OneSingleTests_ReturnsOne(self): + class MockTestSuite(editor_test.EditorTestSuite): + class MockSingleTest(editor_test.EditorSingleTest): + pass + mock_test_suite = MockTestSuite() + tests = mock_test_suite.get_single_tests() + assert len(tests) == 1 + + + def test_GetSingleTests_AllTests_ReturnsOnlySingles(self): + class MockTestSuite(editor_test.EditorTestSuite): + class MockSingleTest(editor_test.EditorSingleTest): + pass + class MockAnotherSingleTest(editor_test.EditorSingleTest): + pass + class MockNotSingleTest(editor_test.EditorSharedTest): + pass + mock_test_suite = MockTestSuite() + tests = mock_test_suite.get_single_tests() + assert len(tests) == 2 + + def test_GetSharedTests_NoSharedTests_EmptyList(self): + class MockTestSuite(editor_test.EditorTestSuite): + pass + mock_test_suite = MockTestSuite() + tests = mock_test_suite.get_shared_tests() + assert len(tests) == 0 + + def test_GetSharedTests_OneSharedTests_ReturnsOne(self): + class MockTestSuite(editor_test.EditorTestSuite): + class MockSharedTest(editor_test.EditorSharedTest): + pass + mock_test_suite = MockTestSuite() + tests = mock_test_suite.get_shared_tests() + assert len(tests) == 1 + + def test_GetSharedTests_AllTests_ReturnsOnlyShared(self): + class MockTestSuite(editor_test.EditorTestSuite): + class MockSharedTest(editor_test.EditorSharedTest): + pass + class MockAnotherSharedTest(editor_test.EditorSharedTest): + pass + class MockNotSharedTest(editor_test.EditorSingleTest): + pass + mock_test_suite = MockTestSuite() + tests = mock_test_suite.get_shared_tests() + assert len(tests) == 2 + + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite.filter_session_shared_tests') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite.get_shared_tests') + def test_GetSessionSharedTests_Valid_CallsCorrectly(self, mock_get_shared_tests, mock_filter_session): + editor_test.EditorTestSuite.get_session_shared_tests(mock.MagicMock()) + assert mock_get_shared_tests.called + assert mock_filter_session.called + + @mock.patch('ly_test_tools.o3de.editor_test.skipping_pytest_runtest_setup', mock.MagicMock()) + def test_FilterSessionSharedTests_OneSharedTest_ReturnsOne(self): + def mock_test(): + pass + mock_session_items = mock.MagicMock() + mock_shared_tests = mock.MagicMock() + mock_test.originalname = 'mock_test' + mock_test.__name__ = mock_test.originalname + mock_session_items = [mock_test] + mock_shared_tests = [mock_test] + + selected_tests = editor_test.EditorTestSuite.filter_session_shared_tests(mock_session_items, mock_shared_tests) + assert selected_tests == mock_session_items + + @mock.patch('ly_test_tools.o3de.editor_test.skipping_pytest_runtest_setup', mock.MagicMock()) + def test_FilterSessionSharedTests_ManyTests_ReturnsCorrectTests(self): + def mock_test(): + pass + def mock_test_2(): + pass + def mock_test_3(): + pass + mock_session_items = mock.MagicMock() + mock_shared_tests = mock.MagicMock() + mock_test.originalname = 'mock_test' + mock_test.__name__ = mock_test.originalname + mock_test_2.originalname = 'mock_test_2' + mock_test_2.__name__ = mock_test_2.originalname + mock_test_3.originalname = 'mock_test_3' + mock_test_3.__name__ = mock_test_3.originalname + mock_session_items = [mock_test, mock_test_2] + mock_shared_tests = [mock_test, mock_test_2, mock_test_3] + + selected_tests = editor_test.EditorTestSuite.filter_session_shared_tests(mock_session_items, mock_shared_tests) + assert selected_tests == mock_session_items + + @mock.patch('ly_test_tools.o3de.editor_test.skipping_pytest_runtest_setup', mock.MagicMock(side_effect=Exception)) + def test_FilterSessionSharedTests_SkippingPytestRaises_SkipsAddingTest(self): + def mock_test(): + pass + mock_session_items = mock.MagicMock() + mock_shared_tests = mock.MagicMock() + mock_test.originalname = 'mock_test' + mock_test.__name__ = mock_test.originalname + mock_session_items = [mock_test] + mock_shared_tests = [mock_test] + + selected_tests = editor_test.EditorTestSuite.filter_session_shared_tests(mock_session_items, mock_shared_tests) + assert len(selected_tests) == 0 + + def test_FilterSharedTests_TrueParams_ReturnsTrueTests(self): + mock_test = mock.MagicMock() + mock_test.is_batchable = True + mock_test.is_parallelizable = True + mock_test_2 = mock.MagicMock() + mock_test_2.is_batchable = False + mock_test_2.is_parallelizable = False + mock_shared_tests = [mock_test, mock_test_2] + + filtered_tests = editor_test.EditorTestSuite.filter_shared_tests(mock_shared_tests, True, True) + assert filtered_tests == [mock_test] + + def test_FilterSharedTests_FalseParams_ReturnsFalseTests(self): + mock_test = mock.MagicMock() + mock_test.is_batchable = True + mock_test.is_parallelizable = True + mock_test_2 = mock.MagicMock() + mock_test_2.is_batchable = False + mock_test_2.is_parallelizable = False + mock_shared_tests = [mock_test, mock_test_2] + + filtered_tests = editor_test.EditorTestSuite.filter_shared_tests(mock_shared_tests, False, False) + assert filtered_tests == [mock_test_2] + +class TestUtils(unittest.TestCase): + + @mock.patch('ly_test_tools.o3de.editor_test_utils.kill_all_ly_processes') + def test_PrepareAssetProcessor_APExists_StartsAP(self, mock_kill_processes): + mock_test_suite = editor_test.EditorTestSuite() + mock_workspace = mock.MagicMock() + mock_editor_data = mock.MagicMock() + mock_ap = mock.MagicMock() + mock_editor_data.asset_processor = mock_ap + + mock_test_suite._prepare_asset_processor(mock_workspace, mock_editor_data) + assert mock_ap.start.called + assert not mock_kill_processes.called + + @mock.patch('ly_test_tools.o3de.asset_processor.AssetProcessor.start') + @mock.patch('ly_test_tools.environment.process_utils.process_exists') + @mock.patch('ly_test_tools.o3de.editor_test_utils.kill_all_ly_processes') + def test_PrepareAssetProcessor_NoAP_KillAndCreateAP(self, mock_kill_processes, mock_proc_exists, mock_start): + mock_test_suite = editor_test.EditorTestSuite() + mock_workspace = mock.MagicMock() + mock_editor_data = mock.MagicMock() + mock_editor_data.asset_processor = None + mock_proc_exists.return_value = False + + mock_test_suite._prepare_asset_processor(mock_workspace, mock_editor_data) + mock_kill_processes.assert_called_with(include_asset_processor=True) + assert isinstance(mock_editor_data.asset_processor, ly_test_tools.o3de.asset_processor.AssetProcessor) + assert mock_start.called + + @mock.patch('ly_test_tools.o3de.asset_processor.AssetProcessor.start') + @mock.patch('ly_test_tools.environment.process_utils.process_exists') + @mock.patch('ly_test_tools.o3de.editor_test_utils.kill_all_ly_processes') + def test_PrepareAssetProcessor_NoAPButProcExists_NoKill(self, mock_kill_processes, mock_proc_exists, mock_start): + mock_test_suite = editor_test.EditorTestSuite() + mock_workspace = mock.MagicMock() + mock_editor_data = mock.MagicMock() + mock_editor_data.asset_processor = None + mock_proc_exists.return_value = True + + mock_test_suite._prepare_asset_processor(mock_workspace, mock_editor_data) + mock_kill_processes.assert_called_with(include_asset_processor=False) + assert not mock_start.called + assert mock_editor_data.asset_processor is None + + + @mock.patch('ly_test_tools.o3de.asset_processor.AssetProcessor.start') + @mock.patch('ly_test_tools.environment.process_utils.process_exists') + @mock.patch('ly_test_tools.o3de.editor_test_utils.kill_all_ly_processes') + def test_PrepareAssetProcessor_NoAPButProcExists_NoKill(self, mock_kill_processes, mock_proc_exists, mock_start): + mock_test_suite = editor_test.EditorTestSuite() + mock_workspace = mock.MagicMock() + mock_editor_data = mock.MagicMock() + mock_editor_data.asset_processor = None + mock_proc_exists.return_value = True + + mock_test_suite._prepare_asset_processor(mock_workspace, mock_editor_data) + mock_kill_processes.assert_called_with(include_asset_processor=False) + assert not mock_start.called + assert mock_editor_data.asset_processor is None + + @mock.patch('ly_test_tools.o3de.editor_test_utils.kill_all_ly_processes') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._prepare_asset_processor') + def test_SetupEditorTest_ValidArgs_CallsCorrectly(self, mock_prepare_ap, mock_kill_processes): + mock_test_suite = editor_test.EditorTestSuite() + mock_editor = mock.MagicMock() + mock_test_suite._setup_editor_test(mock_editor, mock.MagicMock(), mock.MagicMock()) + + assert mock_editor.configure_settings.called + assert mock_prepare_ap.called + mock_kill_processes.assert_called_once_with(include_asset_processor=False) + + @mock.patch('ly_test_tools.o3de.editor_test.Result.Pass.create') + @mock.patch('ly_test_tools.o3de.editor_test_utils.get_module_filename') + def test_GetResultsUsingOutput_ValidJsonSuccess_CreatesPassResult(self, mock_get_module, mock_create): + mock_get_module.return_value = 'mock_module_name' + mock_test_suite = editor_test.EditorTestSuite() + mock_test = mock.MagicMock() + mock_test.__name__ = 'mock_test_name' + mock_test_list = [mock_test] + mock_output = 'JSON_START(' \ + '{"name": "mock_module_name", "output": "mock_std_out", "success": "mock_success_data"}' \ + ')JSON_END' + mock_editor_log = 'JSON_START(' \ + ')JSON_END' + + results = mock_test_suite._get_results_using_output(mock_test_list, mock_output, mock_editor_log) + assert mock_create.called + assert len(results) == 1 + + @mock.patch('ly_test_tools.o3de.editor_test.Result.Fail.create') + @mock.patch('ly_test_tools.o3de.editor_test_utils.get_module_filename') + def test_GetResultsUsingOutput_ValidJsonFail_CreatesFailResult(self, mock_get_module, mock_create): + mock_get_module.return_value = 'mock_module_name' + mock_test_suite = editor_test.EditorTestSuite() + mock_test = mock.MagicMock() + mock_test.__name__ = 'mock_test_name' + mock_test_list = [mock_test] + mock_output = 'JSON_START(' \ + '{"name": "mock_module_name", "output": "mock_std_out", "failed": "mock_fail_data"}' \ + ')JSON_END' + mock_editor_log = 'JSON_START(' \ + ')JSON_END' + + results = mock_test_suite._get_results_using_output(mock_test_list, mock_output, mock_editor_log) + assert mock_create.called + assert len(results) == 1 + + @mock.patch('ly_test_tools.o3de.editor_test.Result.Unknown.create') + @mock.patch('ly_test_tools.o3de.editor_test_utils.get_module_filename') + def test_GetResultsUsingOutput_ModuleNotInLog_CreatesUnknownResult(self, mock_get_module, mock_create): + mock_get_module.return_value = 'different_module_name' + mock_test_suite = editor_test.EditorTestSuite() + mock_test = mock.MagicMock() + mock_test.__name__ = 'mock_test_name' + mock_test_list = [mock_test] + mock_output = 'JSON_START(' \ + '{"name": "mock_module_name", "output": "mock_std_out", "failed": "mock_fail_data"}' \ + ')JSON_END' + mock_editor_log = 'JSON_START(' \ + ')JSON_END' + + results = mock_test_suite._get_results_using_output(mock_test_list, mock_output, mock_editor_log) + assert mock_create.called + assert len(results) == 1 + + @mock.patch('ly_test_tools.o3de.editor_test.Result.Pass.create') + @mock.patch('ly_test_tools.o3de.editor_test.Result.Fail.create') + @mock.patch('ly_test_tools.o3de.editor_test.Result.Unknown.create') + @mock.patch('ly_test_tools.o3de.editor_test_utils.get_module_filename') + def test_GetResultsUsingOutput_MultipleTests_CreatesCorrectResults(self, mock_get_module, mock_create_unknown, + mock_create_fail, mock_create_pass): + mock_get_module.side_effect = ['mock_module_name_pass', 'mock_module_name_fail', 'different_module_name'] + mock_test_suite = editor_test.EditorTestSuite() + mock_test_pass = mock.MagicMock() + mock_test_pass.__name__ = 'mock_test_name_pass' + mock_test_fail = mock.MagicMock() + mock_test_fail.__name__ = 'mock_test_name_fail' + mock_test_unknown = mock.MagicMock() + mock_test_unknown.__name__ = 'mock_test_name_unknown' + mock_test_list = [mock_test_pass, mock_test_fail, mock_test_unknown] + mock_output = 'JSON_START(' \ + '{"name": "mock_module_name_pass", "output": "mock_std_out", "success": "mock_success_data"}' \ + ')JSON_END' \ + 'JSON_START(' \ + '{"name": "mock_module_name_fail", "output": "mock_std_out", "failed": "mock_fail_data"}' \ + ')JSON_END' \ + 'JSON_START(' \ + '{"name": "mock_module_name_unknown", "output": "mock_std_out", "failed": "mock_fail_data"}' \ + ')JSON_END' + mock_editor_log = 'JSON_START(' \ + '{"name": "mock_module_name_pass"}' \ + ')JSON_END' \ + 'JSON_START(' \ + '{"name": "mock_module_name_fail"}' \ + ')JSON_END' \ + + results = mock_test_suite._get_results_using_output(mock_test_list, mock_output, mock_editor_log) + mock_create_pass.assert_called_with( + mock_test_pass, 'mock_std_out', 'JSON_START({"name": "mock_module_name_pass"})JSON_END') + mock_create_fail.assert_called_with( + mock_test_fail, 'mock_std_out', 'JSON_START({"name": "mock_module_name_fail"})JSON_END') + mock_create_unknown.assert_called_with( + mock_test_unknown, mock_output, "Couldn't find any test run information on stdout", mock_editor_log) + assert len(results) == 3 + + @mock.patch('builtins.print') + def test_ReportResult_TestPassed_ReportsCorrectly(self, mock_print): + mock_test_name = 'mock name' + mock_pass = ly_test_tools.o3de.editor_test.Result.Pass() + ly_test_tools.o3de.editor_test.EditorTestSuite._report_result(mock_test_name, mock_pass) + mock_print.assert_called_with(f'Test {mock_test_name}:\nTest Passed\n------------\n| Output |\n------------\n' + f'-- No output --\n') + + @mock.patch('pytest.fail') + def test_ReportResult_TestFailed_FailsCorrectly(self, mock_pytest_fail): + mock_fail = ly_test_tools.o3de.editor_test.Result.Fail() + + ly_test_tools.o3de.editor_test.EditorTestSuite._report_result('mock_test_name', mock_fail) + mock_pytest_fail.assert_called_with('Test mock_test_name:\nTest FAILED\n------------\n| Output |' + '\n------------\n-- No output --\n--------------\n| Editor log |' + '\n--------------\n-- No editor log found --\n') + +class TestRunningTests(unittest.TestCase): + + @mock.patch('ly_test_tools.o3de.editor_test.Result.Pass.create') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_results_using_output') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_editor_log_content') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') + @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + def test_ExecEditorTest_TestSucceeds_ReturnsPass(self, mock_cycle_crash, mock_get_testcase_filepath, + mock_retrieve_log, mock_retrieve_editor_log, + mock_get_output_results, mock_create): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_workspace = mock.MagicMock() + mock_editor = mock.MagicMock() + mock_test_spec = mock.MagicMock() + mock_test_spec.__name__ = 'mock_test_name' + mock_editor.get_returncode.return_value = 0 + mock_get_output_results.return_value = {} + mock_pass = mock.MagicMock() + mock_create.return_value = mock_pass + + results = mock_test_suite._exec_editor_test(mock.MagicMock(), mock_workspace, mock_editor, 0, + 'mock_log_name', mock_test_spec, []) + assert mock_cycle_crash.called + assert mock_editor.start.called + assert mock_create.called + assert results == {mock_test_spec.__name__: mock_pass} + + @mock.patch('ly_test_tools.o3de.editor_test.Result.Fail.create') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_results_using_output') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_editor_log_content') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') + @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + def test_ExecEditorTest_TestFails_ReturnsFail(self, mock_cycle_crash, mock_get_testcase_filepath, + mock_retrieve_log, mock_retrieve_editor_log, + mock_get_output_results, mock_create): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_workspace = mock.MagicMock() + mock_editor = mock.MagicMock() + mock_test_spec = mock.MagicMock() + mock_test_spec.__name__ = 'mock_test_name' + mock_editor.get_returncode.return_value = 15 + mock_get_output_results.return_value = {} + mock_fail = mock.MagicMock() + mock_create.return_value = mock_fail + + results = mock_test_suite._exec_editor_test(mock.MagicMock(), mock_workspace, mock_editor, 0, + 'mock_log_name', mock_test_spec, []) + assert mock_cycle_crash.called + assert mock_editor.start.called + assert mock_create.called + assert results == {mock_test_spec.__name__: mock_fail} + + @mock.patch('ly_test_tools.o3de.editor_test.Result.Crash.create') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_crash_output') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_results_using_output') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_editor_log_content') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') + @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + def test_ExecEditorTest_TestCrashes_ReturnsCrash(self, mock_cycle_crash, mock_get_testcase_filepath, + mock_retrieve_log, mock_retrieve_editor_log, + mock_get_output_results, mock_retrieve_crash, mock_create): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_workspace = mock.MagicMock() + mock_editor = mock.MagicMock() + mock_test_spec = mock.MagicMock() + mock_test_spec.__name__ = 'mock_test_name' + mock_editor.get_returncode.return_value = 1 + mock_get_output_results.return_value = {} + mock_crash = mock.MagicMock() + mock_create.return_value = mock_crash + + results = mock_test_suite._exec_editor_test(mock.MagicMock(), mock_workspace, mock_editor, 0, + 'mock_log_name', mock_test_spec, []) + assert mock_cycle_crash.call_count == 2 + assert mock_editor.start.called + assert mock_retrieve_crash.called + assert mock_create.called + assert results == {mock_test_spec.__name__: mock_crash} + + @mock.patch('ly_test_tools.o3de.editor_test.Result.Timeout.create') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_results_using_output') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_editor_log_content') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') + @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + def test_ExecEditorTest_TestTimeout_ReturnsTimeout(self, mock_cycle_crash, mock_get_testcase_filepath, + mock_retrieve_log, mock_retrieve_editor_log, + mock_get_output_results, mock_create): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_workspace = mock.MagicMock() + mock_editor = mock.MagicMock() + mock_test_spec = mock.MagicMock() + mock_test_spec.__name__ = 'mock_test_name' + mock_editor.wait.side_effect = ly_test_tools.launchers.exceptions.WaitTimeoutError() + mock_get_output_results.return_value = {} + mock_timeout = mock.MagicMock() + mock_create.return_value = mock_timeout + + results = mock_test_suite._exec_editor_test(mock.MagicMock(), mock_workspace, mock_editor, 0, + 'mock_log_name', mock_test_spec, []) + assert mock_cycle_crash.called + assert mock_editor.start.called + assert mock_editor.kill.called + assert mock_create.called + assert results == {mock_test_spec.__name__: mock_timeout} + + @mock.patch('ly_test_tools.o3de.editor_test.Result.Pass.create') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_editor_log_content') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') + @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + def test_ExecEditorMultitest_AllTestsPass_ReturnsPasses(self, mock_cycle_crash, mock_get_testcase_filepath, + mock_retrieve_log, mock_retrieve_editor_log, mock_create): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_workspace = mock.MagicMock() + mock_editor = mock.MagicMock() + mock_editor.get_returncode.return_value = 0 + mock_test_spec = mock.MagicMock() + mock_test_spec.__name__ = 'mock_test_name' + mock_test_spec_2 = mock.MagicMock() + mock_test_spec_2.__name__ = 'mock_test_name_2' + mock_test_spec_list = [mock_test_spec, mock_test_spec_2] + mock_get_testcase_filepath.side_effect = ['mock_path', 'mock_path_2'] + mock_pass = mock.MagicMock() + mock_pass_2 = mock.MagicMock() + mock_create.side_effect = [mock_pass, mock_pass_2] + + results = mock_test_suite._exec_editor_multitest(mock.MagicMock(), mock_workspace, mock_editor, 0, + 'mock_log_name', mock_test_spec_list, []) + assert results == {mock_test_spec.__name__: mock_pass, mock_test_spec_2.__name__: mock_pass_2} + assert mock_cycle_crash.called + assert mock_create.call_count == 2 + + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_results_using_output') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_editor_log_content') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') + @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + def test_ExecEditorMultitest_OneFailure_CallsCorrectFunc(self, mock_cycle_crash, mock_get_testcase_filepath, + mock_retrieve_log, mock_retrieve_editor_log, mock_get_results): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_workspace = mock.MagicMock() + mock_editor = mock.MagicMock() + mock_editor.get_returncode.return_value = 15 + mock_test_spec = mock.MagicMock() + mock_test_spec_2 = mock.MagicMock() + mock_test_spec_list = [mock_test_spec, mock_test_spec_2] + mock_get_testcase_filepath.side_effect = ['mock_path', 'mock_path_2'] + mock_get_results.return_value = {'mock_test_name': mock.MagicMock(), 'mock_test_name_2': mock.MagicMock()} + + results = mock_test_suite._exec_editor_multitest(mock.MagicMock(), mock_workspace, mock_editor, 0, + 'mock_log_name', mock_test_spec_list, []) + assert mock_cycle_crash.called + assert mock_get_results.called + + @mock.patch('ly_test_tools.o3de.editor_test.Result.Crash.create') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_crash_output') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_results_using_output') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_editor_log_content') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') + @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + def test_ExecEditorMultitest_OneCrash_ReportsOnUnknownResult(self, mock_cycle_crash, mock_get_testcase_filepath, + mock_retrieve_log, mock_retrieve_editor_log, + mock_get_results, mock_retrieve_crash, mock_create): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_workspace = mock.MagicMock() + mock_editor = mock.MagicMock() + mock_editor.get_returncode.return_value = 1 + mock_test_spec = mock.MagicMock() + mock_test_spec.__name__ = 'mock_test_name' + mock_test_spec_2 = mock.MagicMock() + mock_test_spec_2.__name__ = 'mock_test_name_2' + mock_test_spec_list = [mock_test_spec, mock_test_spec_2] + mock_unknown_result = ly_test_tools.o3de.editor_test.Result.Unknown() + mock_unknown_result.test_spec = mock.MagicMock() + mock_unknown_result.editor_log = mock.MagicMock() + mock_get_testcase_filepath.side_effect = ['mock_path', 'mock_path_2'] + mock_get_results.return_value = {mock_test_spec.__name__: mock_unknown_result, + mock_test_spec_2.__name__: mock.MagicMock()} + mock_crash = mock.MagicMock() + mock_create.return_value = mock_crash + + results = mock_test_suite._exec_editor_multitest(mock.MagicMock(), mock_workspace, mock_editor, 0, + 'mock_log_name', mock_test_spec_list, []) + assert mock_cycle_crash.call_count == 2 + assert mock_get_results.called + assert results[mock_test_spec.__name__] == mock_crash + + @mock.patch('ly_test_tools.o3de.editor_test.Result.Crash.create') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_crash_output') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_results_using_output') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_editor_log_content') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') + @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + def test_ExecEditorMultitest_ManyUnknown_ReportsUnknownResults(self, mock_cycle_crash, mock_get_testcase_filepath, + mock_retrieve_log, mock_retrieve_editor_log, + mock_get_results, mock_retrieve_crash, mock_create): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_workspace = mock.MagicMock() + mock_editor = mock.MagicMock() + mock_editor.get_returncode.return_value = 1 + mock_test_spec = mock.MagicMock() + mock_test_spec.__name__ = 'mock_test_name' + mock_test_spec_2 = mock.MagicMock() + mock_test_spec_2.__name__ = 'mock_test_name_2' + mock_test_spec_list = [mock_test_spec, mock_test_spec_2] + mock_unknown_result = ly_test_tools.o3de.editor_test.Result.Unknown() + mock_unknown_result.__name__ = 'mock_test_name' + mock_unknown_result.test_spec = mock.MagicMock() + mock_unknown_result.test_spec.__name__ = 'mock_test_spec_name' + mock_unknown_result.editor_log = mock.MagicMock() + mock_get_testcase_filepath.side_effect = ['mock_path', 'mock_path_2'] + mock_get_results.return_value = {mock_test_spec.__name__: mock_unknown_result, + mock_test_spec_2.__name__: mock_unknown_result} + mock_crash = mock.MagicMock() + mock_create.return_value = mock_crash + + results = mock_test_suite._exec_editor_multitest(mock.MagicMock(), mock_workspace, mock_editor, 0, + 'mock_log_name', mock_test_spec_list, []) + assert mock_cycle_crash.call_count == 2 + assert mock_get_results.called + assert results[mock_test_spec.__name__] == mock_crash + assert results[mock_test_spec_2.__name__].extra_info + + @mock.patch('ly_test_tools.o3de.editor_test.Result.Timeout.create') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_results_using_output') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_editor_log_content') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') + @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + def test_ExecEditorMultitest_EditorTimeout_ReportsCorrectly(self, mock_cycle_crash, mock_get_testcase_filepath, + mock_retrieve_log, mock_retrieve_editor_log, + mock_get_results, mock_create): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_workspace = mock.MagicMock() + mock_editor = mock.MagicMock() + mock_editor.wait.side_effect = ly_test_tools.launchers.exceptions.WaitTimeoutError() + mock_test_spec = mock.MagicMock() + mock_test_spec.__name__ = 'mock_test_name' + mock_test_spec_2 = mock.MagicMock() + mock_test_spec_2.__name__ = 'mock_test_name_2' + mock_test_spec_list = [mock_test_spec, mock_test_spec_2] + mock_unknown_result = ly_test_tools.o3de.editor_test.Result.Unknown() + mock_unknown_result.test_spec = mock.MagicMock() + mock_unknown_result.test_spec.__name__ = 'mock_test_spec_name' + mock_unknown_result.output = mock.MagicMock() + mock_unknown_result.editor_log = mock.MagicMock() + mock_get_testcase_filepath.side_effect = ['mock_path', 'mock_path_2'] + mock_get_results.return_value = {mock_test_spec.__name__: mock_unknown_result, + mock_test_spec_2.__name__: mock_unknown_result} + mock_timeout = mock.MagicMock() + mock_create.return_value = mock_timeout + + results = mock_test_suite._exec_editor_multitest(mock.MagicMock(), mock_workspace, mock_editor, 0, + 'mock_log_name', mock_test_spec_list, []) + assert mock_cycle_crash.called + assert mock_get_results.called + assert results[mock_test_spec_2.__name__].extra_info + assert results[mock_test_spec.__name__] == mock_timeout + + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._report_result') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._exec_editor_test') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._setup_editor_test') + def test_RunSingleTest_ValidTest_ReportsResults(self, mock_setup_test, mock_exec_editor_test, mock_report_result): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_test_data = mock.MagicMock() + mock_test_spec = mock.MagicMock() + mock_result = mock.MagicMock() + mock_test_name = 'mock_test_result' + mock_exec_editor_test.return_value = {mock_test_name: mock_result} + + mock_test_suite._run_single_test(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), mock_test_data, + mock_test_spec) + + assert mock_setup_test.called + assert mock_exec_editor_test.called + assert mock_test_data.results.update.called + mock_report_result.assert_called_with(mock_test_name, mock_result) + + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._exec_editor_multitest') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._setup_editor_test') + def test_RunBatchedTests_ValidTests_CallsCorrectly(self, mock_setup_test, mock_exec_multitest): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_test_data = mock.MagicMock() + + mock_test_suite._run_batched_tests(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), mock_test_data, + mock.MagicMock(), []) + + assert mock_setup_test.called + assert mock_exec_multitest.called + assert mock_test_data.results.update.called + + @mock.patch('threading.Thread') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_number_parallel_editors') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._setup_editor_test') + def test_RunParallelTests_TwoTestsAndEditors_TwoThreads(self, mock_setup_test, mock_get_num_editors, mock_thread): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_get_num_editors.return_value = 2 + mock_test_spec_list = [mock.MagicMock(), mock.MagicMock()] + mock_test_data = mock.MagicMock() + + mock_test_suite._run_parallel_tests(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), mock_test_data, + mock_test_spec_list, []) + + assert mock_setup_test.called + assert mock_test_data.results.update.call_count == len(mock_test_spec_list) + assert mock_thread.call_count == len(mock_test_spec_list) + + @mock.patch('threading.Thread') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_number_parallel_editors') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._setup_editor_test') + def test_RunParallelTests_TenTestsAndTwoEditors_TenThreads(self, mock_setup_test, mock_get_num_editors, mock_thread): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_get_num_editors.return_value = 2 + mock_test_spec_list = [] + for i in range(10): + mock_test_spec_list.append(mock.MagicMock()) + mock_test_data = mock.MagicMock() + + mock_test_suite._run_parallel_tests(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), mock_test_data, + mock_test_spec_list, []) + + assert mock_setup_test.called + assert mock_test_data.results.update.call_count == len(mock_test_spec_list) + assert mock_thread.call_count == len(mock_test_spec_list) + + @mock.patch('threading.Thread') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_number_parallel_editors') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._setup_editor_test') + def test_RunParallelTests_TenTestsAndThreeEditors_TenThreads(self, mock_setup_test, mock_get_num_editors, + mock_thread): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_get_num_editors.return_value = 3 + mock_test_spec_list = [] + for i in range(10): + mock_test_spec_list.append(mock.MagicMock()) + mock_test_data = mock.MagicMock() + + mock_test_suite._run_parallel_tests(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), mock_test_data, + mock_test_spec_list, []) + + assert mock_setup_test.called + assert mock_test_data.results.update.call_count == len(mock_test_spec_list) + assert mock_thread.call_count == len(mock_test_spec_list) + + @mock.patch('threading.Thread') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_number_parallel_editors') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._setup_editor_test') + def test_RunParallelBatchedTests_TwoTestsAndEditors_TwoThreads(self, mock_setup_test, mock_get_num_editors, + mock_thread): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_get_num_editors.return_value = 2 + mock_test_spec_list = [mock.MagicMock(), mock.MagicMock()] + mock_test_data = mock.MagicMock() + + mock_test_suite._run_parallel_tests(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), mock_test_data, + mock_test_spec_list, []) + + assert mock_setup_test.called + assert mock_test_data.results.update.call_count == len(mock_test_spec_list) + assert mock_thread.call_count == len(mock_test_spec_list) + + @mock.patch('threading.Thread') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_number_parallel_editors') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._setup_editor_test') + def test_RunParallelBatchedTests_TenTestsAndTwoEditors_TenThreads(self, mock_setup_test, mock_get_num_editors, + mock_thread): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_get_num_editors.return_value = 2 + mock_test_spec_list = [] + for i in range(10): + mock_test_spec_list.append(mock.MagicMock()) + mock_test_data = mock.MagicMock() + + mock_test_suite._run_parallel_tests(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), mock_test_data, + mock_test_spec_list, []) + + assert mock_setup_test.called + assert mock_test_data.results.update.call_count == len(mock_test_spec_list) + assert mock_thread.call_count == len(mock_test_spec_list) + + @mock.patch('threading.Thread') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_number_parallel_editors') + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._setup_editor_test') + def test_RunParallelBatchedTests_TenTestsAndThreeEditors_TenThreads(self, mock_setup_test, mock_get_num_editors, + mock_thread): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_get_num_editors.return_value = 3 + mock_test_spec_list = [] + for i in range(10): + mock_test_spec_list.append(mock.MagicMock()) + mock_test_data = mock.MagicMock() + + mock_test_suite._run_parallel_tests(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), mock_test_data, + mock_test_spec_list, []) + + assert mock_setup_test.called + assert mock_test_data.results.update.call_count == len(mock_test_spec_list) + assert mock_thread.call_count == len(mock_test_spec_list) + + def test_GetNumberParallelEditors_ConfigExists_ReturnsConfig(self): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_request = mock.MagicMock() + mock_request.config.getoption.return_value = 1 + + num_of_editors = mock_test_suite._get_number_parallel_editors(mock_request) + assert num_of_editors == 1 + + def test_GetNumberParallelEditors_ConfigNotExists_ReturnsDefault(self): + mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() + mock_request = mock.MagicMock() + mock_request.config.getoption.return_value = None + + num_of_editors = mock_test_suite._get_number_parallel_editors(mock_request) + assert num_of_editors == mock_test_suite.get_number_parallel_editors() \ No newline at end of file diff --git a/Tools/LyTestTools/tests/unit/test_pytest_plugin_editor_test.py b/Tools/LyTestTools/tests/unit/test_pytest_plugin_editor_test.py new file mode 100644 index 0000000000..968c07aca6 --- /dev/null +++ b/Tools/LyTestTools/tests/unit/test_pytest_plugin_editor_test.py @@ -0,0 +1,41 @@ +""" +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 +import os +import unittest.mock as mock +import unittest + +import ly_test_tools._internal.pytest_plugin.editor_test as editor_test + +pytestmark = pytest.mark.SUITE_smoke + +class TestEditorTest(unittest.TestCase): + + @mock.patch('inspect.isclass', mock.MagicMock(return_value=True)) + def test_PytestPycollectMakeitem_ValidArgs_CallsCorrectly(self): + mock_collector = mock.MagicMock() + mock_name = mock.MagicMock() + mock_obj = mock.MagicMock() + mock_base = mock.MagicMock() + mock_obj.__bases__ = [mock_base] + + editor_test.pytest_pycollect_makeitem(mock_collector, mock_name, mock_obj) + mock_base.pytest_custom_makeitem.assert_called_once_with(mock_collector, mock_name, mock_obj) + + def test_PytestCollectionModifyitem_OneValidClass_CallsOnce(self): + mock_item = mock.MagicMock() + mock_class = mock.MagicMock() + mock_class.pytest_custom_modify_items = mock.MagicMock() + mock_item.instance.__class__ = mock_class + mock_session = mock.MagicMock() + mock_items = [mock_item, mock.MagicMock()] + mock_config = mock.MagicMock() + + generator = editor_test.pytest_collection_modifyitems(mock_session, mock_items, mock_config) + for x in generator: + pass + assert mock_class.pytest_custom_modify_items.call_count == 1 \ No newline at end of file From f12d7626f841e69d2bbe7a4c0ee20f195f720b4f Mon Sep 17 00:00:00 2001 From: evanchia Date: Wed, 13 Oct 2021 16:22:26 -0700 Subject: [PATCH 05/77] Finishing up unit tests Signed-off-by: evanchia --- .../tests/unit/test_o3de_editor_test.py | 122 ++++++++++++++++-- 1 file changed, 109 insertions(+), 13 deletions(-) diff --git a/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py b/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py index ef49934887..05d1ebc305 100644 --- a/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py +++ b/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py @@ -955,8 +955,8 @@ class TestRunningTests(unittest.TestCase): mock_test_spec_list = [mock.MagicMock(), mock.MagicMock()] mock_test_data = mock.MagicMock() - mock_test_suite._run_parallel_tests(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), mock_test_data, - mock_test_spec_list, []) + mock_test_suite._run_parallel_batched_tests(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), + mock_test_data, mock_test_spec_list, []) assert mock_setup_test.called assert mock_test_data.results.update.call_count == len(mock_test_spec_list) @@ -965,7 +965,7 @@ class TestRunningTests(unittest.TestCase): @mock.patch('threading.Thread') @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_number_parallel_editors') @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._setup_editor_test') - def test_RunParallelBatchedTests_TenTestsAndTwoEditors_TenThreads(self, mock_setup_test, mock_get_num_editors, + def test_RunParallelBatchedTests_TenTestsAndTwoEditors_2Threads(self, mock_setup_test, mock_get_num_editors, mock_thread): mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() mock_get_num_editors.return_value = 2 @@ -974,17 +974,17 @@ class TestRunningTests(unittest.TestCase): mock_test_spec_list.append(mock.MagicMock()) mock_test_data = mock.MagicMock() - mock_test_suite._run_parallel_tests(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), mock_test_data, - mock_test_spec_list, []) + mock_test_suite._run_parallel_batched_tests(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), + mock_test_data, mock_test_spec_list, []) assert mock_setup_test.called - assert mock_test_data.results.update.call_count == len(mock_test_spec_list) - assert mock_thread.call_count == len(mock_test_spec_list) + assert mock_test_data.results.update.call_count == 2 + assert mock_thread.call_count == 2 @mock.patch('threading.Thread') @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._get_number_parallel_editors') @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite._setup_editor_test') - def test_RunParallelBatchedTests_TenTestsAndThreeEditors_TenThreads(self, mock_setup_test, mock_get_num_editors, + def test_RunParallelBatchedTests_TenTestsAndThreeEditors_ThreeThreads(self, mock_setup_test, mock_get_num_editors, mock_thread): mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() mock_get_num_editors.return_value = 3 @@ -993,12 +993,12 @@ class TestRunningTests(unittest.TestCase): mock_test_spec_list.append(mock.MagicMock()) mock_test_data = mock.MagicMock() - mock_test_suite._run_parallel_tests(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), mock_test_data, - mock_test_spec_list, []) + mock_test_suite._run_parallel_batched_tests(mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), + mock_test_data, mock_test_spec_list, []) assert mock_setup_test.called - assert mock_test_data.results.update.call_count == len(mock_test_spec_list) - assert mock_thread.call_count == len(mock_test_spec_list) + assert mock_test_data.results.update.call_count == 3 + assert mock_thread.call_count == 3 def test_GetNumberParallelEditors_ConfigExists_ReturnsConfig(self): mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() @@ -1014,4 +1014,100 @@ class TestRunningTests(unittest.TestCase): mock_request.config.getoption.return_value = None num_of_editors = mock_test_suite._get_number_parallel_editors(mock_request) - assert num_of_editors == mock_test_suite.get_number_parallel_editors() \ No newline at end of file + assert num_of_editors == mock_test_suite.get_number_parallel_editors() + +@mock.patch('_pytest.python.Class.collect') +class TestEditorTestClass(unittest.TestCase): + + def setUp(self): + mock_name = mock.MagicMock() + mock_collector = mock.MagicMock() + self.mock_test_class = ly_test_tools.o3de.editor_test.EditorTestSuite.EditorTestClass(mock_name, mock_collector) + self.mock_test_class.obj = mock.MagicMock() + single_1 = mock.MagicMock() + single_1.__name__ = 'single_1_name' + single_2 = mock.MagicMock() + single_2.__name__ = 'single_2_name' + self.mock_test_class.obj.get_single_tests.return_value = [single_1, single_2] + batch_1 = mock.MagicMock() + batch_1.__name__ = 'batch_1_name' + batch_2 = mock.MagicMock() + batch_2.__name__ = 'batch_2_name' + parallel_1 = mock.MagicMock() + parallel_1.__name__ = 'parallel_1_name' + parallel_2 = mock.MagicMock() + parallel_2.__name__ = 'parallel_2_name' + both_1 = mock.MagicMock() + both_1.__name__ = 'both_1_name' + both_2 = mock.MagicMock() + both_2.__name__ = 'both_2_name' + self.mock_test_class.obj.filter_shared_tests.side_effect = [ [batch_1, batch_2], + [parallel_1, parallel_2], + [both_1, both_2] ] + + def test_Collect_NoParallelNoBatched_RunsAsSingleTests(self, mock_collect): + self.mock_test_class.config.getoption.return_value = True + self.mock_test_class.collect() + assert self.mock_test_class.obj.single_1_name.__name__ == 'single_run' + assert self.mock_test_class.obj.single_2_name.__name__ == 'single_run' + assert self.mock_test_class.obj.batch_1_name.__name__ == 'single_run' + assert self.mock_test_class.obj.batch_2_name.__name__ == 'single_run' + assert self.mock_test_class.obj.parallel_1_name.__name__ == 'single_run' + assert self.mock_test_class.obj.parallel_2_name.__name__ == 'single_run' + assert self.mock_test_class.obj.both_1_name.__name__ == 'single_run' + assert self.mock_test_class.obj.both_2_name.__name__ == 'single_run' + + def test_Collect_AllValidTests_RunsAsInteded(self, mock_collect): + self.mock_test_class.config.getoption.return_value = False + self.mock_test_class.collect() + assert self.mock_test_class.obj.single_1_name.__name__ == 'single_run' + assert self.mock_test_class.obj.single_2_name.__name__ == 'single_run' + assert self.mock_test_class.obj.batch_1_name.__name__ == 'result' + assert self.mock_test_class.obj.batch_2_name.__name__ == 'result' + assert self.mock_test_class.obj.parallel_1_name.__name__ == 'result' + assert self.mock_test_class.obj.parallel_2_name.__name__ == 'result' + assert self.mock_test_class.obj.both_1_name.__name__ == 'result' + assert self.mock_test_class.obj.both_2_name.__name__ == 'result' + + def test_Collect_AllValidTests_CallsCollect(self, mock_collect): + self.mock_test_class.collect() + assert mock_collect.called + + def test_Collect_NormalCollection_ReturnsFilteredRuns(self, mock_collect): + mock_run = mock.MagicMock() + mock_run.obj.marks = {"run_type": 'run_shared'} + mock_run_2 = mock.MagicMock() + mock_run_2.obj.marks = {"run_type": 'result'} + mock_instance = mock.MagicMock() + mock_instance.collect.return_value = [mock_run, mock_run_2] + mock_collect.return_value = [mock_instance] + + collection = self.mock_test_class.collect() + assert collection == [mock_run_2] + + def test_Collect_NormalRun_ReturnsRunners(self, mock_collect): + self.mock_test_class.collect() + runners = self.mock_test_class.obj._runners + + assert runners[0].name == 'run_batched_tests' + assert runners[1].name == 'run_parallel_tests' + assert runners[2].name == 'run_parallel_batched_tests' + + def test_Collect_NormalCollection_StoresRunners(self, mock_collect): + mock_runner = mock.MagicMock() + mock_run = mock.MagicMock() + mock_run.obj.marks = {"run_type": 'run_shared'} + mock_run.function.marks = {"runner": mock_runner} + mock_runner_2 = mock.MagicMock() + mock_runner_2.result_pytestfuncs = [] + mock_run_2 = mock.MagicMock() + mock_run_2.obj.marks = {"run_type": 'result'} + mock_run_2.function.marks = {"runner": mock_runner_2} + mock_instance = mock.MagicMock() + mock_instance.collect.return_value = [mock_run, mock_run_2] + mock_collect.return_value = [mock_instance] + + self.mock_test_class.collect() + + assert mock_runner.run_pytestfunc == mock_run + assert mock_run_2 in mock_runner_2.result_pytestfuncs From 84493760caa0718c46789d6bcc4ec60fd5f5e385 Mon Sep 17 00:00:00 2001 From: evanchia Date: Mon, 18 Oct 2021 13:27:40 -0700 Subject: [PATCH 06/77] addressing PR feedback Signed-off-by: evanchia --- .../_internal/pytest_plugin/editor_test.py | 11 +- .../pytest_plugin/test_tools_fixtures.py | 16 -- .../ly_test_tools/o3de/editor_test.py | 55 +++---- .../ly_test_tools/o3de/editor_test_utils.py | 9 +- .../tests/unit/test_editor_test_utils.py | 26 +-- Tools/LyTestTools/tests/unit/test_fixtures.py | 11 -- .../tests/unit/test_o3de_editor_test.py | 149 ++++++++---------- .../unit/test_pytest_plugin_editor_test.py | 2 +- 8 files changed, 118 insertions(+), 161 deletions(-) diff --git a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/editor_test.py b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/editor_test.py index 2df5810047..19caf7e090 100644 --- a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/editor_test.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/editor_test.py @@ -4,7 +4,8 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT -Utility for specifying an Editor test, supports seamless parallelization and/or batching of tests. +Utility for specifying an Editor test, supports seamless parallelization and/or batching of tests. This is not a set of +tools to directly invoke, but a plugin with functions intended to be called by only the Pytest framework. """ import pytest @@ -15,7 +16,7 @@ __test__ = False def pytest_addoption(parser): # type (argparse.ArgumentParser) -> None """ - Options when running tests in batches or parallel. + Options when running editor tests in batches or parallel. :param parser: The ArgumentParser object :return: None """ @@ -27,8 +28,8 @@ def pytest_pycollect_makeitem(collector, name, obj): # type (PyCollector, str, object) -> Collector """ Create a custom custom item collection if the class defines pytest_custom_makeitem function. This is used for - automtically generating test functions with a custom collector. - :param collector: The Python test collector + automatically generating test functions with a custom collector. + :param collector: The Pytest collector :param name: Name of the collector :param obj: The custom collector, normally an EditorTestSuite.EditorTestClass object :return: Returns the custom collector @@ -40,7 +41,7 @@ def pytest_pycollect_makeitem(collector, name, obj): @pytest.hookimpl(hookwrapper=True) def pytest_collection_modifyitems(session, items, config): - # type (Session, list, Config) -> None + # type (Session, List[EditorTestBase], Config) -> None """ Add custom modification of items. This is used for adding the runners into the item list. :param session: The Pytest Session diff --git a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py index 3115c28406..af29064766 100755 --- a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py @@ -55,22 +55,6 @@ def pytest_configure(config): ly_test_tools._internal.pytest_plugin.build_directory = _get_build_directory(config) ly_test_tools._internal.pytest_plugin.output_path = _get_output_path(config) -def pytest_pycollect_makeitem(collector, name, obj): - # type (PyCollector, str, object) -> Collector - """ - Create a custom custom item collection if the class defines pytest_custom_makeitem function. This is used for - automtically generating test functions with a custom collector. - :param collector: The Python test collector - :param name: Name of the collector - :param obj: The custom collector, normally an EditorTestSuite.EditorTestClass object - :return: Returns the custom collector - """ - import inspect - if inspect.isclass(obj): - for base in obj.__bases__: - if hasattr(base, "pytest_custom_makeitem"): - return base.pytest_custom_makeitem(collector, name, obj) - def _get_build_directory(config): """ Fetch and verify the cmake build directory CLI arg, without creating an error when unset diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py index 39413c22a3..789d07f200 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py @@ -321,8 +321,9 @@ class EditorTestSuite(): def editor_test_data(self, request): # type (request) -> TestData """ - Yields a generator to capture the test results and an AssetProcessor object. - :request: The pytest request + Yields a per-testsuite structure to store the data of each test result and an AssetProcessor object that will be + re-used on the whole suite + :request: The Pytest request :yield: The TestData object """ self._editor_test_data(request) @@ -513,12 +514,15 @@ class EditorTestSuite(): @classmethod def pytest_custom_modify_items(cls, session, items, config): - # type () -> None + # type (Session, List[EditorTestBase], Config) -> None """ - + Adds the runners' functions and filters the tests that will run. The runners will be added if they have any + selected tests + :param session: The Pytest Session + :param items: The test case functions + :param config: The Pytest Config object + :return: None """ - # Add here the runners functions and filter the tests that will be run. - # The runners will be added if they have any selected tests new_items = [] for runner in cls._runners: runner.tests[:] = cls.filter_session_shared_tests(items, runner.tests) @@ -535,7 +539,7 @@ class EditorTestSuite(): @classmethod def get_single_tests(cls): - # type () -> list + # type () -> List """ Grabs all of the EditorSingleTests subclassed tests from the EditorTestSuite class Usage example: @@ -549,7 +553,7 @@ class EditorTestSuite(): @classmethod def get_shared_tests(cls): - # type () -> list + # type () -> List """ Grabs all of the EditorSharedTests from the EditorTestSuite Usage example: @@ -563,7 +567,7 @@ class EditorTestSuite(): @classmethod def get_session_shared_tests(cls, session): - # type (Session) -> list[EditorTestBase] + # type (Session) -> List[EditorTestBase] """ Filters and returns all of the shared tests in a given session. :session: The test session @@ -574,7 +578,7 @@ class EditorTestSuite(): @staticmethod def filter_session_shared_tests(session_items, shared_tests): - # type (list, list) -> list[EditorTestBase] + # type (List[EditorTestBase, List[EditorSharedTest]) -> List[EditorTestBase] """ Retrieve the test sub-set that was collected this can be less than the original set if were overriden via -k argument or similars @@ -596,7 +600,7 @@ class EditorTestSuite(): @staticmethod def filter_shared_tests(shared_tests, is_batchable=False, is_parallelizable=False): - # type (list, bool, bool) -> list + # type (List[EditorSharedTest], bool, bool) -> List[EditorSharedTest] """ Filters and returns all tests based off of if they are batchable and/or parallelizable :shared_tests: All shared tests @@ -654,7 +658,7 @@ class EditorTestSuite(): @staticmethod def _get_results_using_output(test_spec_list, output, editor_log_content): - # type(list, str, str) -> dict{str: Result} + # type(List[EditorTestBase], str, str) -> dict{str: Result} """ Utility function for parsing the output information from the editor. It deserializes the JSON content printed in the output for every test and returns that information. @@ -732,7 +736,7 @@ class EditorTestSuite(): ### Running tests ### def _exec_editor_test(self, request, workspace, editor, run_id, log_name, test_spec, cmdline_args = []): - # type (Request, AbstractWorkspace, Editor, int, str, EditorTestBase, list[str] -> dict{str: Result} + # type (Request, AbstractWorkspace, Editor, int, str, EditorTestBase, List[str] -> dict{str: Result} """ Starts the editor with the given test and retuns an result dict with a single element specifying the result :request: The pytest request @@ -794,7 +798,7 @@ class EditorTestSuite(): return results def _exec_editor_multitest(self, request, workspace, editor, run_id, log_name, test_spec_list, cmdline_args=[]): - # type (Request, AbstractWorkspace, Editor, int, str, list[EditorTestBase], list[str]) -> dict{str: Result} + # type (Request, AbstractWorkspace, Editor, int, str, List[EditorTestBase], List[str]) -> dict{str: Result} """ Starts an editor executable with a list of tests and returns a dict of the result of every test ran within that editor instance. In case of failure this function also parses the editor output to find out what specific tests @@ -804,7 +808,7 @@ class EditorTestSuite(): :editor: The LyTestTools Editor object :run_id: The unique run id :log_name: The name of the editor log to retrieve - :test_spec_list: A list of EditorTestBase tests to run + :test_spec_list: A list of EditorTestBase tests to run in the same editor instance :cmdline_args: Any additional command line args :return: A dict of Result objects """ @@ -820,8 +824,7 @@ class EditorTestSuite(): editor_utils.cycle_crash_report(run_id, workspace) results = {} - test_filenames_str = ";".join(editor_utils.get_testcase_module_filepath(test_spec.test_module) for - test_spec in test_spec_list) + test_filenames_str = ";".join(editor_utils.get_testcase_module_filepath(test_spec.test_module) for test_spec in test_spec_list) cmdline = [ "--runpythontest", test_filenames_str, "-logfile", f"@log@/{log_name}", @@ -846,8 +849,7 @@ class EditorTestSuite(): # Scrap the output to attempt to find out which tests failed. # This function should always populate the result list, if it didn't find it, it will have "Unknown" type of result results = self._get_results_using_output(test_spec_list, output, editor_log_content) - assert len(results) == len(test_spec_list), "bug in _get_results_using_output(), the number of results" \ - "don't match the tests ran" + assert len(results) == len(test_spec_list), "bug in _get_results_using_output(), the number of results don't match the tests ran" # If the editor crashed, find out in which test it happened and update the results has_crashed = return_code != EditorTestSuite._TEST_FAIL_RETCODE @@ -866,9 +868,9 @@ class EditorTestSuite(): else: # If there are remaning "Unknown" results, these couldn't execute because of the crash, # update with info about the offender - results[test_spec_name].extra_info = f"This test has unknown result, test " \ - f"'{crashed_result.test_spec.__name__}' crashed " \ - f"before this test could be executed" + results[test_spec_name].extra_info = f"This test has unknown result," \ + f"test '{crashed_result.test_spec.__name__}'" \ + f"crashed before this test could be executed" # if all the tests ran, the one that has caused the crash is the last test if not crashed_result: crash_error = editor_utils.retrieve_crash_output(run_id, workspace, self._TIMEOUT_CRASH_LOG) @@ -882,8 +884,7 @@ class EditorTestSuite(): # The editor timed out when running the tests, get the data from the output to find out which ones ran results = self._get_results_using_output(test_spec_list, output, editor_log_content) - assert len(results) == len(test_spec_list), "bug in _get_results_using_output(), the number of results " \ - "don't match the tests ran" + assert len(results) == len(test_spec_list), "bug in _get_results_using_output(), the number of results don't match the tests ran" # Similar logic here as crashes, the first test that has no result is the one that timed out timed_out_result = None for test_spec_name, result in results.items(): @@ -929,7 +930,7 @@ class EditorTestSuite(): self._report_result(test_name, test_result) def _run_batched_tests(self, request, workspace, editor, editor_test_data, test_spec_list, extra_cmdline_args=[]): - # type (Request, AbstractWorkspace, Editor, TestData, list[EditorSharedTest], list[str]) -> None + # type (Request, AbstractWorkspace, Editor, TestData, List[EditorSharedTest], List[str]) -> None """ Runs a batch of tests in one single editor with the given spec list (one editor, multiple tests) :request: The Pytest Request @@ -950,7 +951,7 @@ class EditorTestSuite(): editor_test_data.results.update(results) def _run_parallel_tests(self, request, workspace, editor, editor_test_data, test_spec_list, extra_cmdline_args=[]): - # type(Request, AbstractWorkspace, Editor, TestData, list[EditorSharedTest], list[str]) -> None + # type(Request, AbstractWorkspace, Editor, TestData, List[EditorSharedTest], List[str]) -> None """ Runs multiple editors with one test on each editor (multiple editor, one test each) :request: The Pytest Request @@ -999,7 +1000,7 @@ class EditorTestSuite(): def _run_parallel_batched_tests(self, request, workspace, editor, editor_test_data, test_spec_list, extra_cmdline_args=[]): - # type(Request, AbstractWorkspace, Editor, TestData, list[EditorSharedTest], list[str] -> None + # type(Request, AbstractWorkspace, Editor, TestData, List[EditorSharedTest], List[str] -> None """ Runs multiple editors with a batch of tests for each editor (multiple editor, multiple tests each) :request: The Pytest Request diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py index 838f929cfa..6e319bb860 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py @@ -4,7 +4,7 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT -Utility functions for the editor_test module +Utility functions mostly for the editor_test module. They can also be used for assisting Editor tests. """ import os @@ -19,7 +19,8 @@ logger = logging.getLogger(__name__) def kill_all_ly_processes(include_asset_processor=True): # type (bool) -> None """ - Kills all common O3DE processes such as the Editor, Game Launchers, and Asset Processor. + Kills all common O3DE processes such as the Editor, Game Launchers, and optionally Asset Processor. Defaults to + killing the Asset Processor. :param include_asset_processor: Boolean flag whether or not to kill the AP :return: None """ @@ -65,7 +66,7 @@ def retrieve_log_path(run_id, workspace): """ return os.path.join(workspace.paths.project(), "user", f"log_test_{run_id}") -def retrieve_crash_output(run_id, workspace, timeout): +def retrieve_crash_output(run_id, workspace, timeout=10): # type (int, ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager, float) -> str """ returns the crash output string for the given test run. @@ -138,7 +139,7 @@ def retrieve_editor_log_content(run_id, log_name, workspace, timeout=10): return editor_info def retrieve_last_run_test_index_from_output(test_spec_list, output): - # type (list, str) -> int + # type (List[EditorTestBase], str) -> int """ Finds out what was the last test that was run by inspecting the input. This is used for determining what was the batched test has crashed the editor diff --git a/Tools/LyTestTools/tests/unit/test_editor_test_utils.py b/Tools/LyTestTools/tests/unit/test_editor_test_utils.py index 134d1e1ad8..b096f6d6b0 100644 --- a/Tools/LyTestTools/tests/unit/test_editor_test_utils.py +++ b/Tools/LyTestTools/tests/unit/test_editor_test_utils.py @@ -16,18 +16,20 @@ pytestmark = pytest.mark.SUITE_smoke class TestEditorTestUtils(unittest.TestCase): @mock.patch('ly_test_tools.environment.process_utils.kill_processes_named') - def test_KillAllLyProcesses_IncludeAP_CallsCorrectly(self, under_test): + def test_KillAllLyProcesses_IncludeAP_CallsCorrectly(self, mock_kill_processes_named): process_list = ['Editor', 'Profiler', 'RemoteConsole', 'AssetProcessor', 'AssetProcessorBatch', 'AssetBuilder'] editor_test_utils.kill_all_ly_processes(include_asset_processor=True) - under_test.assert_called_once_with(process_list, ignore_extensions=True) + mock_kill_processes_named.assert_called_once_with(process_list, ignore_extensions=True) @mock.patch('ly_test_tools.environment.process_utils.kill_processes_named') - def test_KillAllLyProcesses_NotIncludeAP_CallsCorrectly(self, under_test): + def test_KillAllLyProcesses_NotIncludeAP_CallsCorrectly(self, mock_kill_processes_named): process_list = ['Editor', 'Profiler', 'RemoteConsole'] + ap_process_list = ['AssetProcessor', 'AssetProcessorBatch', 'AssetBuilder'] editor_test_utils.kill_all_ly_processes(include_asset_processor=False) - under_test.assert_called_once_with(process_list, ignore_extensions=True) + mock_kill_processes_named.assert_called_once() + assert ap_process_list not in mock_kill_processes_named.call_args[0] def test_GetTestcaseModuleFilepath_NoExtension_ReturnsPYExtension(self): mock_module = mock.MagicMock() @@ -81,30 +83,30 @@ class TestEditorTestUtils(unittest.TestCase): @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @mock.patch('os.path.exists') def test_CycleCrashReport_LogExists_NamedCorrectly(self, mock_exists, mock_retrieve_log_path, mock_getmtime, - under_test): + mock_rename): mock_exists.side_effect = [True, False] mock_retrieve_log_path.return_value = 'mock_log_path' mock_workspace = mock.MagicMock() mock_getmtime.return_value = 1 editor_test_utils.cycle_crash_report(0, mock_workspace) - under_test.assert_called_once_with(os.path.join('mock_log_path', 'error.log'), - os.path.join('mock_log_path', 'error_1969_12_31_16_00_01.log')) + mock_rename.assert_called_once_with(os.path.join('mock_log_path', 'error.log'), + os.path.join('mock_log_path', 'error_1969_12_31_16_00_01.log')) @mock.patch('os.rename') @mock.patch('os.path.getmtime') @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @mock.patch('os.path.exists') def test_CycleCrashReport_DmpExists_NamedCorrectly(self, mock_exists, mock_retrieve_log_path, mock_getmtime, - under_test): + mock_rename): mock_exists.side_effect = [False, True] mock_retrieve_log_path.return_value = 'mock_log_path' mock_workspace = mock.MagicMock() mock_getmtime.return_value = 1 editor_test_utils.cycle_crash_report(0, mock_workspace) - under_test.assert_called_once_with(os.path.join('mock_log_path', 'error.dmp'), - os.path.join('mock_log_path', 'error_1969_12_31_16_00_01.dmp')) + mock_rename.assert_called_once_with(os.path.join('mock_log_path', 'error.dmp'), + os.path.join('mock_log_path', 'error_1969_12_31_16_00_01.dmp')) @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock()) @@ -123,9 +125,9 @@ class TestEditorTestUtils(unittest.TestCase): mock_retrieve_log_path.return_value = 'mock_log_path' mock_logname = 'mock_log.log' mock_workspace = mock.MagicMock() - expected = f"-- Error reading editor.log: [Errno 2] No such file or directory: 'mock_log_path\\\\mock_log.log' --" + expected = f"-- Error reading editor.log" - assert expected == editor_test_utils.retrieve_editor_log_content(0, mock_logname, mock_workspace) + assert expected in editor_test_utils.retrieve_editor_log_content(0, mock_logname, mock_workspace) def test_RetrieveLastRunTestIndexFromOutput_SecondTestFailed_Returns0(self): mock_test = mock.MagicMock() diff --git a/Tools/LyTestTools/tests/unit/test_fixtures.py b/Tools/LyTestTools/tests/unit/test_fixtures.py index 911e6fef91..32dc204bd2 100755 --- a/Tools/LyTestTools/tests/unit/test_fixtures.py +++ b/Tools/LyTestTools/tests/unit/test_fixtures.py @@ -369,14 +369,3 @@ class TestFixtures(object): mock_request.addfinalizer.call_args[0][0]() mock_stop.assert_called_once() - - @mock.patch('inspect.isclass', mock.MagicMock(return_value=True)) - def test_PytestPycollectMakeitem_ValidArgs_CallsCorrectly(self): - mock_collector = mock.MagicMock() - mock_name = mock.MagicMock() - mock_obj = mock.MagicMock() - mock_base = mock.MagicMock() - mock_obj.__bases__ = [mock_base] - - test_tools_fixtures.pytest_pycollect_makeitem(mock_collector, mock_name, mock_obj) - mock_base.pytest_custom_makeitem.assert_called_once_with(mock_collector, mock_name, mock_obj) diff --git a/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py b/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py index 05d1ebc305..2ba5a8ed6c 100644 --- a/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py +++ b/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py @@ -68,14 +68,9 @@ class TestPass(unittest.TestCase): mock_test_spec = mock.MagicMock() mock_output = 'mock_output' mock_editor_log = mock.MagicMock() - expected = f"Test Passed\n"\ - f"------------\n"\ - f"| Output |\n"\ - f"------------\n"\ - f"{mock_output}\n" mock_pass = editor_test.Result.Pass.create(mock_test_spec, mock_output, mock_editor_log) - assert str(mock_pass) == expected + assert mock_output in str(mock_pass) class TestFail(unittest.TestCase): @@ -93,18 +88,10 @@ class TestFail(unittest.TestCase): mock_test_spec = mock.MagicMock() mock_output = 'mock_output' mock_editor_log = 'mock_editor_log' - expected = f"Test FAILED\n"\ - f"------------\n"\ - f"| Output |\n"\ - f"------------\n"\ - f"{mock_output}\n"\ - f"--------------\n"\ - f"| Editor log |\n"\ - f"--------------\n"\ - f"{mock_editor_log}\n" mock_pass = editor_test.Result.Fail.create(mock_test_spec, mock_output, mock_editor_log) - assert str(mock_pass) == expected + assert mock_output in str(mock_pass) + assert mock_editor_log in str(mock_pass) class TestCrash(unittest.TestCase): @@ -129,23 +116,12 @@ class TestCrash(unittest.TestCase): mock_editor_log = 'mock_editor_log' mock_return_code = 0 mock_stacktrace = 'mock stacktrace' - expected = f"Test CRASHED, return code {hex(mock_return_code)}\n"\ - f"---------------\n"\ - f"| Stacktrace |\n"\ - f"---------------\n"\ - f"{mock_stacktrace}"\ - f"------------\n" \ - f"| Output |\n" \ - f"------------\n" \ - f"{mock_output}\n" \ - f"--------------\n" \ - f"| Editor log |\n" \ - f"--------------\n" \ - f"{mock_editor_log}\n" mock_pass = editor_test.Result.Crash.create(mock_test_spec, mock_output, mock_return_code, mock_stacktrace, mock_editor_log) - assert str(mock_pass) == expected + assert mock_stacktrace in str(mock_pass) + assert mock_output in str(mock_pass) + assert mock_editor_log in str(mock_pass) def test_Str_MissingStackTrace_ReturnsCorrectly(self): mock_test_spec = mock.MagicMock() @@ -153,23 +129,10 @@ class TestCrash(unittest.TestCase): mock_editor_log = 'mock_editor_log' mock_return_code = 0 mock_stacktrace = None - expected = f"Test CRASHED, return code {hex(mock_return_code)}\n"\ - f"---------------\n"\ - f"| Stacktrace |\n"\ - f"---------------\n"\ - f"-- No stacktrace data found --\n"\ - f"------------\n" \ - f"| Output |\n" \ - f"------------\n" \ - f"{mock_output}\n" \ - f"--------------\n" \ - f"| Editor log |\n" \ - f"--------------\n" \ - f"{mock_editor_log}\n" - mock_pass = editor_test.Result.Crash.create(mock_test_spec, mock_output, mock_return_code, mock_stacktrace, mock_editor_log) - assert str(mock_pass) == expected + assert mock_output in str(mock_pass) + assert mock_editor_log in str(mock_pass) class Timeout(unittest.TestCase): @@ -190,18 +153,10 @@ class Timeout(unittest.TestCase): mock_output = 'mock_output' mock_editor_log = 'mock_editor_log' mock_timeout = 0 - expected = f"Test TIMED OUT after {mock_timeout} seconds\n"\ - f"------------\n" \ - f"| Output |\n" \ - f"------------\n" \ - f"{mock_output}\n" \ - f"--------------\n" \ - f"| Editor log |\n" \ - f"--------------\n" \ - f"{mock_editor_log}\n" mock_pass = editor_test.Result.Timeout.create(mock_test_spec, mock_output, mock_timeout, mock_editor_log) - assert str(mock_pass) == expected + assert mock_output in str(mock_pass) + assert mock_editor_log in str(mock_pass) class Unknown(unittest.TestCase): @@ -222,18 +177,10 @@ class Unknown(unittest.TestCase): mock_output = 'mock_output' mock_editor_log = 'mock_editor_log' mock_extra_info = 'mock extra info' - expected = f"Unknown test result, possible cause: {mock_extra_info}\n"\ - f"------------\n" \ - f"| Output |\n" \ - f"------------\n" \ - f"{mock_output}\n" \ - f"--------------\n" \ - f"| Editor log |\n" \ - f"--------------\n" \ - f"{mock_editor_log}\n" mock_pass = editor_test.Result.Unknown.create(mock_test_spec, mock_output, mock_extra_info, mock_editor_log) - assert str(mock_pass) == expected + assert mock_output in str(mock_pass) + assert mock_editor_log in str(mock_pass) class TestEditorTestSuite(unittest.TestCase): @@ -274,12 +221,31 @@ class TestEditorTestSuite(unittest.TestCase): mock.MagicMock()) assert isinstance(mock_test_class, editor_test.EditorTestSuite.EditorTestClass) - def test_PytestCustomModifyItems(self): - pass + @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite.filter_session_shared_tests') + def test_PytestCustomModifyItems_FunctionsMatch_AddsRunners(self, mock_filter_tests): + class MockTestSuite(editor_test.EditorTestSuite): + pass + mock_func_1 = mock.MagicMock() + mock_test = mock.MagicMock() + runner_1 = editor_test.EditorTestSuite.Runner('mock_runner_1', mock_func_1, [mock_test]) + mock_run_pytest_func = mock.MagicMock() + runner_1.run_pytestfunc = mock_run_pytest_func + mock_result_pytestfuncs = [mock.MagicMock()] + runner_1.result_pytestfuncs = mock_result_pytestfuncs + mock_items = [] + mock_items.extend(mock_result_pytestfuncs) + + MockTestSuite._runners = [runner_1] + mock_test_1 = mock.MagicMock() + mock_test_2 = mock.MagicMock() + mock_filter_tests.return_value = [mock_test_1, mock_test_2] + + MockTestSuite.pytest_custom_modify_items(mock.MagicMock(), mock_items, mock.MagicMock()) + assert mock_items == [mock_run_pytest_func, mock_result_pytestfuncs[0]] def test_GetSingleTests_NoSingleTests_EmptyList(self): class MockTestSuite(editor_test.EditorTestSuite): - pass + pass mock_test_suite = MockTestSuite() tests = mock_test_suite.get_single_tests() assert len(tests) == 0 @@ -291,7 +257,8 @@ class TestEditorTestSuite(unittest.TestCase): mock_test_suite = MockTestSuite() tests = mock_test_suite.get_single_tests() assert len(tests) == 1 - + assert tests[0].__name__ == "MockSingleTest" + assert issubclass(tests[0], editor_test.EditorSingleTest) def test_GetSingleTests_AllTests_ReturnsOnlySingles(self): class MockTestSuite(editor_test.EditorTestSuite): @@ -304,6 +271,8 @@ class TestEditorTestSuite(unittest.TestCase): mock_test_suite = MockTestSuite() tests = mock_test_suite.get_single_tests() assert len(tests) == 2 + for test in tests: + assert issubclass(test, editor_test.EditorSingleTest) def test_GetSharedTests_NoSharedTests_EmptyList(self): class MockTestSuite(editor_test.EditorTestSuite): @@ -319,6 +288,8 @@ class TestEditorTestSuite(unittest.TestCase): mock_test_suite = MockTestSuite() tests = mock_test_suite.get_shared_tests() assert len(tests) == 1 + assert tests[0].__name__ == 'MockSharedTest' + assert issubclass(tests[0], editor_test.EditorSharedTest) def test_GetSharedTests_AllTests_ReturnsOnlyShared(self): class MockTestSuite(editor_test.EditorTestSuite): @@ -331,6 +302,8 @@ class TestEditorTestSuite(unittest.TestCase): mock_test_suite = MockTestSuite() tests = mock_test_suite.get_shared_tests() assert len(tests) == 2 + for test in tests: + assert issubclass(test, editor_test.EditorSharedTest) @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite.filter_session_shared_tests') @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite.get_shared_tests') @@ -343,8 +316,6 @@ class TestEditorTestSuite(unittest.TestCase): def test_FilterSessionSharedTests_OneSharedTest_ReturnsOne(self): def mock_test(): pass - mock_session_items = mock.MagicMock() - mock_shared_tests = mock.MagicMock() mock_test.originalname = 'mock_test' mock_test.__name__ = mock_test.originalname mock_session_items = [mock_test] @@ -361,8 +332,6 @@ class TestEditorTestSuite(unittest.TestCase): pass def mock_test_3(): pass - mock_session_items = mock.MagicMock() - mock_shared_tests = mock.MagicMock() mock_test.originalname = 'mock_test' mock_test.__name__ = mock_test.originalname mock_test_2.originalname = 'mock_test_2' @@ -379,8 +348,6 @@ class TestEditorTestSuite(unittest.TestCase): def test_FilterSessionSharedTests_SkippingPytestRaises_SkipsAddingTest(self): def mock_test(): pass - mock_session_items = mock.MagicMock() - mock_shared_tests = mock.MagicMock() mock_test.originalname = 'mock_test' mock_test.__name__ = mock_test.originalname mock_session_items = [mock_test] @@ -495,12 +462,13 @@ class TestUtils(unittest.TestCase): mock_output = 'JSON_START(' \ '{"name": "mock_module_name", "output": "mock_std_out", "success": "mock_success_data"}' \ ')JSON_END' - mock_editor_log = 'JSON_START(' \ - ')JSON_END' + mock_pass = mock.MagicMock() + mock_create.return_value = mock_pass - results = mock_test_suite._get_results_using_output(mock_test_list, mock_output, mock_editor_log) + results = mock_test_suite._get_results_using_output(mock_test_list, mock_output, '') assert mock_create.called assert len(results) == 1 + assert results[mock_test.__name__] == mock_pass @mock.patch('ly_test_tools.o3de.editor_test.Result.Fail.create') @mock.patch('ly_test_tools.o3de.editor_test_utils.get_module_filename') @@ -513,12 +481,13 @@ class TestUtils(unittest.TestCase): mock_output = 'JSON_START(' \ '{"name": "mock_module_name", "output": "mock_std_out", "failed": "mock_fail_data"}' \ ')JSON_END' - mock_editor_log = 'JSON_START(' \ - ')JSON_END' + mock_fail = mock.MagicMock() + mock_create.return_value = mock_fail - results = mock_test_suite._get_results_using_output(mock_test_list, mock_output, mock_editor_log) + results = mock_test_suite._get_results_using_output(mock_test_list, mock_output, '') assert mock_create.called assert len(results) == 1 + assert results[mock_test.__name__] == mock_fail @mock.patch('ly_test_tools.o3de.editor_test.Result.Unknown.create') @mock.patch('ly_test_tools.o3de.editor_test_utils.get_module_filename') @@ -531,12 +500,13 @@ class TestUtils(unittest.TestCase): mock_output = 'JSON_START(' \ '{"name": "mock_module_name", "output": "mock_std_out", "failed": "mock_fail_data"}' \ ')JSON_END' - mock_editor_log = 'JSON_START(' \ - ')JSON_END' + mock_unknown = mock.MagicMock() + mock_create.return_value = mock_unknown - results = mock_test_suite._get_results_using_output(mock_test_list, mock_output, mock_editor_log) + results = mock_test_suite._get_results_using_output(mock_test_list, mock_output, '') assert mock_create.called assert len(results) == 1 + assert results[mock_test.__name__] == mock_unknown @mock.patch('ly_test_tools.o3de.editor_test.Result.Pass.create') @mock.patch('ly_test_tools.o3de.editor_test.Result.Fail.create') @@ -567,7 +537,13 @@ class TestUtils(unittest.TestCase): ')JSON_END' \ 'JSON_START(' \ '{"name": "mock_module_name_fail"}' \ - ')JSON_END' \ + ')JSON_END' + mock_unknown = mock.MagicMock() + mock_pass = mock.MagicMock() + mock_fail = mock.MagicMock() + mock_create_unknown.return_value = mock_unknown + mock_create_pass.return_value = mock_pass + mock_create_fail.return_value = mock_fail results = mock_test_suite._get_results_using_output(mock_test_list, mock_output, mock_editor_log) mock_create_pass.assert_called_with( @@ -577,6 +553,9 @@ class TestUtils(unittest.TestCase): mock_create_unknown.assert_called_with( mock_test_unknown, mock_output, "Couldn't find any test run information on stdout", mock_editor_log) assert len(results) == 3 + assert results[mock_test_pass.__name__] == mock_pass + assert results[mock_test_fail.__name__] == mock_fail + assert results[mock_test_unknown.__name__] == mock_unknown @mock.patch('builtins.print') def test_ReportResult_TestPassed_ReportsCorrectly(self, mock_print): diff --git a/Tools/LyTestTools/tests/unit/test_pytest_plugin_editor_test.py b/Tools/LyTestTools/tests/unit/test_pytest_plugin_editor_test.py index 968c07aca6..10c779e546 100644 --- a/Tools/LyTestTools/tests/unit/test_pytest_plugin_editor_test.py +++ b/Tools/LyTestTools/tests/unit/test_pytest_plugin_editor_test.py @@ -38,4 +38,4 @@ class TestEditorTest(unittest.TestCase): generator = editor_test.pytest_collection_modifyitems(mock_session, mock_items, mock_config) for x in generator: pass - assert mock_class.pytest_custom_modify_items.call_count == 1 \ No newline at end of file + assert mock_class.pytest_custom_modify_items.call_count == 1 From 90bd09ffcaad68d9fa311b2dd6e6688c0d7450e2 Mon Sep 17 00:00:00 2001 From: evanchia Date: Mon, 18 Oct 2021 14:13:31 -0700 Subject: [PATCH 07/77] Fixing minor details in unit tests Signed-off-by: evanchia --- .../tests/unit/test_o3de_editor_test.py | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py b/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py index 2ba5a8ed6c..f16f7533d4 100644 --- a/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py +++ b/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py @@ -31,7 +31,7 @@ class TestEditorTestBase(unittest.TestCase): assert mock_editorsharedtest.is_batchable == True assert mock_editorsharedtest.is_parallelizable == False -class TestBase(unittest.TestCase): +class TestResultBase(unittest.TestCase): def setUp(self): self.mock_result = editor_test.Result.Base() @@ -52,7 +52,7 @@ class TestBase(unittest.TestCase): self.mock_result.editor_log = None assert self.mock_result.get_editor_log_str() == '-- No editor log found --' -class TestPass(unittest.TestCase): +class TestResultPass(unittest.TestCase): def test_Create_ValidArgs_CorrectAttributes(self): mock_test_spec = mock.MagicMock() @@ -72,7 +72,7 @@ class TestPass(unittest.TestCase): mock_pass = editor_test.Result.Pass.create(mock_test_spec, mock_output, mock_editor_log) assert mock_output in str(mock_pass) -class TestFail(unittest.TestCase): +class TestResultFail(unittest.TestCase): def test_Create_ValidArgs_CorrectAttributes(self): mock_test_spec = mock.MagicMock() @@ -93,7 +93,7 @@ class TestFail(unittest.TestCase): assert mock_output in str(mock_pass) assert mock_editor_log in str(mock_pass) -class TestCrash(unittest.TestCase): +class TestResultCrash(unittest.TestCase): def test_Create_ValidArgs_CorrectAttributes(self): mock_test_spec = mock.MagicMock() @@ -134,7 +134,7 @@ class TestCrash(unittest.TestCase): assert mock_output in str(mock_pass) assert mock_editor_log in str(mock_pass) -class Timeout(unittest.TestCase): +class TestResultTimeout(unittest.TestCase): def test_Create_ValidArgs_CorrectAttributes(self): mock_test_spec = mock.MagicMock() @@ -158,7 +158,7 @@ class Timeout(unittest.TestCase): assert mock_output in str(mock_pass) assert mock_editor_log in str(mock_pass) -class Unknown(unittest.TestCase): +class TestResultUnknown(unittest.TestCase): def test_Create_ValidArgs_CorrectAttributes(self): mock_test_spec = mock.MagicMock() @@ -185,7 +185,7 @@ class Unknown(unittest.TestCase): class TestEditorTestSuite(unittest.TestCase): @mock.patch('ly_test_tools.o3de.editor_test_utils.kill_all_ly_processes') - def test_EditorTestData_ValidAP_TeardownProperly(self, mock_kill_processes): + def test_EditorTestData_ValidAP_TeardownAPOnce(self, mock_kill_processes): mock_editor_test_suite = editor_test.EditorTestSuite() mock_test_data_generator = mock_editor_test_suite._editor_test_data(mock.MagicMock()) mock_asset_processor = mock.MagicMock() @@ -197,30 +197,13 @@ class TestEditorTestSuite(unittest.TestCase): mock_kill_processes.assert_called_once_with(include_asset_processor=True) @mock.patch('ly_test_tools.o3de.editor_test_utils.kill_all_ly_processes') - def test_EditorTestData_NoAP_TeardownProperly(self, mock_kill_processes): + def test_EditorTestData_NoAP_NoTeardownAP(self, mock_kill_processes): mock_editor_test_suite = editor_test.EditorTestSuite() mock_test_data_generator = mock_editor_test_suite._editor_test_data(mock.MagicMock()) for test_data in mock_test_data_generator: test_data.asset_processor = None mock_kill_processes.assert_called_once_with(include_asset_processor=False) - def test_RunnerInit_ValidArgs_InitProperly(self): - mock_name = mock.MagicMock() - mock_func = mock.MagicMock() - mock_tests = mock.MagicMock() - - mock_runner = editor_test.EditorTestSuite.Runner(mock_name, mock_func, mock_tests) - mock_runner.name = mock_name - mock_runner.func = mock_func - mock_runner.tests = mock_tests - mock_runner.run_pytestfunc = None - mock_runner.result_pytestfuncs = [] - - def test_PytestCustomMakeitem_Called_ReturnsClass(self): - mock_test_class = editor_test.EditorTestSuite.pytest_custom_makeitem(mock.MagicMock(), mock.MagicMock(), - mock.MagicMock()) - assert isinstance(mock_test_class, editor_test.EditorTestSuite.EditorTestClass) - @mock.patch('ly_test_tools.o3de.editor_test.EditorTestSuite.filter_session_shared_tests') def test_PytestCustomModifyItems_FunctionsMatch_AddsRunners(self, mock_filter_tests): class MockTestSuite(editor_test.EditorTestSuite): @@ -323,6 +306,7 @@ class TestEditorTestSuite(unittest.TestCase): selected_tests = editor_test.EditorTestSuite.filter_session_shared_tests(mock_session_items, mock_shared_tests) assert selected_tests == mock_session_items + assert len(selected_tests) == 1 @mock.patch('ly_test_tools.o3de.editor_test.skipping_pytest_runtest_setup', mock.MagicMock()) def test_FilterSessionSharedTests_ManyTests_ReturnsCorrectTests(self): @@ -344,8 +328,29 @@ class TestEditorTestSuite(unittest.TestCase): selected_tests = editor_test.EditorTestSuite.filter_session_shared_tests(mock_session_items, mock_shared_tests) assert selected_tests == mock_session_items + @mock.patch('ly_test_tools.o3de.editor_test.skipping_pytest_runtest_setup') + def test_FilterSessionSharedTests_SkipOneTest_ReturnsCorrectTests(self, mock_skip): + def mock_test(): + pass + def mock_test_2(): + pass + def mock_test_3(): + pass + mock_skip.side_effect = [True, Exception] + mock_test.originalname = 'mock_test' + mock_test.__name__ = mock_test.originalname + mock_test_2.originalname = 'mock_test_2' + mock_test_2.__name__ = mock_test_2.originalname + mock_test_3.originalname = 'mock_test_3' + mock_test_3.__name__ = mock_test_3.originalname + mock_session_items = [mock_test, mock_test_2] + mock_shared_tests = [mock_test, mock_test_2, mock_test_3] + + selected_tests = editor_test.EditorTestSuite.filter_session_shared_tests(mock_session_items, mock_shared_tests) + assert selected_tests == [mock_test] + @mock.patch('ly_test_tools.o3de.editor_test.skipping_pytest_runtest_setup', mock.MagicMock(side_effect=Exception)) - def test_FilterSessionSharedTests_SkippingPytestRaises_SkipsAddingTest(self): + def test_FilterSessionSharedTests_ExceptionDuringSkipSetup_SkipsAddingTest(self): def mock_test(): pass mock_test.originalname = 'mock_test' @@ -365,7 +370,8 @@ class TestEditorTestSuite(unittest.TestCase): mock_test_2.is_parallelizable = False mock_shared_tests = [mock_test, mock_test_2] - filtered_tests = editor_test.EditorTestSuite.filter_shared_tests(mock_shared_tests, True, True) + filtered_tests = editor_test.EditorTestSuite.filter_shared_tests( + mock_shared_tests, is_batchable=True, is_parallelizable=True) assert filtered_tests == [mock_test] def test_FilterSharedTests_FalseParams_ReturnsFalseTests(self): @@ -377,7 +383,8 @@ class TestEditorTestSuite(unittest.TestCase): mock_test_2.is_parallelizable = False mock_shared_tests = [mock_test, mock_test_2] - filtered_tests = editor_test.EditorTestSuite.filter_shared_tests(mock_shared_tests, False, False) + filtered_tests = editor_test.EditorTestSuite.filter_shared_tests( + mock_shared_tests, is_batchable=False, is_parallelizable=False) assert filtered_tests == [mock_test_2] class TestUtils(unittest.TestCase): From f1a38ded86e02d436f061937b6f11585862739a3 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 18 Oct 2021 16:09:54 -0700 Subject: [PATCH 08/77] fixes warning in release Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Code/Source/Material/EditorMaterialSystemComponent.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp index 5df17a5478..2e1c7f0bd6 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp @@ -192,6 +192,9 @@ namespace AZ AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath), propertyOverrides), [entityId, materialAssignmentId]() { + AZ_UNUSED(entityId); + AZ_UNUSED(materialAssignmentId); + AZ_Warning( "EditorMaterialSystemComponent", false, "RenderMaterialPreview capture failed for entity %s slot %s.", entityId.ToString().c_str(), materialAssignmentId.ToString().c_str()); From c842fce4bfcc7cba9bb4f7f734a1cd160239c5e3 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 18 Oct 2021 16:13:35 -0700 Subject: [PATCH 09/77] WIP, need to merge from development Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Install.cmake | 2 +- cmake/Packaging.cmake | 35 ++++++++--- cmake/Platform/Common/Install_common.cmake | 73 +++++++++++++++------- cmake/Platform/Mac/Install_mac.cmake | 43 +++++++------ 4 files changed, 100 insertions(+), 53 deletions(-) diff --git a/cmake/Install.cmake b/cmake/Install.cmake index adcd28fa37..4816d475fc 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -168,4 +168,4 @@ function(ly_install_run_script SCRIPT) COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being ) -endfunction() \ No newline at end of file +endfunction() diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 9f62b89e39..25f9b87cbc 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -136,6 +136,7 @@ endif() install(FILES ${_cmake_package_dest} DESTINATION ./Tools/Redistributables/CMake + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) # the version string and git tags are intended to be synchronized so it should be safe to use that instead @@ -159,6 +160,7 @@ if(${CPACK_PACKAGE_VERSION} VERSION_GREATER "0.0.0.0") if (${_status_code} EQUAL 0 AND EXISTS ${_3rd_party_license_dest}) install(FILES ${_3rd_party_license_dest} DESTINATION . + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) else() file(REMOVE ${_3rd_party_license_dest}) @@ -242,29 +244,35 @@ ly_configure_cpack_component( DISPLAY_NAME "${PROJECT_NAME}" DESCRIPTION "${PROJECT_NAME} Headers, scripts and common files" ) -#file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "set(LY_CPACK_COMPONENTS_ALL ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME})\n") + +file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "set(LY_CPACK_COMPONENTS_ALL ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME})\n") foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) string(TOUPPER ${conf} UCONF) unset(flags) - if(${conf} STREQUAL profile) + if(${conf} STREQUAL profile AND ${LY_BUILD_PERMUTATION} STREQUAL Default) set(flags REQUIRED) else() set(flags DISABLED) endif() + unset(permutation_description) + if(${LY_BUILD_PERMUTATION} STREQUAL Monolithic) + set(permutation_description " monolithic ") + endif() + # Inject a check to not declare components that have not been built. We are using AzCore since that is a # common target that will always be build, in every permutation and configuration - #file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" - # "if(EXISTS \"${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${conf}/${CMAKE_STATIC_LIBRARY_PREFIX}AzCore${CMAKE_STATIC_LIBRARY_SUFFIX}\")\n") + file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" + "if(EXISTS \"${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${conf}/${CMAKE_STATIC_LIBRARY_PREFIX}AzCore${CMAKE_STATIC_LIBRARY_SUFFIX}\")\n") ly_configure_cpack_component( - ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} ${flags} + ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} ${flags} DISPLAY_NAME "${PROJECT_NAME} (${conf})" - DESCRIPTION "${PROJECT_NAME} Libraries and Tools in ${conf}" + DESCRIPTION "${PROJECT_NAME} Libraries and Tools in${permutation_description}${conf}" ) - #file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" -#"list(APPEND LY_CPACK_COMPONENTS_ALL ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF}) -#endif()\n") + file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" +"list(APPEND LY_CPACK_COMPONENTS_ALL ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF}) +endif()\n") endforeach() @@ -279,4 +287,11 @@ if(LY_INSTALLER_DOWNLOAD_URL) ) endif() -#file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "set(CPACK_COMPONENTS_ALL \${LY_CPACK_COMPONENTS_ALL})\n") +# Inject other build directories +foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS}) + file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" + "include(${external_dir}/CPackConfig.cmake)\n" + ) +endforeach() + +file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "set(CPACK_COMPONENTS_ALL \${LY_CPACK_COMPONENTS_ALL})\n") diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 224d6ccffc..0adb63f08e 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -8,6 +8,8 @@ include(cmake/FileUtil.cmake) +set(LY_INSTALL_EXTERNAL_BUILD_DIRS "" CACHE PATH "External build directories to be included in the install process. This allows to package non-monolithic and monolithic.") + set(CMAKE_INSTALL_MESSAGE NEVER) # Simplify messages to reduce output noise define_property(TARGET PROPERTY LY_INSTALL_GENERATE_RUN_TARGET @@ -19,12 +21,25 @@ define_property(TARGET PROPERTY LY_INSTALL_GENERATE_RUN_TARGET ]] ) -ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Core) +# We can have elements being installed under the following components: +# - Core (required for all) (default) +# - Default +# - Default_$ +# - Monolithic +# - Monolithic_$ +# Debug/Monolithic are build permutations, so for a CMake run, it can only generate +# one of the permutations. Each build permutation can generate only one cmake_install.cmake. +# Each build permutation will generate the same elements in Core. +# CPack is able to put the two together by taking Core from one permutation and then taking +# each permutation. +ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Core) if(LY_MONOLITHIC_GAME) set(LY_BUILD_PERMUTATION Monolithic) + set(LY_INSTALL_PERMUTATION_COMPONENT Monolithic) else() set(LY_BUILD_PERMUTATION Default) + set(LY_INSTALL_PERMUTATION_COMPONENT Default) endif() cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory) @@ -106,19 +121,18 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar else() foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) string(TOUPPER ${conf} UCONF) - install( - TARGETS ${TARGET_NAME} + install(TARGETS ${TARGET_NAME} ARCHIVE DESTINATION ${archive_output_directory} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} CONFIGURATIONS ${conf} LIBRARY DESTINATION ${library_output_directory}/${target_library_output_subdirectory} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} CONFIGURATIONS ${conf} RUNTIME DESTINATION ${runtime_output_directory}/${target_runtime_output_subdirectory} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} CONFIGURATIONS ${conf} ) endforeach() @@ -275,10 +289,15 @@ set_property(TARGET ${NAME_PLACEHOLDER} set(target_install_source_dir ${CMAKE_CURRENT_BINARY_DIR}/install/${relative_target_source_dir}) file(GENERATE OUTPUT "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") - install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/${NAME_PLACEHOLDER}_$.cmake" - DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/${NAME_PLACEHOLDER}_${conf}.cmake" + DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + ) + endforeach() # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target ly_file_read(${LY_ROOT_FOLDER}/cmake/install/InstalledTarget.in target_cmakelists_template) @@ -353,9 +372,10 @@ endif() "${GEM_VARIANT_TO_LOAD_PLACEHOLDER}" "${ENABLE_GEMS_PLACEHOLDER}" ) + install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/permutation.cmake" - DESTINATION ${relative_target_source_dir}//Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} + DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT} ) endfunction() @@ -377,6 +397,11 @@ function(ly_setup_o3de_install) COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + # Inject other build directories + foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS}) + install(CODE "include(${external_dir}/cmake_install.cmake)") + endforeach() + if(COMMAND ly_post_install_steps) ly_post_install_steps() endif() @@ -399,18 +424,19 @@ function(ly_setup_cmake_install) DESTINATION cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - # Inject code that will generate each ConfigurationType_.cmake file - set(install_configuration_type_template [=[ - configure_file(@LY_ROOT_FOLDER@/cmake/install/ConfigurationType_config.cmake.in - ${CMAKE_INSTALL_PREFIX}/cmake/Platform/@PAL_PLATFORM_NAME@/@LY_BUILD_PERMUTATION@/ConfigurationTypes_${CMAKE_INSTALL_CONFIG_NAME}.cmake + # generate each ConfigurationType_.cmake file and install it under that configuration + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + configure_file("${LY_ROOT_FOLDER}/cmake/install/ConfigurationType_config.cmake.in" + "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/ConfigurationTypes_${conf}.cmake" @ONLY ) - message(STATUS "Generated ${CMAKE_INSTALL_PREFIX}/cmake/Platform/@PAL_PLATFORM_NAME@/@LY_BUILD_PERMUTATION@/ConfigurationTypes_${CMAKE_INSTALL_CONFIG_NAME}.cmake") - ]=]) - string(CONFIGURE "${install_configuration_type_template}" install_configuration_type @ONLY) - install(CODE "${install_configuration_type}" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + install(FILES "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/ConfigurationTypes_${conf}.cmake" + DESTINATION cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + ) + endforeach() # Transform the LY_EXTERNAL_SUBDIRS list into a json array set(indent " ") @@ -429,8 +455,7 @@ function(ly_setup_cmake_install) configure_file(${LY_ROOT_FOLDER}/cmake/install/engine.json.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json @ONLY) - install( - FILES + install(FILES "${LY_ROOT_FOLDER}/CMakeLists.txt" "${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json" DESTINATION . diff --git a/cmake/Platform/Mac/Install_mac.cmake b/cmake/Platform/Mac/Install_mac.cmake index bdc2300131..472831425b 100644 --- a/cmake/Platform/Mac/Install_mac.cmake +++ b/cmake/Platform/Mac/Install_mac.cmake @@ -58,24 +58,31 @@ function(ly_install_target_override) set_property(TARGET ${ly_platform_install_target_TARGET} PROPERTY RESOURCE "") endif() - install( - TARGETS ${ly_platform_install_target_TARGET} - ARCHIVE - DESTINATION ${ly_platform_install_target_ARCHIVE_DIR} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - LIBRARY - DESTINATION ${ly_platform_install_target_LIBRARY_DIR}/${ly_platform_install_target_LIBRARY_SUBDIR} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - RUNTIME - DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - BUNDLE - DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - RESOURCE - DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + install(TARGETS ${TARGET_NAME} + ARCHIVE + DESTINATION ${ly_platform_install_target_ARCHIVE_DIR} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + LIBRARY + DESTINATION ${ly_platform_install_target_LIBRARY_DIR}/${ly_platform_install_target_LIBRARY_SUBDIR} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + RUNTIME + DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + BUNDLE + DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + RESOURCE + DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + ) + endforeach() set(install_relative_binaries_path "${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR}") From 62a5aa18748cafb0aeab26a574666539c1a8c823 Mon Sep 17 00:00:00 2001 From: evanchia Date: Mon, 18 Oct 2021 18:15:46 -0700 Subject: [PATCH 10/77] fixing test breaking changes Signed-off-by: evanchia --- Tools/LyTestTools/ly_test_tools/o3de/editor_test.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py index 789d07f200..0bc341012c 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py @@ -326,7 +326,7 @@ class EditorTestSuite(): :request: The Pytest request :yield: The TestData object """ - self._editor_test_data(request) + yield from self._editor_test_data(request) def _editor_test_data(self, request): """ @@ -676,7 +676,6 @@ class EditorTestSuite(): elem = json.loads(m.groups()[0]) found_jsons[elem["name"]] = elem except Exception as e: - raise e continue # Avoid to fail if the output data is corrupt # Try to find the element in the log, this is used for cutting the log contents later @@ -710,7 +709,7 @@ class EditorTestSuite(): cur_log = editor_log_content[log_start : end] log_start = end - if "success" in json_result.keys(): + if json_result["success"]: result = Result.Pass.create(test_spec, json_output, cur_log) else: result = Result.Fail.create(test_spec, json_output, cur_log) From 64a20c45b56551d7f0841e2702cca7d05df61fc5 Mon Sep 17 00:00:00 2001 From: evanchia Date: Tue, 19 Oct 2021 15:51:44 -0700 Subject: [PATCH 11/77] adding editor integ tests to AR Signed-off-by: evanchia --- .../Gem/PythonTests/CMakeLists.txt | 3 + .../editor_test_testing/CMakeLists.txt | 38 +++ .../TestSuiteLinux_Main.py | 267 ++++++++++++++++++ ...Suite_Main.py => TestSuiteWindows_Main.py} | 7 +- .../launchers/launcher_helper.py | 2 +- 5 files changed, 315 insertions(+), 2 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/editor_test_testing/CMakeLists.txt create mode 100644 AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteLinux_Main.py rename AutomatedTesting/Gem/PythonTests/editor_test_testing/{TestSuite_Main.py => TestSuiteWindows_Main.py} (98%) diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt index 466a4b1679..7af10dba66 100644 --- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt @@ -58,3 +58,6 @@ add_subdirectory(smoke) ## AWS ## add_subdirectory(AWS) + +## Test Tools ## +add_subdirectory(editor_test_testing) diff --git a/AutomatedTesting/Gem/PythonTests/editor_test_testing/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/editor_test_testing/CMakeLists.txt new file mode 100644 index 0000000000..fac6192673 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/editor_test_testing/CMakeLists.txt @@ -0,0 +1,38 @@ +# +# 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 +# + +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) + + ly_add_pytest( + NAME AutomatedTesting::ParallelEditorTestsWindows + TEST_SUITE main + TEST_SERIAL + PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuiteWindows_Main.py + PYTEST_MARKS "SUITE_main" + RUNTIME_DEPENDENCIES + AZ::AssetProcessor + Legacy::Editor + AutomatedTesting.Assets + COMPONENT + TestTools + ) + + ly_add_pytest( + NAME AutomatedTesting::ParallelEditorTestsLinux + TEST_SUITE main + TEST_SERIAL + PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuiteLinux_Main.py + PYTEST_MARKS "SUITE_main" + RUNTIME_DEPENDENCIES + AZ::AssetProcessor + Legacy::Editor + AutomatedTesting.Assets + COMPONENT + TestTools + ) + +endif() diff --git a/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteLinux_Main.py b/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteLinux_Main.py new file mode 100644 index 0000000000..8686c43357 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteLinux_Main.py @@ -0,0 +1,267 @@ +""" +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 +""" + +""" +This suite contains the tests for editor_test utilities. +""" + +import pytest +import os +import sys +import importlib +import re + +import ly_test_tools +from ly_test_tools import LAUNCHERS + +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorTestSuite, Result +from ly_test_tools.o3de.asset_processor import AssetProcessor +import ly_test_tools.environment.process_utils as process_utils + +import argparse, sys + +if ly_test_tools.LINUX: + pytestmark = pytest.mark.SUITE_main +else: + pytestmark = pytest.mark.skipif(not ly_test_tools.LINUX, reason="Only runs on Linux") + +@pytest.mark.parametrize("launcher_platform", ['linux_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestEditorTest: + + args = None + path = None + @classmethod + def setup_class(cls): + TestEditorTest.args = sys.argv.copy() + build_dir_arg_index = TestEditorTest.args.index("--build-directory") + if build_dir_arg_index < 0: + print("Error: Must pass --build-directory argument in order to run this test") + sys.exit(-2) + + TestEditorTest.args[build_dir_arg_index+1] = os.path.abspath(TestEditorTest.args[build_dir_arg_index+1]) + TestEditorTest.args.append("-s") + TestEditorTest.path = os.path.dirname(os.path.abspath(__file__)) + cls._asset_processor = None + + def teardown_class(cls): + if cls._asset_processor: + cls._asset_processor.stop(1) + cls._asset_processor.teardown() + + # Test runs # + @classmethod + def _run_single_test(cls, testdir, workspace, module_name): + if cls._asset_processor is None: + if not process_utils.process_exists("AssetProcessor", ignore_extensions=True): + cls._asset_processor = AssetProcessor(workspace) + cls._asset_processor.start() + + testdir.makepyfile( + f""" + import pytest + import os + import sys + + from ly_test_tools import LAUNCHERS + from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorTestSuite + + @pytest.mark.SUITE_main + @pytest.mark.parametrize("launcher_platform", ['linux_editor']) + @pytest.mark.parametrize("project", ["AutomatedTesting"]) + class TestAutomation(EditorTestSuite): + class test_single(EditorSingleTest): + import {module_name} as test_module + + """) + result = testdir.runpytest(*TestEditorTest.args[2:]) + + def get_class(module_name): + class test_single(EditorSingleTest): + test_module = importlib.import_module(module_name) + return test_single + + output = "".join(result.outlines) + extracted_results = EditorTestSuite._get_results_using_output([get_class(module_name)], output, output) + extracted_result = next(iter(extracted_results.items())) + return (extracted_result[1], result) + + def test_single_passing_test(self, request, workspace, launcher_platform, testdir): + (extracted_result, result) = TestEditorTest._run_single_test(testdir, workspace, "EditorTest_That_Passes") + result.assert_outcomes(passed=1) + assert isinstance(extracted_result, Result.Pass) + + def test_single_failing_test(self, request, workspace, launcher_platform, testdir): + (extracted_result, result) = TestEditorTest._run_single_test(testdir, workspace, "EditorTest_That_Fails") + result.assert_outcomes(failed=1) + assert isinstance(extracted_result, Result.Fail) + + def test_single_crashing_test(self, request, workspace, launcher_platform, testdir): + (extracted_result, result) = TestEditorTest._run_single_test(testdir, workspace, "EditorTest_That_Crashes") + result.assert_outcomes(failed=1) + assert isinstance(extracted_result, Result.Unknown) + + @classmethod + def _run_shared_test(cls, testdir, module_class_code, extra_cmd_line=None): + if not extra_cmd_line: + extra_cmd_line = [] + + if cls._asset_processor is None: + if not process_utils.process_exists("AssetProcessor", ignore_extensions=True): + cls._asset_processor = AssetProcessor(workspace) + cls._asset_processor.start() + + testdir.makepyfile( + f""" + import pytest + import os + import sys + + from ly_test_tools import LAUNCHERS + from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorTestSuite + + @pytest.mark.SUITE_main + @pytest.mark.parametrize("launcher_platform", ['linux_editor']) + @pytest.mark.parametrize("project", ["AutomatedTesting"]) + class TestAutomation(EditorTestSuite): + {module_class_code} + """) + result = testdir.runpytest(*TestEditorTest.args[2:] + extra_cmd_line) + return result + + def test_batched_two_passing(self, request, workspace, launcher_platform, testdir): + result = self._run_shared_test(testdir, + """ + class test_pass(EditorSharedTest): + import EditorTest_That_Passes as test_module + is_parallelizable = False + + class test_2(EditorSharedTest): + import EditorTest_That_PassesToo as test_module + is_parallelizable = False + """ + ) + # 2 Passes +1(batch runner) + result.assert_outcomes(passed=3) + + def test_batched_one_pass_one_fail(self, request, workspace, launcher_platform, testdir): + result = self._run_shared_test(testdir, + """ + class test_pass(EditorSharedTest): + import EditorTest_That_Passes as test_module + is_parallelizable = False + + class test_fail(EditorSharedTest): + import EditorTest_That_Fails as test_module + is_parallelizable = False + """ + ) + # 1 Fail, 1 Passes +1(batch runner) + result.assert_outcomes(passed=2, failed=1) + + def test_batched_one_pass_one_fail_one_crash(self, request, workspace, launcher_platform, testdir): + result = self._run_shared_test(testdir, + """ + class test_pass(EditorSharedTest): + import EditorTest_That_Passes as test_module + is_parallelizable = False + + class test_fail(EditorSharedTest): + import EditorTest_That_Fails as test_module + is_parallelizable = False + + class test_crash(EditorSharedTest): + import EditorTest_That_Crashes as test_module + is_parallelizable = False + """ + ) + # 2 Fail, 1 Passes + 1(batch runner) + result.assert_outcomes(passed=2, failed=2) + + def test_parallel_two_passing(self, request, workspace, launcher_platform, testdir): + result = self._run_shared_test(testdir, + """ + class test_pass_1(EditorSharedTest): + import EditorTest_That_Passes as test_module + is_batchable = False + + class test_pass_2(EditorSharedTest): + import EditorTest_That_PassesToo as test_module + is_batchable = False + """ + ) + # 2 Passes +1(parallel runner) + result.assert_outcomes(passed=3) + + def test_parallel_one_passing_one_failing_one_crashing(self, request, workspace, launcher_platform, testdir): + result = self._run_shared_test(testdir, + """ + class test_pass(EditorSharedTest): + import EditorTest_That_Passes as test_module + is_batchable = False + + class test_fail(EditorSharedTest): + import EditorTest_That_Fails as test_module + is_batchable = False + + class test_crash(EditorSharedTest): + import EditorTest_That_Crashes as test_module + is_batchable = False + """ + ) + # 2 Fail, 1 Passes + 1(parallel runner) + result.assert_outcomes(passed=2, failed=2) + + def test_parallel_batched_two_passing(self, request, workspace, launcher_platform, testdir): + result = self._run_shared_test(testdir, + """ + class test_pass_1(EditorSharedTest): + import EditorTest_That_Passes as test_module + + class test_pass_2(EditorSharedTest): + import EditorTest_That_PassesToo as test_module + """ + ) + # 2 Passes +1(batched+parallel runner) + result.assert_outcomes(passed=3) + + def test_parallel_batched_one_passing_one_failing_one_crashing(self, request, workspace, launcher_platform, testdir): + result = self._run_shared_test(testdir, + """ + class test_pass(EditorSharedTest): + import EditorTest_That_Passes as test_module + + class test_fail(EditorSharedTest): + import EditorTest_That_Fails as test_module + + class test_crash(EditorSharedTest): + import EditorTest_That_Crashes as test_module + """ + ) + # 2 Fail, 1 Passes + 1(batched+parallel runner) + result.assert_outcomes(passed=2, failed=2) + + def test_selection_2_deselected_1_selected(self, request, workspace, launcher_platform, testdir): + result = self._run_shared_test(testdir, + """ + class test_pass(EditorSharedTest): + import EditorTest_That_Passes as test_module + + class test_fail(EditorSharedTest): + import EditorTest_That_Fails as test_module + + class test_crash(EditorSharedTest): + import EditorTest_That_Crashes as test_module + """, extra_cmd_line=["-k", "fail"] + ) + # 1 Fail + 1 Success(parallel runner) + result.assert_outcomes(failed=1, passed=1) + outcomes = result.parseoutcomes() + deselected = outcomes.get("deselected") + assert deselected == 2 diff --git a/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteWindows_Main.py similarity index 98% rename from AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py rename to AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteWindows_Main.py index 7c7e063951..3643ab8145 100644 --- a/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteWindows_Main.py @@ -15,6 +15,7 @@ import sys import importlib import re +import ly_test_tools from ly_test_tools import LAUNCHERS sys.path.append(os.path.dirname(os.path.abspath(__file__))) @@ -25,7 +26,11 @@ import ly_test_tools.environment.process_utils as process_utils import argparse, sys -@pytest.mark.SUITE_main +if ly_test_tools.WINDOWS: + pytestmark = pytest.mark.SUITE_main +else: + pytestmark = pytest.mark.skipif(not ly_test_tools.WINDOWS, reason="Only runs on Windows") + @pytest.mark.parametrize("launcher_platform", ['windows_editor']) @pytest.mark.parametrize("project", ["AutomatedTesting"]) class TestEditorTest: diff --git a/Tools/LyTestTools/ly_test_tools/launchers/launcher_helper.py b/Tools/LyTestTools/ly_test_tools/launchers/launcher_helper.py index d37623f352..e4552ec119 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/launcher_helper.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/launcher_helper.py @@ -51,7 +51,7 @@ def create_editor(workspace, launcher_platform=ly_test_tools.HOST_OS_EDITOR, arg Editor is only officially supported on the Windows Platform. :param workspace: lumberyard workspace to use - :param launcher_platform: the platform to target for a launcher (i.e. 'windows_dedicated' for DedicatedWinLauncher) + :param launcher_platform: the platform to target for a launcher (i.e. 'windows_dedicated' for DedicatedWinLauncher) :param args: List of arguments to pass to the launcher's 'args' argument during construction :return: Editor instance """ From 11c31cb5ca0ee09aa78d52bf889efb36d860decf Mon Sep 17 00:00:00 2001 From: evanchia Date: Thu, 21 Oct 2021 10:48:33 -0700 Subject: [PATCH 12/77] removed platform specific tests and consolodated Signed-off-by: evanchia --- .../editor_test_testing/CMakeLists.txt | 16 +- .../TestSuiteLinux_Main.py | 267 ------------------ ...SuiteWindows_Main.py => TestSuite_Main.py} | 12 +- 3 files changed, 10 insertions(+), 285 deletions(-) delete mode 100644 AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteLinux_Main.py rename AutomatedTesting/Gem/PythonTests/editor_test_testing/{TestSuiteWindows_Main.py => TestSuite_Main.py} (96%) diff --git a/AutomatedTesting/Gem/PythonTests/editor_test_testing/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/editor_test_testing/CMakeLists.txt index fac6192673..04a7c6de0b 100644 --- a/AutomatedTesting/Gem/PythonTests/editor_test_testing/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/editor_test_testing/CMakeLists.txt @@ -11,21 +11,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) NAME AutomatedTesting::ParallelEditorTestsWindows TEST_SUITE main TEST_SERIAL - PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuiteWindows_Main.py - PYTEST_MARKS "SUITE_main" - RUNTIME_DEPENDENCIES - AZ::AssetProcessor - Legacy::Editor - AutomatedTesting.Assets - COMPONENT - TestTools - ) - - ly_add_pytest( - NAME AutomatedTesting::ParallelEditorTestsLinux - TEST_SUITE main - TEST_SERIAL - PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuiteLinux_Main.py + PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py PYTEST_MARKS "SUITE_main" RUNTIME_DEPENDENCIES AZ::AssetProcessor diff --git a/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteLinux_Main.py b/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteLinux_Main.py deleted file mode 100644 index 8686c43357..0000000000 --- a/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteLinux_Main.py +++ /dev/null @@ -1,267 +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 -""" - -""" -This suite contains the tests for editor_test utilities. -""" - -import pytest -import os -import sys -import importlib -import re - -import ly_test_tools -from ly_test_tools import LAUNCHERS - -sys.path.append(os.path.dirname(os.path.abspath(__file__))) - -from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorTestSuite, Result -from ly_test_tools.o3de.asset_processor import AssetProcessor -import ly_test_tools.environment.process_utils as process_utils - -import argparse, sys - -if ly_test_tools.LINUX: - pytestmark = pytest.mark.SUITE_main -else: - pytestmark = pytest.mark.skipif(not ly_test_tools.LINUX, reason="Only runs on Linux") - -@pytest.mark.parametrize("launcher_platform", ['linux_editor']) -@pytest.mark.parametrize("project", ["AutomatedTesting"]) -class TestEditorTest: - - args = None - path = None - @classmethod - def setup_class(cls): - TestEditorTest.args = sys.argv.copy() - build_dir_arg_index = TestEditorTest.args.index("--build-directory") - if build_dir_arg_index < 0: - print("Error: Must pass --build-directory argument in order to run this test") - sys.exit(-2) - - TestEditorTest.args[build_dir_arg_index+1] = os.path.abspath(TestEditorTest.args[build_dir_arg_index+1]) - TestEditorTest.args.append("-s") - TestEditorTest.path = os.path.dirname(os.path.abspath(__file__)) - cls._asset_processor = None - - def teardown_class(cls): - if cls._asset_processor: - cls._asset_processor.stop(1) - cls._asset_processor.teardown() - - # Test runs # - @classmethod - def _run_single_test(cls, testdir, workspace, module_name): - if cls._asset_processor is None: - if not process_utils.process_exists("AssetProcessor", ignore_extensions=True): - cls._asset_processor = AssetProcessor(workspace) - cls._asset_processor.start() - - testdir.makepyfile( - f""" - import pytest - import os - import sys - - from ly_test_tools import LAUNCHERS - from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorTestSuite - - @pytest.mark.SUITE_main - @pytest.mark.parametrize("launcher_platform", ['linux_editor']) - @pytest.mark.parametrize("project", ["AutomatedTesting"]) - class TestAutomation(EditorTestSuite): - class test_single(EditorSingleTest): - import {module_name} as test_module - - """) - result = testdir.runpytest(*TestEditorTest.args[2:]) - - def get_class(module_name): - class test_single(EditorSingleTest): - test_module = importlib.import_module(module_name) - return test_single - - output = "".join(result.outlines) - extracted_results = EditorTestSuite._get_results_using_output([get_class(module_name)], output, output) - extracted_result = next(iter(extracted_results.items())) - return (extracted_result[1], result) - - def test_single_passing_test(self, request, workspace, launcher_platform, testdir): - (extracted_result, result) = TestEditorTest._run_single_test(testdir, workspace, "EditorTest_That_Passes") - result.assert_outcomes(passed=1) - assert isinstance(extracted_result, Result.Pass) - - def test_single_failing_test(self, request, workspace, launcher_platform, testdir): - (extracted_result, result) = TestEditorTest._run_single_test(testdir, workspace, "EditorTest_That_Fails") - result.assert_outcomes(failed=1) - assert isinstance(extracted_result, Result.Fail) - - def test_single_crashing_test(self, request, workspace, launcher_platform, testdir): - (extracted_result, result) = TestEditorTest._run_single_test(testdir, workspace, "EditorTest_That_Crashes") - result.assert_outcomes(failed=1) - assert isinstance(extracted_result, Result.Unknown) - - @classmethod - def _run_shared_test(cls, testdir, module_class_code, extra_cmd_line=None): - if not extra_cmd_line: - extra_cmd_line = [] - - if cls._asset_processor is None: - if not process_utils.process_exists("AssetProcessor", ignore_extensions=True): - cls._asset_processor = AssetProcessor(workspace) - cls._asset_processor.start() - - testdir.makepyfile( - f""" - import pytest - import os - import sys - - from ly_test_tools import LAUNCHERS - from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorTestSuite - - @pytest.mark.SUITE_main - @pytest.mark.parametrize("launcher_platform", ['linux_editor']) - @pytest.mark.parametrize("project", ["AutomatedTesting"]) - class TestAutomation(EditorTestSuite): - {module_class_code} - """) - result = testdir.runpytest(*TestEditorTest.args[2:] + extra_cmd_line) - return result - - def test_batched_two_passing(self, request, workspace, launcher_platform, testdir): - result = self._run_shared_test(testdir, - """ - class test_pass(EditorSharedTest): - import EditorTest_That_Passes as test_module - is_parallelizable = False - - class test_2(EditorSharedTest): - import EditorTest_That_PassesToo as test_module - is_parallelizable = False - """ - ) - # 2 Passes +1(batch runner) - result.assert_outcomes(passed=3) - - def test_batched_one_pass_one_fail(self, request, workspace, launcher_platform, testdir): - result = self._run_shared_test(testdir, - """ - class test_pass(EditorSharedTest): - import EditorTest_That_Passes as test_module - is_parallelizable = False - - class test_fail(EditorSharedTest): - import EditorTest_That_Fails as test_module - is_parallelizable = False - """ - ) - # 1 Fail, 1 Passes +1(batch runner) - result.assert_outcomes(passed=2, failed=1) - - def test_batched_one_pass_one_fail_one_crash(self, request, workspace, launcher_platform, testdir): - result = self._run_shared_test(testdir, - """ - class test_pass(EditorSharedTest): - import EditorTest_That_Passes as test_module - is_parallelizable = False - - class test_fail(EditorSharedTest): - import EditorTest_That_Fails as test_module - is_parallelizable = False - - class test_crash(EditorSharedTest): - import EditorTest_That_Crashes as test_module - is_parallelizable = False - """ - ) - # 2 Fail, 1 Passes + 1(batch runner) - result.assert_outcomes(passed=2, failed=2) - - def test_parallel_two_passing(self, request, workspace, launcher_platform, testdir): - result = self._run_shared_test(testdir, - """ - class test_pass_1(EditorSharedTest): - import EditorTest_That_Passes as test_module - is_batchable = False - - class test_pass_2(EditorSharedTest): - import EditorTest_That_PassesToo as test_module - is_batchable = False - """ - ) - # 2 Passes +1(parallel runner) - result.assert_outcomes(passed=3) - - def test_parallel_one_passing_one_failing_one_crashing(self, request, workspace, launcher_platform, testdir): - result = self._run_shared_test(testdir, - """ - class test_pass(EditorSharedTest): - import EditorTest_That_Passes as test_module - is_batchable = False - - class test_fail(EditorSharedTest): - import EditorTest_That_Fails as test_module - is_batchable = False - - class test_crash(EditorSharedTest): - import EditorTest_That_Crashes as test_module - is_batchable = False - """ - ) - # 2 Fail, 1 Passes + 1(parallel runner) - result.assert_outcomes(passed=2, failed=2) - - def test_parallel_batched_two_passing(self, request, workspace, launcher_platform, testdir): - result = self._run_shared_test(testdir, - """ - class test_pass_1(EditorSharedTest): - import EditorTest_That_Passes as test_module - - class test_pass_2(EditorSharedTest): - import EditorTest_That_PassesToo as test_module - """ - ) - # 2 Passes +1(batched+parallel runner) - result.assert_outcomes(passed=3) - - def test_parallel_batched_one_passing_one_failing_one_crashing(self, request, workspace, launcher_platform, testdir): - result = self._run_shared_test(testdir, - """ - class test_pass(EditorSharedTest): - import EditorTest_That_Passes as test_module - - class test_fail(EditorSharedTest): - import EditorTest_That_Fails as test_module - - class test_crash(EditorSharedTest): - import EditorTest_That_Crashes as test_module - """ - ) - # 2 Fail, 1 Passes + 1(batched+parallel runner) - result.assert_outcomes(passed=2, failed=2) - - def test_selection_2_deselected_1_selected(self, request, workspace, launcher_platform, testdir): - result = self._run_shared_test(testdir, - """ - class test_pass(EditorSharedTest): - import EditorTest_That_Passes as test_module - - class test_fail(EditorSharedTest): - import EditorTest_That_Fails as test_module - - class test_crash(EditorSharedTest): - import EditorTest_That_Crashes as test_module - """, extra_cmd_line=["-k", "fail"] - ) - # 1 Fail + 1 Success(parallel runner) - result.assert_outcomes(failed=1, passed=1) - outcomes = result.parseoutcomes() - deselected = outcomes.get("deselected") - assert deselected == 2 diff --git a/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteWindows_Main.py b/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py similarity index 96% rename from AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteWindows_Main.py rename to AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py index 3643ab8145..9a78afdeb7 100644 --- a/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuiteWindows_Main.py +++ b/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py @@ -31,7 +31,13 @@ if ly_test_tools.WINDOWS: else: pytestmark = pytest.mark.skipif(not ly_test_tools.WINDOWS, reason="Only runs on Windows") -@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +def get_editor_launcher_platform(): + if ly_test_tools.WINDOWS: + return "windows_editor" + else: + return "linux_editor" + +@pytest.mark.parametrize("launcher_platform", [get_editor_launcher_platform()]) @pytest.mark.parametrize("project", ["AutomatedTesting"]) class TestEditorTest: @@ -73,7 +79,7 @@ class TestEditorTest: from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorTestSuite @pytest.mark.SUITE_main - @pytest.mark.parametrize("launcher_platform", ['windows_editor']) + @pytest.mark.parametrize("launcher_platform", [{get_editor_launcher_platform()}]) @pytest.mark.parametrize("project", ["AutomatedTesting"]) class TestAutomation(EditorTestSuite): class test_single(EditorSingleTest): @@ -127,7 +133,7 @@ class TestEditorTest: from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorTestSuite @pytest.mark.SUITE_main - @pytest.mark.parametrize("launcher_platform", ['windows_editor']) + @pytest.mark.parametrize("launcher_platform", [{get_editor_launcher_platform()}]) @pytest.mark.parametrize("project", ["AutomatedTesting"]) class TestAutomation(EditorTestSuite): {module_class_code} From 6168528964329f5eef84c029dc429f97d8113292 Mon Sep 17 00:00:00 2001 From: evanchia Date: Thu, 21 Oct 2021 14:44:43 -0700 Subject: [PATCH 13/77] fixing unit tests Signed-off-by: evanchia --- Tools/LyTestTools/tests/unit/test_o3de_editor_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py b/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py index f16f7533d4..3f6c23ea3d 100644 --- a/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py +++ b/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py @@ -486,7 +486,7 @@ class TestUtils(unittest.TestCase): mock_test.__name__ = 'mock_test_name' mock_test_list = [mock_test] mock_output = 'JSON_START(' \ - '{"name": "mock_module_name", "output": "mock_std_out", "failed": "mock_fail_data"}' \ + '{"name": "mock_module_name", "output": "mock_std_out", "failed": "mock_fail_data", "success": ""}' \ ')JSON_END' mock_fail = mock.MagicMock() mock_create.return_value = mock_fail @@ -534,10 +534,10 @@ class TestUtils(unittest.TestCase): '{"name": "mock_module_name_pass", "output": "mock_std_out", "success": "mock_success_data"}' \ ')JSON_END' \ 'JSON_START(' \ - '{"name": "mock_module_name_fail", "output": "mock_std_out", "failed": "mock_fail_data"}' \ + '{"name": "mock_module_name_fail", "output": "mock_std_out", "failed": "mock_fail_data", "success": ""}' \ ')JSON_END' \ 'JSON_START(' \ - '{"name": "mock_module_name_unknown", "output": "mock_std_out", "failed": "mock_fail_data"}' \ + '{"name": "mock_module_name_unknown", "output": "mock_std_out", "failed": "mock_fail_data", "success": ""}' \ ')JSON_END' mock_editor_log = 'JSON_START(' \ '{"name": "mock_module_name_pass"}' \ From f61c37786f0733e31f722e1655cfcbb1d036b498 Mon Sep 17 00:00:00 2001 From: evanchia Date: Thu, 21 Oct 2021 16:40:48 -0700 Subject: [PATCH 14/77] fixing unit test with local time issue Signed-off-by: evanchia --- .../tests/unit/test_editor_test_utils.py | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Tools/LyTestTools/tests/unit/test_editor_test_utils.py b/Tools/LyTestTools/tests/unit/test_editor_test_utils.py index b096f6d6b0..56000364d1 100644 --- a/Tools/LyTestTools/tests/unit/test_editor_test_utils.py +++ b/Tools/LyTestTools/tests/unit/test_editor_test_utils.py @@ -78,6 +78,22 @@ class TestEditorTestUtils(unittest.TestCase): assert expected == editor_test_utils.retrieve_crash_output(0, mock_workspace, 0) + @mock.patch('os.path.getmtime', mock.MagicMock()) + @mock.patch('os.rename') + @mock.patch('time.strftime') + @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('os.path.exists') + def test_CycleCrashReport_DmpExists_NamedCorrectly(self, mock_exists, mock_retrieve_log_path, mock_strftime, + mock_rename): + mock_exists.side_effect = [False, True] + mock_retrieve_log_path.return_value = 'mock_log_path' + mock_workspace = mock.MagicMock() + mock_strftime.return_value = 'mock_strftime' + + editor_test_utils.cycle_crash_report(0, mock_workspace) + mock_rename.assert_called_once_with(os.path.join('mock_log_path', 'error.dmp'), + os.path.join('mock_log_path', 'error_mock_strftime.dmp')) + @mock.patch('os.rename') @mock.patch('os.path.getmtime') @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @@ -93,21 +109,6 @@ class TestEditorTestUtils(unittest.TestCase): mock_rename.assert_called_once_with(os.path.join('mock_log_path', 'error.log'), os.path.join('mock_log_path', 'error_1969_12_31_16_00_01.log')) - @mock.patch('os.rename') - @mock.patch('os.path.getmtime') - @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') - @mock.patch('os.path.exists') - def test_CycleCrashReport_DmpExists_NamedCorrectly(self, mock_exists, mock_retrieve_log_path, mock_getmtime, - mock_rename): - mock_exists.side_effect = [False, True] - mock_retrieve_log_path.return_value = 'mock_log_path' - mock_workspace = mock.MagicMock() - mock_getmtime.return_value = 1 - - editor_test_utils.cycle_crash_report(0, mock_workspace) - mock_rename.assert_called_once_with(os.path.join('mock_log_path', 'error.dmp'), - os.path.join('mock_log_path', 'error_1969_12_31_16_00_01.dmp')) - @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock()) def test_RetrieveEditorLogContent_CrashLogExists_ReturnsLogInfo(self, mock_retrieve_log_path): From 2fe1e513468f7c39aa79d831de93be75c9af4760 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 21 Oct 2021 18:40:31 -0700 Subject: [PATCH 15/77] generated a package for debug/profile/release monolithic-profile/release Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Registry/CMakeLists.txt | 11 +- cmake/Install.cmake | 29 ++++- cmake/Packaging.cmake | 122 ++++++++---------- cmake/Platform/Common/Install_common.cmake | 50 ++++++- cmake/Platform/Linux/Install_linux.cmake | 2 + .../Platform/Windows/Packaging_windows.cmake | 7 +- 6 files changed, 135 insertions(+), 86 deletions(-) diff --git a/Registry/CMakeLists.txt b/Registry/CMakeLists.txt index 773adac07f..df309ba657 100644 --- a/Registry/CMakeLists.txt +++ b/Registry/CMakeLists.txt @@ -12,6 +12,11 @@ endif() ly_install_directory(DIRECTORIES .) -ly_install_directory(DIRECTORIES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/Registry - DESTINATION ${runtime_output_directory} -) +foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + string(REPLACE "$" "${conf}" output ${runtime_output_directory}) + ly_install_directory(DIRECTORIES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${conf}/Registry + DESTINATION ${output} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + ) +endforeach() diff --git a/cmake/Install.cmake b/cmake/Install.cmake index 9bc908f74a..26535d89be 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -18,6 +18,7 @@ endif() # \arg:DIRECTORIES directories to install # \arg:DESTINATION (optional) destination to install the directory to (relative to CMAKE_PREFIX_PATH) # \arg:EXCLUDE_PATTERNS (optional) patterns to exclude +# \arg:COMPONENT (optional) component to use (defaults to CMAKE_INSTALL_DEFAULT_COMPONENT_NAME) # \arg:VERBATIM (optional) copies the directories as they are, this excludes the default exclude patterns # # \notes: @@ -34,7 +35,7 @@ function(ly_install_directory) endif() set(options VERBATIM) - set(oneValueArgs DESTINATION) + set(oneValueArgs DESTINATION COMPONENT) set(multiValueArgs DIRECTORIES EXCLUDE_PATTERNS) cmake_parse_arguments(ly_install_directory "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) @@ -77,11 +78,21 @@ function(ly_install_directory) list(APPEND exclude_patterns PATTERN *.egg-info EXCLUDE) endif() - install(DIRECTORY ${directory} - DESTINATION ${ly_install_directory_DESTINATION} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the deafult for the time being - ${exclude_patterns} - ) + if(ly_install_directory_COMPONENT) + install(DIRECTORY ${directory} + DESTINATION ${ly_install_directory_DESTINATION} + COMPONENT ${ly_install_directory_COMPONENT} + ${exclude_patterns} + ) + else() + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") + install(DIRECTORY ${directory} + DESTINATION ${ly_install_directory_DESTINATION} + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} + ${exclude_patterns} + ) + install(CODE "endif()") + endif() endforeach() endfunction() @@ -126,10 +137,12 @@ function(ly_install_files) set(install_type FILES) endif() + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(${install_type} ${files} DESTINATION ${ly_install_files_DESTINATION} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being ) + install(CODE "endif()") endfunction() @@ -144,9 +157,11 @@ function(ly_install_run_code CODE) return() endif() + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(CODE ${CODE} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being ) + install(CODE "endif()") endfunction() @@ -161,8 +176,10 @@ function(ly_install_run_script SCRIPT) return() endif() + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(SCRIPT ${SCRIPT} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being ) + install(CODE "endif()") endfunction() diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 25f9b87cbc..a87b0c4361 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -134,10 +134,12 @@ if(NOT EXISTS ${_cmake_package_dest}) endif() endif() +install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(FILES ${_cmake_package_dest} DESTINATION ./Tools/Redistributables/CMake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) +install(CODE "endif()") # the version string and git tags are intended to be synchronized so it should be safe to use that instead # of directly calling into git which could get messy in certain scenarios @@ -158,10 +160,12 @@ if(${CPACK_PACKAGE_VERSION} VERSION_GREATER "0.0.0.0") list(POP_FRONT _status _status_code) if (${_status_code} EQUAL 0 AND EXISTS ${_3rd_party_license_dest}) + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(FILES ${_3rd_party_license_dest} DESTINATION . COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + install(CODE "endif()") else() file(REMOVE ${_3rd_party_license_dest}) message(FATAL_ERROR "Failed to acquire the 3rd Party license manifest file at ${_3rd_party_license_url}. Error: ${_status}") @@ -204,76 +208,73 @@ endif() # IMPORTANT: required to be included AFTER setting all property overrides include(CPack REQUIRED) -function(ly_configure_cpack_component ly_configure_cpack_component_NAME) - - set(options REQUIRED DISABLED) - set(oneValueArgs DISPLAY_NAME DESCRIPTION LICENSE_NAME LICENSE_FILE DEPENDS) - set(multiValueArgs) - - cmake_parse_arguments(ly_configure_cpack_component "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - unset(component_type) - - if(ly_configure_cpack_component_DISABLED) - list(APPEND component_type DISABLED) - endif() - if(ly_configure_cpack_component_REQUIRED) - list(APPEND component_type REQUIRED) - endif() - - set(license_name ${DEFAULT_LICENSE_NAME}) - set(license_file ${DEFAULT_LICENSE_FILE}) - - if(ly_configure_cpack_component_LICENSE_NAME AND ly_configure_cpack_component_LICENSE_FILE) - set(license_name ${ly_configure_cpack_component_LICENSE_NAME}) - set(license_file ${ly_configure_cpack_component_LICENSE_FILE}) - elseif(ly_configure_cpack_component_LICENSE_NAME OR ly_configure_cpack_component_LICENSE_FILE) - message(FATAL_ERROR "Invalid argument configuration. Both LICENSE_NAME and LICENSE_FILE must be set for ly_configure_cpack_component") - endif() - - cpack_add_component( - ${ly_configure_cpack_component_NAME} ${component_type} - DISPLAY_NAME ${ly_configure_cpack_component_DISPLAY_NAME} - DESCRIPTION ${ly_configure_cpack_component_DESCRIPTION} - ) -endfunction() - # configure ALL components here -ly_configure_cpack_component( - ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} REQUIRED - DISPLAY_NAME "${PROJECT_NAME}" - DESCRIPTION "${PROJECT_NAME} Headers, scripts and common files" -) +file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" " +set(CPACK_COMPONENTS_ALL ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) +set(CPACK_COMPONENT_${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_DISPLAY_NAME \"${PROJECT_NAME}\") +set(CPACK_COMPONENT_${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_DESCRIPTION \"${PROJECT_NAME} Headers, scripts and common files\") +set(CPACK_COMPONENT_${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_REQUIRED TRUE) +set(CPACK_COMPONENT_${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_DISABLED FALSE) -file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "set(LY_CPACK_COMPONENTS_ALL ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME})\n") +include(CPackComponents.cmake) +") + +# Generate a file (CPackComponents.config) that we will include that defines the components +# for this build permutation. This way we can get components for other permutations being passed +# through LY_INSTALL_EXTERNAL_BUILD_DIRS +unset(cpack_components_contents) + +set(required "FALSE") +set(disabled "FALSE") +if(${LY_INSTALL_PERMUTATION_COMPONENT} STREQUAL DEFAULT) + set(required "TRUE") +else() + set(disabled "TRUE") +endif() +string(APPEND cpack_components_contents " +list(APPEND CPACK_COMPONENTS_ALL ${LY_INSTALL_PERMUTATION_COMPONENT}) +set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_DISPLAY_NAME \"${PROJECT_NAME} (${LY_BUILD_PERMUTATION})\") +set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_DESCRIPTION \"${PROJECT_NAME} scripts and common files for ${LY_BUILD_PERMUTATION}\") +set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_DEPENDS ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) +set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_REQUIRED ${required}) +set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_DISABLED ${disabled}) +") foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) string(TOUPPER ${conf} UCONF) - unset(flags) - if(${conf} STREQUAL profile AND ${LY_BUILD_PERMUTATION} STREQUAL Default) - set(flags REQUIRED) + set(required "FALSE") + set(disabled "FALSE") + if(${conf} STREQUAL profile AND ${LY_INSTALL_PERMUTATION_COMPONENT} STREQUAL DEFAULT) + set(required "TRUE") else() - set(flags DISABLED) + set(disabled "TRUE") endif() unset(permutation_description) - if(${LY_BUILD_PERMUTATION} STREQUAL Monolithic) - set(permutation_description " monolithic ") + if(${LY_INSTALL_PERMUTATION_COMPONENT} STREQUAL MONOLITHIC) + set(permutation_description "monolithic ") endif() # Inject a check to not declare components that have not been built. We are using AzCore since that is a # common target that will always be build, in every permutation and configuration - file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" - "if(EXISTS \"${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${conf}/${CMAKE_STATIC_LIBRARY_PREFIX}AzCore${CMAKE_STATIC_LIBRARY_SUFFIX}\")\n") - ly_configure_cpack_component( - ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} ${flags} - DISPLAY_NAME "${PROJECT_NAME} (${conf})" - DESCRIPTION "${PROJECT_NAME} Libraries and Tools in${permutation_description}${conf}" - ) - file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" -"list(APPEND LY_CPACK_COMPONENTS_ALL ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF}) -endif()\n") + string(APPEND cpack_components_contents " +if(EXISTS \"${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${conf}/${CMAKE_STATIC_LIBRARY_PREFIX}AzCore${CMAKE_STATIC_LIBRARY_SUFFIX}\") + list(APPEND CPACK_COMPONENTS_ALL ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}) + set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DISPLAY_NAME \"${PROJECT_NAME} (${permutation_description}${conf})\") + set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DESCRIPTION \"${PROJECT_NAME} Libraries and Applications in ${permutation_description}${conf}\") + set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DEPENDS ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}) + set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_REQUIRED ${required}) + set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DISABLED ${disabled}) +endif() +") +endforeach() +file(WRITE "${CMAKE_BINARY_DIR}/CPackComponents.cmake" ${cpack_components_contents}) +# Inject other build directories +foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS}) + file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" + "include(${external_dir}/CPackComponents.cmake)\n" + ) endforeach() if(LY_INSTALLER_DOWNLOAD_URL) @@ -286,12 +287,3 @@ if(LY_INSTALLER_DOWNLOAD_URL) ALL ) endif() - -# Inject other build directories -foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS}) - file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" - "include(${external_dir}/CPackConfig.cmake)\n" - ) -endforeach() - -file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "set(CPACK_COMPONENTS_ALL \${LY_CPACK_COMPONENTS_ALL})\n") diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index b1cd5095b8..71aacd5e31 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -33,14 +33,13 @@ define_property(TARGET PROPERTY LY_INSTALL_GENERATE_RUN_TARGET # CPack is able to put the two together by taking Core from one permutation and then taking # each permutation. -ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Core) +ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME CORE) if(LY_MONOLITHIC_GAME) set(LY_BUILD_PERMUTATION Monolithic) - set(LY_INSTALL_PERMUTATION_COMPONENT Monolithic) else() set(LY_BUILD_PERMUTATION Default) - set(LY_INSTALL_PERMUTATION_COMPONENT Default) endif() +string(TOUPPER ${LY_BUILD_PERMUTATION} LY_INSTALL_PERMUTATION_COMPONENT) cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory) cmake_path(RELATIVE_PATH CMAKE_LIBRARY_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE library_output_directory) @@ -84,7 +83,8 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar cmake_path(RELATIVE_PATH include_directory BASE_DIRECTORY ${LY_ROOT_FOLDER} OUTPUT_VARIABLE rel_include_dir) cmake_path(APPEND rel_include_dir "..") cmake_path(NORMAL_PATH rel_include_dir OUTPUT_VARIABLE destination_dir) - + + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(DIRECTORY ${include_directory} DESTINATION ${destination_dir} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} @@ -95,6 +95,7 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar PATTERN *.hxx PATTERN *.jinja # LyAutoGen files ) + install(CODE "endif()") endif() endforeach() endif() @@ -337,10 +338,13 @@ function(ly_setup_subdirectory absolute_target_source_dir) @cmake_copyright_comment@ include(Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) ]] @ONLY) + + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(FILES "${target_install_source_dir}/CMakeLists.txt" DESTINATION ${relative_target_source_dir} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + install(CODE "endif()") # 2. For this platform file, create a Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake file # that will include different configuration permutations (e.g. monolithic vs non-monolithic) @@ -352,10 +356,12 @@ else() include(Platform/${PAL_PLATFORM_NAME}/Default/permutation.cmake) endif() ]]) + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake" DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + install(CODE "endif()") # 3. For this configuration permutation, generate a Platform/${PAL_PLATFORM_NAME}/${permutation}/permutation.cmake # that will declare the target and configure it @@ -389,6 +395,7 @@ function(ly_setup_o3de_install) ly_setup_assets() # Misc + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(FILES ${LY_ROOT_FOLDER}/ctest_pytest.ini ${LY_ROOT_FOLDER}/LICENSE.txt @@ -396,10 +403,13 @@ function(ly_setup_o3de_install) DESTINATION . COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + install(CODE "endif()") # Inject other build directories foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS}) - install(CODE "include(${external_dir}/cmake_install.cmake)") + install(CODE "set(LY_CORE_COMPONENT_ALREADY_INCLUDED TRUE) +include(${external_dir}/cmake_install.cmake)" +ALL_COMPONENTS) endforeach() if(COMMAND ly_post_install_steps) @@ -411,6 +421,7 @@ endfunction() #! ly_setup_cmake_install: install the "cmake" folder function(ly_setup_cmake_install) + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(DIRECTORY "${LY_ROOT_FOLDER}/cmake" DESTINATION . COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} @@ -418,11 +429,16 @@ function(ly_setup_cmake_install) PATTERN "Findo3de.cmake" EXCLUDE REGEX "3rdParty/Platform\/.*\/BuiltInPackages_.*\.cmake" EXCLUDE ) + install(CODE "endif()") + # Connect configuration types + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(FILES "${LY_ROOT_FOLDER}/cmake/install/ConfigurationTypes.cmake" DESTINATION cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + install(CODE "endif()") + # generate each ConfigurationType_.cmake file and install it under that configuration foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) string(TOUPPER ${conf} UCONF) @@ -430,11 +446,13 @@ function(ly_setup_cmake_install) "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/ConfigurationTypes_${conf}.cmake" @ONLY ) + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(FILES "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/ConfigurationTypes_${conf}.cmake" DESTINATION cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} CONFIGURATIONS ${conf} ) + install(CODE "endif()") endforeach() # Transform the LY_EXTERNAL_SUBDIRS list into a json array @@ -454,12 +472,14 @@ function(ly_setup_cmake_install) configure_file(${LY_ROOT_FOLDER}/cmake/install/engine.json.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json @ONLY) + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(FILES "${LY_ROOT_FOLDER}/CMakeLists.txt" "${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json" DESTINATION . COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + install(CODE "endif()") # Collect all Find files that were added with ly_add_external_target_path unset(additional_find_files) @@ -477,6 +497,8 @@ function(ly_setup_cmake_install) list(APPEND additional_platform_files "${plat_files}") endforeach() endforeach() + + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(FILES ${additional_find_files} DESTINATION cmake/3rdParty COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} @@ -485,6 +507,7 @@ function(ly_setup_cmake_install) DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + install(CODE "endif()") # Findo3de.cmake file: we generate a different Findo3de.camke file than the one we have in cmake. This one is going to expose all # targets that are pre-built @@ -498,10 +521,12 @@ function(ly_setup_cmake_install) endforeach() configure_file(${LY_ROOT_FOLDER}/cmake/install/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake @ONLY) + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake" DESTINATION cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + install(CODE "endif()") # BuiltInPackage_.cmake: since associations could happen in any cmake file across the engine. We collect # all the associations in ly_associate_package and then generate them into BuiltInPackages_.cmake. This @@ -518,10 +543,12 @@ function(ly_setup_cmake_install) file(GENERATE OUTPUT ${pal_builtin_file} CONTENT ${builtinpackages} ) + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(FILES "${pal_builtin_file}" DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + install(CODE "endif()") endfunction() @@ -536,9 +563,12 @@ function(ly_setup_runtime_dependencies) string(TOUPPER ${conf} UCONF) install(CODE "function(ly_copy source_file target_directory) - file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) + cmake_path(GET source_file FILENAME file_name) + if(NOT EXISTS ${target_directory}/${file_name}) + file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) + endif() endfunction()" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} ) endforeach() endif() @@ -672,17 +702,23 @@ function(ly_setup_assets) if (NOT gem_install_dest_dir) cmake_path(SET gem_install_dest_dir .) endif() + if(IS_DIRECTORY ${gem_absolute_path}) + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(DIRECTORY "${gem_absolute_path}" DESTINATION ${gem_install_dest_dir} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + install(CODE "endif()") elseif (EXISTS ${gem_absolute_path}) + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(FILES ${gem_absolute_path} DESTINATION ${gem_install_dest_dir} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + install(CODE "endif()") endif() + endforeach() endforeach() diff --git a/cmake/Platform/Linux/Install_linux.cmake b/cmake/Platform/Linux/Install_linux.cmake index dea26e5872..68016872aa 100644 --- a/cmake/Platform/Linux/Install_linux.cmake +++ b/cmake/Platform/Linux/Install_linux.cmake @@ -22,9 +22,11 @@ endfunction()]]) function(ly_install_code_function_override) string(CONFIGURE "${ly_copy_template}" ly_copy_function_linux @ONLY) + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") install(CODE "${ly_copy_function_linux}" COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + install(CODE "endif()") endfunction() include(cmake/Platform/Common/Install_common.cmake) diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index 65b5751ebe..5981372ed2 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -28,11 +28,8 @@ set(_cmake_package_name "cmake-${CPACK_DESIRED_CMAKE_VERSION}-windows-x86_64") set(CPACK_CMAKE_PACKAGE_FILE "${_cmake_package_name}.zip") set(CPACK_CMAKE_PACKAGE_HASH "15a49e2ab81c1822d75b1b1a92f7863f58e31f6d6aac1c4103eef2b071be3112") -# workaround for shortening the path cpack installs to by stripping the platform directory and forcing monolithic -# mode to strip out component folders. this unfortunately is the closest we can get to changing the install location -# as CPACK_PACKAGING_INSTALL_PREFIX/CPACK_SET_DESTDIR isn't supported for the WiX generator -#set(CPACK_TOPLEVEL_TAG "") -#set(CPACK_MONOLITHIC_INSTALL ON) +# workaround for shortening the path cpack installs to by stripping the platform directory +set(CPACK_TOPLEVEL_TAG "") # CPack will generate the WiX product/upgrade GUIDs further down the chain if they weren't supplied # however, they are unique for each run. instead, let's do the auto generation here and add it to From 29ecb0a246217455fdfd8ad7a0e2c2f9e6ec3803 Mon Sep 17 00:00:00 2001 From: evanchia Date: Thu, 21 Oct 2021 19:49:42 -0700 Subject: [PATCH 16/77] fixing more AR only unit test failures Signed-off-by: evanchia --- Tools/LyTestTools/tests/unit/test_editor_test_utils.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Tools/LyTestTools/tests/unit/test_editor_test_utils.py b/Tools/LyTestTools/tests/unit/test_editor_test_utils.py index 56000364d1..bf7fae7189 100644 --- a/Tools/LyTestTools/tests/unit/test_editor_test_utils.py +++ b/Tools/LyTestTools/tests/unit/test_editor_test_utils.py @@ -94,20 +94,21 @@ class TestEditorTestUtils(unittest.TestCase): mock_rename.assert_called_once_with(os.path.join('mock_log_path', 'error.dmp'), os.path.join('mock_log_path', 'error_mock_strftime.dmp')) + @mock.patch('os.path.getmtime', mock.MagicMock()) @mock.patch('os.rename') - @mock.patch('os.path.getmtime') + @mock.patch('time.strftime') @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @mock.patch('os.path.exists') - def test_CycleCrashReport_LogExists_NamedCorrectly(self, mock_exists, mock_retrieve_log_path, mock_getmtime, + def test_CycleCrashReport_LogExists_NamedCorrectly(self, mock_exists, mock_retrieve_log_path, mock_strftime, mock_rename): mock_exists.side_effect = [True, False] mock_retrieve_log_path.return_value = 'mock_log_path' mock_workspace = mock.MagicMock() - mock_getmtime.return_value = 1 + mock_strftime.return_value = 'mock_strftime' editor_test_utils.cycle_crash_report(0, mock_workspace) mock_rename.assert_called_once_with(os.path.join('mock_log_path', 'error.log'), - os.path.join('mock_log_path', 'error_1969_12_31_16_00_01.log')) + os.path.join('mock_log_path', 'error_mock_strftime.log')) @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock()) From c345733057bef4fe513c2c22af7dc6f37157d698 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 22 Oct 2021 15:30:32 -0700 Subject: [PATCH 17/77] improving some text messages Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Packaging.cmake | 13 ++++--------- cmake/Platform/Windows/Packaging_windows.cmake | 3 +++ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index a87b0c4361..a810bf8b56 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -211,7 +211,7 @@ include(CPack REQUIRED) # configure ALL components here file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" " set(CPACK_COMPONENTS_ALL ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) -set(CPACK_COMPONENT_${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_DISPLAY_NAME \"${PROJECT_NAME}\") +set(CPACK_COMPONENT_${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_DISPLAY_NAME \"Common files\") set(CPACK_COMPONENT_${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_DESCRIPTION \"${PROJECT_NAME} Headers, scripts and common files\") set(CPACK_COMPONENT_${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_REQUIRED TRUE) set(CPACK_COMPONENT_${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_DISABLED FALSE) @@ -233,7 +233,7 @@ else() endif() string(APPEND cpack_components_contents " list(APPEND CPACK_COMPONENTS_ALL ${LY_INSTALL_PERMUTATION_COMPONENT}) -set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_DISPLAY_NAME \"${PROJECT_NAME} (${LY_BUILD_PERMUTATION})\") +set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_DISPLAY_NAME \"${LY_BUILD_PERMUTATION} common files\") set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_DESCRIPTION \"${PROJECT_NAME} scripts and common files for ${LY_BUILD_PERMUTATION}\") set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_DEPENDS ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_REQUIRED ${required}) @@ -250,18 +250,13 @@ foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) set(disabled "TRUE") endif() - unset(permutation_description) - if(${LY_INSTALL_PERMUTATION_COMPONENT} STREQUAL MONOLITHIC) - set(permutation_description "monolithic ") - endif() - # Inject a check to not declare components that have not been built. We are using AzCore since that is a # common target that will always be build, in every permutation and configuration string(APPEND cpack_components_contents " if(EXISTS \"${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${conf}/${CMAKE_STATIC_LIBRARY_PREFIX}AzCore${CMAKE_STATIC_LIBRARY_SUFFIX}\") list(APPEND CPACK_COMPONENTS_ALL ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}) - set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DISPLAY_NAME \"${PROJECT_NAME} (${permutation_description}${conf})\") - set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DESCRIPTION \"${PROJECT_NAME} Libraries and Applications in ${permutation_description}${conf}\") + set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DISPLAY_NAME \"Binaries for ${LY_BUILD_PERMUTATION} ${conf}\") + set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DESCRIPTION \"${PROJECT_NAME} libraries and applications for ${LY_BUILD_PERMUTATION} ${conf}\") set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DEPENDS ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}) set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_REQUIRED ${required}) set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DISABLED ${disabled}) diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index 5981372ed2..630817370f 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -105,6 +105,9 @@ set(_raw_text_license [[ #(loc.InstallEulaAcceptance) ]]) +# if we are doing an offline installer, there is a limit in size the wix tooling can handle and produces +# issues for our current sizes. If the installer is offline, disable the curstom wix generator generating +# a msi instead. if(LY_INSTALLER_DOWNLOAD_URL) set(WIX_THEME_WARNING_IMAGE ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/warning.png) From ec78c1c00313f7f3f81658c4ea746c2939cab991 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 22 Oct 2021 15:31:46 -0700 Subject: [PATCH 18/77] Removes unity=true since its the default Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Windows/ProjectBuilderWorker_windows.cpp | 3 +- .../build/Platform/Android/build_config.json | 10 +++--- .../build/Platform/Linux/build_config.json | 18 +++++------ scripts/build/Platform/Mac/build_config.json | 14 ++++---- .../build/Platform/Windows/build_config.json | 32 +++++++++---------- .../Platform/Windows/installer_windows.cmd | 4 +-- .../Windows/package_build_config.json | 2 +- scripts/build/Platform/iOS/build_config.json | 10 +++--- 8 files changed, 46 insertions(+), 47 deletions(-) diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectBuilderWorker_windows.cpp b/Code/Tools/ProjectManager/Platform/Windows/ProjectBuilderWorker_windows.cpp index 075c6de774..b6b37b222d 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectBuilderWorker_windows.cpp +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectBuilderWorker_windows.cpp @@ -21,8 +21,7 @@ namespace O3DE::ProjectManager return AZ::Success(QStringList{ ProjectCMakeCommand, "-B", targetBuildPath, "-S", m_projectInfo.m_path, - QString("-DLY_3RDPARTY_PATH=").append(thirdPartyPath), - "-DLY_UNITY_BUILD=ON" } ); + QString("-DLY_3RDPARTY_PATH=").append(thirdPartyPath) } ); } AZ::Outcome ProjectBuilderWorker::ConstructCmakeBuildCommandArguments() const diff --git a/scripts/build/Platform/Android/build_config.json b/scripts/build/Platform/Android/build_config.json index c1fbb1dd87..5e2da44a3c 100644 --- a/scripts/build/Platform/Android/build_config.json +++ b/scripts/build/Platform/Android/build_config.json @@ -35,7 +35,7 @@ "PARAMETERS": { "CONFIGURATION":"debug", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\"", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -60,7 +60,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\"", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -93,7 +93,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"build\\windows_vs2019", - "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"AssetProcessorBatch", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -112,7 +112,7 @@ "PARAMETERS": { "CONFIGURATION":"release", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\"", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -128,7 +128,7 @@ "PARAMETERS": { "CONFIGURATION":"release", "OUTPUT_DIRECTORY":"build\\mono_android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_MONOLITHIC_GAME=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" diff --git a/scripts/build/Platform/Linux/build_config.json b/scripts/build/Platform/Linux/build_config.json index ee4c27b0a9..c99d0d128d 100644 --- a/scripts/build/Platform/Linux/build_config.json +++ b/scripts/build/Platform/Linux/build_config.json @@ -37,7 +37,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -53,7 +53,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -80,7 +80,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all", "CTEST_OPTIONS": "-E Gem::EMotionFX.Editor.Tests -LE (SUITE_sandbox|SUITE_awsi) -L FRAMEWORK_googletest", @@ -110,7 +110,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", @@ -142,7 +142,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_periodic", "CTEST_OPTIONS": "-L (SUITE_periodic)", @@ -162,7 +162,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all", "CTEST_OPTIONS": "-L (SUITE_sandbox)" @@ -178,7 +178,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_benchmark", "CTEST_OPTIONS": "-L (SUITE_benchmark)", @@ -195,7 +195,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -210,7 +210,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/mono_linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_MONOLITHIC_GAME=TRUE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } diff --git a/scripts/build/Platform/Mac/build_config.json b/scripts/build/Platform/Mac/build_config.json index 7eb3cb5699..b57cc522bc 100644 --- a/scripts/build/Platform/Mac/build_config.json +++ b/scripts/build/Platform/Mac/build_config.json @@ -37,7 +37,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -51,7 +51,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -81,7 +81,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", @@ -99,7 +99,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_periodic", "CTEST_OPTIONS": "-L \"(SUITE_periodic)\"", @@ -116,7 +116,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_benchmark", "CTEST_OPTIONS": "-L \"(SUITE_benchmark)\"", @@ -133,7 +133,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -148,7 +148,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/mono_mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_MONOLITHIC_GAME=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index ce1d55f877..9f779705a2 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -99,7 +99,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -113,7 +113,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -131,7 +131,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_TEST_IMPACT_INSTRUMENTATION_BIN=!TEST_IMPACT_WIN_BINARY!", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_TEST_IMPACT_INSTRUMENTATION_BIN=!TEST_IMPACT_WIN_BINARY!", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -162,7 +162,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -183,7 +183,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -203,7 +203,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -234,7 +234,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_awsi", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -253,7 +253,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_periodic", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -275,7 +275,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_sandbox", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -294,7 +294,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_benchmark", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -314,7 +314,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -330,7 +330,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build\\mono_windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_MONOLITHIC_GAME=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -345,7 +345,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_DISABLE_TEST_MODULES=TRUE", "CMAKE_LY_PROJECTS": "", "CMAKE_TARGET": "INSTALL", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -363,7 +363,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_INSTALLER_WIX_ROOT=\"!WIX!\"", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_INSTALLER_WIX_ROOT=\"!WIX!\"", "EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=ON -DLY_INSTALLER_DOWNLOAD_URL=!INSTALLER_DOWNLOAD_URL! -DLY_INSTALLER_LICENSE_URL=!INSTALLER_DOWNLOAD_URL!/license", "CPACK_BUCKET": "!INSTALLER_BUCKET!", "CMAKE_LY_PROJECTS": "", @@ -382,7 +382,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DCMAKE_MODULE_PATH=!WORKSPACE!/o3de/cmake", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_MODULE_PATH=!WORKSPACE!/o3de/cmake", "CMAKE_LY_PROJECTS": "", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -397,7 +397,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DCMAKE_MODULE_PATH=!WORKSPACE!/o3de/install/cmake", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_MODULE_PATH=!WORKSPACE!/o3de/install/cmake", "CMAKE_LY_PROJECTS": "", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index 94fb8c4f42..6f793cab64 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -48,11 +48,11 @@ IF ERRORLEVEL 1 ( ) IF NOT "%CPACK_BUCKET%"=="" ( - SET "CPACK_OPTIONS=-D CPACK_UPLOAD_URL=s3://%CPACK_BUCKET% %CPACK_OPTIONS%" + SET "CPACK_OPTIONS=-DCPACK_UPLOAD_URL=s3://%CPACK_BUCKET% %CPACK_OPTIONS%" ) ECHO [ci_build] "!CPACK_PATH!" -C %CONFIGURATION% %CPACK_OPTIONS% -REM "!CPACK_PATH!" -C %CONFIGURATION% %CPACK_OPTIONS% +"!CPACK_PATH!" -C %CONFIGURATION% %CPACK_OPTIONS% IF NOT %ERRORLEVEL%==0 ( REM dump the log file generated by cpack specifically for WIX ECHO **************************************************************** diff --git a/scripts/build/Platform/Windows/package_build_config.json b/scripts/build/Platform/Windows/package_build_config.json index 89431ad96e..5eb96f1e38 100644 --- a/scripts/build/Platform/Windows/package_build_config.json +++ b/scripts/build/Platform/Windows/package_build_config.json @@ -4,7 +4,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"windows_vs2019", - "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS":"AtomTest;AtomSampleViewer", "CMAKE_TARGET":"ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" diff --git a/scripts/build/Platform/iOS/build_config.json b/scripts/build/Platform/iOS/build_config.json index 01f545ffb6..895f74daae 100644 --- a/scripts/build/Platform/iOS/build_config.json +++ b/scripts/build/Platform/iOS/build_config.json @@ -27,7 +27,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" @@ -44,7 +44,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" @@ -76,7 +76,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", @@ -94,7 +94,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" @@ -112,7 +112,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/ios_test", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=FALSE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=TRUE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=TRUE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=FALSE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=TRUE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "", "TARGET_DEVICE_NAME": "Lumberyard", From 595e0e1a833e6aa3bdd7b875541fa3ad2eea1f88 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 22 Oct 2021 20:38:52 -0700 Subject: [PATCH 19/77] better wrapping for install in core components Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Install.cmake | 59 +++++---- cmake/Packaging.cmake | 10 +- cmake/Platform/Common/Install_common.cmake | 143 +++++++++------------ cmake/Platform/Linux/Install_linux.cmake | 8 +- cmake/Platform/Mac/Install_mac.cmake | 8 +- 5 files changed, 107 insertions(+), 121 deletions(-) diff --git a/cmake/Install.cmake b/cmake/Install.cmake index 26535d89be..a7340c29f3 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -13,6 +13,28 @@ if(LY_INSTALL_ENABLED) include(${pal_dir}/Install_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) endif() +#! ly_install: wrapper to install that handles common functionality +# +# \notes: +# - this wrapper handles the case where common installs are called multiple times from different +# build folders (when using LY_INSTALL_EXTERNAL_BUILD_DIRS) to generate install layouts that +# have multiple build permutations +# +function(ly_install) + + cmake_parse_arguments(ly_install "" "COMPONENT" "" ${ARGN}) + if (NOT ly_install_COMPONENT OR "${ly_install_COMPONENT}" STREQUAL "${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}") + # if it is installing under the default component, we need to de-duplicate since we can have + # cases coming from different build directories (when using LY_INSTALL_EXTERNAL_BUILD_DIRS) + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)" ALL_COMPONENTS) + install(${ARGN}) + install(CODE "endif()\n" ALL_COMPONENTS) + else() + install(${ARGN}) + endif() + +endfunction() + #! ly_install_directory: specifies a directory to be copied to the install layout at install time # # \arg:DIRECTORIES directories to install @@ -43,6 +65,10 @@ function(ly_install_directory) if(NOT ly_install_directory_DIRECTORIES) message(FATAL_ERROR "You must provide at least a directory to install") endif() + + if(NOT ly_install_directory_COMPONENT) + set(ly_install_directory_COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) + endif() foreach(directory ${ly_install_directory_DIRECTORIES}) @@ -78,21 +104,12 @@ function(ly_install_directory) list(APPEND exclude_patterns PATTERN *.egg-info EXCLUDE) endif() - if(ly_install_directory_COMPONENT) - install(DIRECTORY ${directory} - DESTINATION ${ly_install_directory_DESTINATION} - COMPONENT ${ly_install_directory_COMPONENT} - ${exclude_patterns} - ) - else() - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(DIRECTORY ${directory} - DESTINATION ${ly_install_directory_DESTINATION} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ${exclude_patterns} - ) - install(CODE "endif()") - endif() + ly_install(DIRECTORY ${directory} + DESTINATION ${ly_install_directory_DESTINATION} + COMPONENT ${ly_install_directory_COMPONENT} + ${exclude_patterns} + ) + endforeach() endfunction() @@ -137,12 +154,10 @@ function(ly_install_files) set(install_type FILES) endif() - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(${install_type} ${files} + ly_install(${install_type} ${files} DESTINATION ${ly_install_files_DESTINATION} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being ) - install(CODE "endif()") endfunction() @@ -157,11 +172,9 @@ function(ly_install_run_code CODE) return() endif() - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(CODE ${CODE} + ly_install(CODE ${CODE} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being ) - install(CODE "endif()") endfunction() @@ -176,10 +189,8 @@ function(ly_install_run_script SCRIPT) return() endif() - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(SCRIPT ${SCRIPT} + ly_install(SCRIPT ${SCRIPT} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being ) - install(CODE "endif()") endfunction() diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index a810bf8b56..6a1e2d8cef 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -134,12 +134,10 @@ if(NOT EXISTS ${_cmake_package_dest}) endif() endif() -install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") -install(FILES ${_cmake_package_dest} +ly_install(FILES ${_cmake_package_dest} DESTINATION ./Tools/Redistributables/CMake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) -install(CODE "endif()") # the version string and git tags are intended to be synchronized so it should be safe to use that instead # of directly calling into git which could get messy in certain scenarios @@ -160,12 +158,10 @@ if(${CPACK_PACKAGE_VERSION} VERSION_GREATER "0.0.0.0") list(POP_FRONT _status _status_code) if (${_status_code} EQUAL 0 AND EXISTS ${_3rd_party_license_dest}) - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(FILES ${_3rd_party_license_dest} + ly_install(FILES ${_3rd_party_license_dest} DESTINATION . COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - install(CODE "endif()") else() file(REMOVE ${_3rd_party_license_dest}) message(FATAL_ERROR "Failed to acquire the 3rd Party license manifest file at ${_3rd_party_license_url}. Error: ${_status}") @@ -257,7 +253,7 @@ if(EXISTS \"${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${conf}/${CMAKE_STATIC_LIBRARY_PRE list(APPEND CPACK_COMPONENTS_ALL ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}) set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DISPLAY_NAME \"Binaries for ${LY_BUILD_PERMUTATION} ${conf}\") set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DESCRIPTION \"${PROJECT_NAME} libraries and applications for ${LY_BUILD_PERMUTATION} ${conf}\") - set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DEPENDS ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}) + set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DEPENDS ${LY_INSTALL_PERMUTATION_COMPONENT}) set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_REQUIRED ${required}) set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DISABLED ${disabled}) endif() diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 71aacd5e31..622100b4d8 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -9,6 +9,12 @@ include(cmake/FileUtil.cmake) set(LY_INSTALL_EXTERNAL_BUILD_DIRS "" CACHE PATH "External build directories to be included in the install process. This allows to package non-monolithic and monolithic.") +unset(normalized_external_build_dirs) +foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS}) + cmake_path(ABSOLUTE_PATH external_dir BASE_DIRECTORY ${LY_ROOT_FOLDER} NORMALIZE) + list(APPEND normalized_external_build_dirs ${external_dir}) +endforeach() +set(LY_INSTALL_EXTERNAL_BUILD_DIRS ${normalized_external_build_dirs}) set(CMAKE_INSTALL_MESSAGE NEVER) # Simplify messages to reduce output noise @@ -84,8 +90,7 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar cmake_path(APPEND rel_include_dir "..") cmake_path(NORMAL_PATH rel_include_dir OUTPUT_VARIABLE destination_dir) - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(DIRECTORY ${include_directory} + ly_install(DIRECTORY ${include_directory} DESTINATION ${destination_dir} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} FILES_MATCHING @@ -95,7 +100,6 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar PATTERN *.hxx PATTERN *.jinja # LyAutoGen files ) - install(CODE "endif()") endif() endforeach() endif() @@ -122,7 +126,7 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar else() foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) string(TOUPPER ${conf} UCONF) - install(TARGETS ${TARGET_NAME} + ly_install(TARGETS ${TARGET_NAME} ARCHIVE DESTINATION ${archive_output_directory} COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} @@ -293,7 +297,7 @@ set_property(TARGET ${NAME_PLACEHOLDER} foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) string(TOUPPER ${conf} UCONF) - install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/${NAME_PLACEHOLDER}_${conf}.cmake" + ly_install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/${NAME_PLACEHOLDER}_${conf}.cmake" DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} CONFIGURATIONS ${conf} @@ -339,12 +343,10 @@ function(ly_setup_subdirectory absolute_target_source_dir) include(Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) ]] @ONLY) - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(FILES "${target_install_source_dir}/CMakeLists.txt" + ly_install(FILES "${target_install_source_dir}/CMakeLists.txt" DESTINATION ${relative_target_source_dir} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - install(CODE "endif()") # 2. For this platform file, create a Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake file # that will include different configuration permutations (e.g. monolithic vs non-monolithic) @@ -356,12 +358,10 @@ else() include(Platform/${PAL_PLATFORM_NAME}/Default/permutation.cmake) endif() ]]) - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake" + ly_install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake" DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - install(CODE "endif()") # 3. For this configuration permutation, generate a Platform/${PAL_PLATFORM_NAME}/${permutation}/permutation.cmake # that will declare the target and configure it @@ -379,65 +379,29 @@ endif() "${ENABLE_GEMS_PLACEHOLDER}" ) - install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/permutation.cmake" + ly_install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/permutation.cmake" DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT} ) endfunction() -#! ly_setup_o3de_install: orchestrates the installation of the different parts. This is the entry point from the root CMakeLists.txt -function(ly_setup_o3de_install) - - ly_setup_subdirectories() - ly_setup_cmake_install() - ly_setup_runtime_dependencies() - ly_setup_assets() - - # Misc - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(FILES - ${LY_ROOT_FOLDER}/ctest_pytest.ini - ${LY_ROOT_FOLDER}/LICENSE.txt - ${LY_ROOT_FOLDER}/README.md - DESTINATION . - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) - install(CODE "endif()") - - # Inject other build directories - foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS}) - install(CODE "set(LY_CORE_COMPONENT_ALREADY_INCLUDED TRUE) -include(${external_dir}/cmake_install.cmake)" -ALL_COMPONENTS) - endforeach() - - if(COMMAND ly_post_install_steps) - ly_post_install_steps() - endif() - -endfunction() - #! ly_setup_cmake_install: install the "cmake" folder function(ly_setup_cmake_install) - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(DIRECTORY "${LY_ROOT_FOLDER}/cmake" + ly_install(DIRECTORY "${LY_ROOT_FOLDER}/cmake" DESTINATION . COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} PATTERN "__pycache__" EXCLUDE PATTERN "Findo3de.cmake" EXCLUDE REGEX "3rdParty/Platform\/.*\/BuiltInPackages_.*\.cmake" EXCLUDE ) - install(CODE "endif()") # Connect configuration types - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(FILES "${LY_ROOT_FOLDER}/cmake/install/ConfigurationTypes.cmake" + ly_install(FILES "${LY_ROOT_FOLDER}/cmake/install/ConfigurationTypes.cmake" DESTINATION cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - install(CODE "endif()") # generate each ConfigurationType_.cmake file and install it under that configuration foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) @@ -446,13 +410,11 @@ function(ly_setup_cmake_install) "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/ConfigurationTypes_${conf}.cmake" @ONLY ) - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(FILES "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/ConfigurationTypes_${conf}.cmake" + ly_install(FILES "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/ConfigurationTypes_${conf}.cmake" DESTINATION cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} CONFIGURATIONS ${conf} ) - install(CODE "endif()") endforeach() # Transform the LY_EXTERNAL_SUBDIRS list into a json array @@ -472,14 +434,12 @@ function(ly_setup_cmake_install) configure_file(${LY_ROOT_FOLDER}/cmake/install/engine.json.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json @ONLY) - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(FILES + ly_install(FILES "${LY_ROOT_FOLDER}/CMakeLists.txt" "${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json" DESTINATION . COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - install(CODE "endif()") # Collect all Find files that were added with ly_add_external_target_path unset(additional_find_files) @@ -498,16 +458,14 @@ function(ly_setup_cmake_install) endforeach() endforeach() - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(FILES ${additional_find_files} + ly_install(FILES ${additional_find_files} DESTINATION cmake/3rdParty COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - install(FILES ${additional_platform_files} + ly_install(FILES ${additional_platform_files} DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - install(CODE "endif()") # Findo3de.cmake file: we generate a different Findo3de.camke file than the one we have in cmake. This one is going to expose all # targets that are pre-built @@ -521,21 +479,21 @@ function(ly_setup_cmake_install) endforeach() configure_file(${LY_ROOT_FOLDER}/cmake/install/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake @ONLY) - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake" + ly_install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake" DESTINATION cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - install(CODE "endif()") # BuiltInPackage_.cmake: since associations could happen in any cmake file across the engine. We collect # all the associations in ly_associate_package and then generate them into BuiltInPackages_.cmake. This # will consolidate all associations in one file get_property(all_package_names GLOBAL PROPERTY LY_PACKAGE_NAMES) + list(REMOVE_DUPLICATES all_package_names) set(builtinpackages "# Generated by O3DE install\n\n") foreach(package_name IN LISTS all_package_names) get_property(package_hash GLOBAL PROPERTY LY_PACKAGE_HASH_${package_name}) get_property(targets GLOBAL PROPERTY LY_PACKAGE_TARGETS_${package_name}) + list(REMOVE_DUPLICATES targets) string(APPEND builtinpackages "ly_associate_package(PACKAGE_NAME ${package_name} TARGETS ${targets} PACKAGE_HASH ${package_hash})\n") endforeach() @@ -543,12 +501,10 @@ function(ly_setup_cmake_install) file(GENERATE OUTPUT ${pal_builtin_file} CONTENT ${builtinpackages} ) - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(FILES "${pal_builtin_file}" + ly_install(FILES "${pal_builtin_file}" DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - install(CODE "endif()") endfunction() @@ -556,21 +512,18 @@ endfunction() function(ly_setup_runtime_dependencies) # Common functions used by the bellow code - if(COMMAND ly_install_code_function_override) - ly_install_code_function_override() + if(COMMAND ly_setup_runtime_dependencies_copy_function_override) + ly_setup_runtime_dependencies_copy_function_override() else() - foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) - string(TOUPPER ${conf} UCONF) - install(CODE + ly_install(CODE "function(ly_copy source_file target_directory) cmake_path(GET source_file FILENAME file_name) if(NOT EXISTS ${target_directory}/${file_name}) file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) endif() endfunction()" - COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} - ) - endforeach() + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} + ) endif() unset(runtime_commands) @@ -611,7 +564,7 @@ endfunction()" list(JOIN runtime_commands " " runtime_commands_str) # the spaces are just to see the right identation in the cmake_install.cmake file foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) string(TOUPPER ${conf} UCONF) - install(CODE + ly_install(CODE "if(\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^(${conf})\$\") ${runtime_commands_str} endif()" @@ -704,19 +657,15 @@ function(ly_setup_assets) endif() if(IS_DIRECTORY ${gem_absolute_path}) - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(DIRECTORY "${gem_absolute_path}" + ly_install(DIRECTORY "${gem_absolute_path}" DESTINATION ${gem_install_dest_dir} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - install(CODE "endif()") elseif (EXISTS ${gem_absolute_path}) - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(FILES ${gem_absolute_path} + ly_install(FILES ${gem_absolute_path} DESTINATION ${gem_install_dest_dir} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - install(CODE "endif()") endif() endforeach() @@ -778,4 +727,36 @@ function(ly_setup_subdirectory_enable_gems absolute_target_source_dir output_scr string(APPEND enable_gems_calls ${enable_gems_command}) endforeach() set(${output_script} ${enable_gems_calls} PARENT_SCOPE) +endfunction() + +#! ly_setup_o3de_install: orchestrates the installation of the different parts. This is the entry point from the root CMakeLists.txt +function(ly_setup_o3de_install) + + ly_setup_subdirectories() + ly_setup_cmake_install() + ly_setup_runtime_dependencies() + ly_setup_assets() + + # Misc + ly_install(FILES + ${LY_ROOT_FOLDER}/ctest_pytest.ini + ${LY_ROOT_FOLDER}/LICENSE.txt + ${LY_ROOT_FOLDER}/README.md + DESTINATION . + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} + ) + + # Inject other build directories + foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS}) + ly_install(CODE +"set(LY_CORE_COMPONENT_ALREADY_INCLUDED TRUE) +include(${external_dir}/cmake_install.cmake)" + ALL_COMPONENTS + ) + endforeach() + + if(COMMAND ly_post_install_steps) + ly_post_install_steps() + endif() + endfunction() \ No newline at end of file diff --git a/cmake/Platform/Linux/Install_linux.cmake b/cmake/Platform/Linux/Install_linux.cmake index 68016872aa..54d1e18837 100644 --- a/cmake/Platform/Linux/Install_linux.cmake +++ b/cmake/Platform/Linux/Install_linux.cmake @@ -6,7 +6,7 @@ # # -#! ly_install_code_function_override: Linux-specific copy function to handle RPATH fixes +#! ly_setup_runtime_dependencies_copy_function_override: Linux-specific copy function to handle RPATH fixes set(ly_copy_template [[ function(ly_copy source_file target_directory) file(COPY "${source_file}" DESTINATION "${target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN) @@ -20,13 +20,11 @@ function(ly_copy source_file target_directory) endif() endfunction()]]) -function(ly_install_code_function_override) +function(ly_setup_runtime_dependencies_copy_function_override) string(CONFIGURE "${ly_copy_template}" ly_copy_function_linux @ONLY) - install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)") - install(CODE "${ly_copy_function_linux}" + ly_install(CODE "${ly_copy_function_linux}" COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - install(CODE "endif()") endfunction() include(cmake/Platform/Common/Install_common.cmake) diff --git a/cmake/Platform/Mac/Install_mac.cmake b/cmake/Platform/Mac/Install_mac.cmake index 472831425b..fe0424f86e 100644 --- a/cmake/Platform/Mac/Install_mac.cmake +++ b/cmake/Platform/Mac/Install_mac.cmake @@ -39,10 +39,10 @@ file(GENERATE # This needs to be done here because it needs to update the install prefix # before cmake does anything else in the install process. configure_file(${LY_ROOT_FOLDER}/cmake/Platform/Mac/PreInstallSteps_mac.cmake.in ${CMAKE_BINARY_DIR}/runtime_install/PreInstallSteps_mac.cmake @ONLY) -install(SCRIPT ${CMAKE_BINARY_DIR}/runtime_install/PreInstallSteps_mac.cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) +ly_install(SCRIPT ${CMAKE_BINARY_DIR}/runtime_install/PreInstallSteps_mac.cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) -#! ly_install_target_override: Mac specific target installation -function(ly_install_target_override) +#! ly_setup_runtime_dependencies_copy_function_override: Mac specific target installation +function(ly_setup_runtime_dependencies_copy_function_override) set(options) set(oneValueArgs TARGET ARCHIVE_DIR LIBRARY_DIR RUNTIME_DIR LIBRARY_SUBDIR RUNTIME_SUBDIR) @@ -60,7 +60,7 @@ function(ly_install_target_override) foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) string(TOUPPER ${conf} UCONF) - install(TARGETS ${TARGET_NAME} + ly_install(TARGETS ${TARGET_NAME} ARCHIVE DESTINATION ${ly_platform_install_target_ARCHIVE_DIR} COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} From 7c25cb6d5a0642b348c92c089dae0bb763b251e8 Mon Sep 17 00:00:00 2001 From: evanchia Date: Tue, 26 Oct 2021 10:37:39 -0700 Subject: [PATCH 20/77] addressing minor details in feedback Signed-off-by: evanchia --- .../editor_test_testing/TestSuite_Main.py | 9 ++-- .../ly_test_tools/o3de/editor_test.py | 46 +++++++++---------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py index 8832a16d99..50b89ab138 100644 --- a/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py @@ -26,16 +26,13 @@ import ly_test_tools.environment.process_utils as process_utils import argparse, sys -if ly_test_tools.WINDOWS: - pytestmark = pytest.mark.SUITE_main -else: - pytestmark = pytest.mark.skipif(not ly_test_tools.WINDOWS, reason="Only runs on Windows") - def get_editor_launcher_platform(): if ly_test_tools.WINDOWS: return "windows_editor" - else: + elif ly_test_tools.LINUX: return "linux_editor" + else: + return None @pytest.mark.parametrize("launcher_platform", [get_editor_launcher_platform()]) @pytest.mark.parametrize("project", ["AutomatedTesting"]) diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py index 0bc341012c..cf3682e080 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py @@ -3,6 +3,27 @@ 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 + +This file provides editor testing functionality to easily write automated editor tests for O3DE. +For using these utilities, you can subclass your test suite from EditorTestSuite, this allows an easy way of +specifying python test scripts that the editor will run without needing to write any boilerplace code. +It supports out of the box parallelization(running multiple editor instances at once), batching(running multiple tests +in the same editor instance) and crash detection. +Usage example: + class MyTestSuite(EditorTestSuite): + + class MyFirstTest(EditorSingleTest): + from . import script_to_be_run_by_editor as test_module + + class MyTestInParallel_1(EditorParallelTest): + from . import another_script_to_be_run_by_editor as test_module + + class MyTestInParallel_2(EditorParallelTest): + from . import yet_another_script_to_be_run_by_editor as test_module + + +EditorTestSuite does introspection of the defined classes inside of it and automatically prepares the tests, +parallelizing/batching as required """ import pytest @@ -30,27 +51,6 @@ import ly_test_tools.o3de.editor_test_utils as editor_utils from ly_test_tools.o3de.asset_processor import AssetProcessor from ly_test_tools.launchers.exceptions import WaitTimeoutError -# This file provides editor testing functionality to easily write automated editor tests for O3DE. -# For using these utilities, you can subclass your test suite from EditorTestSuite, this allows an easy way of -# specifying python test scripts that the editor will run without needing to write any boilerplace code. -# It supports out of the box parallelization(running multiple editor instances at once), batching(running multiple tests -# in the same editor instance) and crash detection. -# Usage example: -# class MyTestSuite(EditorTestSuite): -# -# class MyFirstTest(EditorSingleTest): -# from . import script_to_be_run_by_editor as test_module -# -# class MyTestInParallel_1(EditorParallelTest): -# from . import another_script_to_be_run_by_editor as test_module -# -# class MyTestInParallel_2(EditorParallelTest): -# from . import yet_another_script_to_be_run_by_editor as test_module -# -# -# EditorTestSuite does introspection of the defined classes inside of it and automatically prepares the tests, -# parallelizing/batching as required - # This file contains no tests, but with this we make sure it won't be picked up by the runner since the file ends with _test __test__ = False @@ -212,7 +212,7 @@ class Result: return r def __str__(self): - stacktrace_str = "-- No stacktrace data found --\n" if not self.stacktrace else self.stacktrace + stacktrace_str = "-- No stacktrace data found --" if not self.stacktrace else self.stacktrace output = ( f"Test CRASHED, return code {hex(self.ret_code)}\n" f"---------------\n" @@ -675,7 +675,7 @@ class EditorTestSuite(): try: elem = json.loads(m.groups()[0]) found_jsons[elem["name"]] = elem - except Exception as e: + except Exception: continue # Avoid to fail if the output data is corrupt # Try to find the element in the log, this is used for cutting the log contents later From 250a91dd96d399b10069559a55975afa18468da4 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Tue, 26 Oct 2021 19:10:46 -0400 Subject: [PATCH 21/77] Network Hierarchy Root and Child components can now act as MultiplayerInputDriver for components with NetworkInputs Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../Code/Source/Components/NetworkHierarchyChildComponent.cpp | 1 + .../Code/Source/Components/NetworkHierarchyRootComponent.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkHierarchyChildComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkHierarchyChildComponent.cpp index 59782b1f4d..aa90b1b17b 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkHierarchyChildComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkHierarchyChildComponent.cpp @@ -45,6 +45,7 @@ namespace Multiplayer void NetworkHierarchyChildComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("NetworkHierarchyChildComponent")); + provided.push_back(AZ_CRC_CE("MultiplayerInputDriver")); } void NetworkHierarchyChildComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkHierarchyRootComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkHierarchyRootComponent.cpp index 76f4bddb1a..1404484d5c 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkHierarchyRootComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkHierarchyRootComponent.cpp @@ -53,6 +53,7 @@ namespace Multiplayer void NetworkHierarchyRootComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("NetworkHierarchyRootComponent")); + provided.push_back(AZ_CRC_CE("MultiplayerInputDriver")); } void NetworkHierarchyRootComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) From ee57885d640e2d7ea9e23756a2ced8c12d9cdbc0 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Wed, 27 Oct 2021 10:10:59 -0500 Subject: [PATCH 22/77] Cherry picked PythonGem template to stabilization. Signed-off-by: Chris Galvan --- Templates/CMakeLists.txt | 2 + Templates/PythonGem/Template/CMakeLists.txt | 14 ++ .../Code/${NameLower}_editor_files.cmake | 14 ++ .../${NameLower}_editor_shared_files.cmake | 11 + .../${NameLower}_editor_tests_files.cmake | 11 + .../PythonGem/Template/Code/CMakeLists.txt | 76 ++++++ .../Code/Include/${Name}/${Name}Bus.h | 40 ++++ .../Linux/${NameLower}_linux_files.cmake | 15 ++ .../${NameLower}_shared_linux_files.cmake | 15 ++ .../Code/Platform/Linux/PAL_linux.cmake | 11 + .../Platform/Mac/${NameLower}_mac_files.cmake | 15 ++ .../Mac/${NameLower}_shared_mac_files.cmake | 15 ++ .../Template/Code/Platform/Mac/PAL_mac.cmake | 11 + .../${NameLower}_shared_windows_files.cmake | 15 ++ .../Windows/${NameLower}_windows_files.cmake | 15 ++ .../Code/Platform/Windows/PAL_windows.cmake | 11 + .../Code/Source/${Name}EditorModule.cpp | 47 ++++ .../Source/${Name}EditorSystemComponent.cpp | 70 ++++++ .../Source/${Name}EditorSystemComponent.h | 42 ++++ .../Code/Source/${Name}ModuleInterface.h | 36 +++ .../Template/Code/Tests/${Name}EditorTest.cpp | 13 ++ .../Editor/Scripts/${NameLower}_dialog.py | 46 ++++ .../Template/Editor/Scripts/__init__.py | 9 + .../Template/Editor/Scripts/bootstrap.py | 117 ++++++++++ Templates/PythonGem/Template/gem.json | 16 ++ Templates/PythonGem/Template/preview.png | 3 + Templates/PythonGem/template.json | 216 ++++++++++++++++++ 27 files changed, 906 insertions(+) create mode 100644 Templates/PythonGem/Template/CMakeLists.txt create mode 100644 Templates/PythonGem/Template/Code/${NameLower}_editor_files.cmake create mode 100644 Templates/PythonGem/Template/Code/${NameLower}_editor_shared_files.cmake create mode 100644 Templates/PythonGem/Template/Code/${NameLower}_editor_tests_files.cmake create mode 100644 Templates/PythonGem/Template/Code/CMakeLists.txt create mode 100644 Templates/PythonGem/Template/Code/Include/${Name}/${Name}Bus.h create mode 100644 Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Linux/PAL_linux.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Mac/PAL_mac.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Windows/PAL_windows.cmake create mode 100644 Templates/PythonGem/Template/Code/Source/${Name}EditorModule.cpp create mode 100644 Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.cpp create mode 100644 Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.h create mode 100644 Templates/PythonGem/Template/Code/Source/${Name}ModuleInterface.h create mode 100644 Templates/PythonGem/Template/Code/Tests/${Name}EditorTest.cpp create mode 100644 Templates/PythonGem/Template/Editor/Scripts/${NameLower}_dialog.py create mode 100644 Templates/PythonGem/Template/Editor/Scripts/__init__.py create mode 100644 Templates/PythonGem/Template/Editor/Scripts/bootstrap.py create mode 100644 Templates/PythonGem/Template/gem.json create mode 100644 Templates/PythonGem/Template/preview.png create mode 100644 Templates/PythonGem/template.json diff --git a/Templates/CMakeLists.txt b/Templates/CMakeLists.txt index 1a3a45b5ec..84a708989a 100644 --- a/Templates/CMakeLists.txt +++ b/Templates/CMakeLists.txt @@ -9,6 +9,8 @@ ly_install_directory( DIRECTORIES AssetGem + CustomTool + PythonGem DefaultGem DefaultProject MinimalProject diff --git a/Templates/PythonGem/Template/CMakeLists.txt b/Templates/PythonGem/Template/CMakeLists.txt new file mode 100644 index 0000000000..d61bbd9e7d --- /dev/null +++ b/Templates/PythonGem/Template/CMakeLists.txt @@ -0,0 +1,14 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(o3de_gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(o3de_gem_json ${o3de_gem_path}/gem.json) +o3de_read_json_key(o3de_gem_name ${o3de_gem_json} "gem_name") +o3de_restricted_path(${o3de_gem_json} o3de_gem_restricted_path) + +add_subdirectory(Code) diff --git a/Templates/PythonGem/Template/Code/${NameLower}_editor_files.cmake b/Templates/PythonGem/Template/Code/${NameLower}_editor_files.cmake new file mode 100644 index 0000000000..8362d37f52 --- /dev/null +++ b/Templates/PythonGem/Template/Code/${NameLower}_editor_files.cmake @@ -0,0 +1,14 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(FILES + Include/${Name}/${Name}Bus.h + Source/${Name}ModuleInterface.h + Source/${Name}EditorSystemComponent.cpp + Source/${Name}EditorSystemComponent.h +) diff --git a/Templates/PythonGem/Template/Code/${NameLower}_editor_shared_files.cmake b/Templates/PythonGem/Template/Code/${NameLower}_editor_shared_files.cmake new file mode 100644 index 0000000000..2d4ceae97d --- /dev/null +++ b/Templates/PythonGem/Template/Code/${NameLower}_editor_shared_files.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(FILES + Source/${Name}EditorModule.cpp +) diff --git a/Templates/PythonGem/Template/Code/${NameLower}_editor_tests_files.cmake b/Templates/PythonGem/Template/Code/${NameLower}_editor_tests_files.cmake new file mode 100644 index 0000000000..ff45c2fc1c --- /dev/null +++ b/Templates/PythonGem/Template/Code/${NameLower}_editor_tests_files.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(FILES + Tests/${Name}EditorTest.cpp +) diff --git a/Templates/PythonGem/Template/Code/CMakeLists.txt b/Templates/PythonGem/Template/Code/CMakeLists.txt new file mode 100644 index 0000000000..b7a5ac89a9 --- /dev/null +++ b/Templates/PythonGem/Template/Code/CMakeLists.txt @@ -0,0 +1,76 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Currently we are in the Code folder: ${CMAKE_CURRENT_LIST_DIR} +# Get the platform specific folder ${pal_dir} for the current folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} +# Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform +# in which case it will see if that platform is present here or in the restricted folder. +# i.e. It could here in our gem : Gems/${Name}/Code/Platform/ or +# //Gems/${Name}/Code +ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_gem_restricted_path} ${o3de_gem_path} ${o3de_gem_name}) + +# Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the +# traits for this platform. Traits for a platform are defines for things like whether or not something in this gem +# is supported by this platform. +include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) + + +# If we are on a host platform, we want to add the host tools targets like the ${Name}.Editor target which +# will also depend on ${Name}.Static +if(PAL_TRAIT_BUILD_HOST_TOOLS) + ly_add_target( + NAME ${Name}.Editor.Static STATIC + NAMESPACE Gem + FILES_CMAKE + ${NameLower}_editor_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + PUBLIC + Include + BUILD_DEPENDENCIES + PUBLIC + AZ::AzToolsFramework + ) + + ly_add_target( + NAME ${Name}.Editor GEM_MODULE + NAMESPACE Gem + AUTOMOC + FILES_CMAKE + ${NameLower}_editor_shared_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + PUBLIC + Include + BUILD_DEPENDENCIES + PUBLIC + Gem::${Name}.Editor.Static + ) + + # By default, we will specify that the above target ${Name} would be used by + # Tool and Builder type targets when this gem is enabled. If you don't want it + # active in Tools or Builders by default, delete one of both of the following lines: + ly_create_alias(NAME ${Name}.Tools NAMESPACE Gem TARGETS Gem::${Name}.Editor) + ly_create_alias(NAME ${Name}.Builders NAMESPACE Gem TARGETS Gem::${Name}.Editor) + + +endif() + +################################################################################ +# Tests +################################################################################ +# See if globally, tests are supported +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + # We globally support tests, see if we support tests on this platform for ${Name}.Static + + # If we are a host platform we want to add tools test like editor tests here + if(PAL_TRAIT_BUILD_HOST_TOOLS) + endif() +endif() diff --git a/Templates/PythonGem/Template/Code/Include/${Name}/${Name}Bus.h b/Templates/PythonGem/Template/Code/Include/${Name}/${Name}Bus.h new file mode 100644 index 0000000000..d09bb2b009 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Include/${Name}/${Name}Bus.h @@ -0,0 +1,40 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#pragma once + +#include +#include + +namespace ${SanitizedCppName} +{ + class ${SanitizedCppName}Requests + { + public: + AZ_RTTI(${SanitizedCppName}Requests, "{${Random_Uuid}}"); + virtual ~${SanitizedCppName}Requests() = default; + // Put your public methods here + }; + + class ${SanitizedCppName}BusTraits + : public AZ::EBusTraits + { + public: + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + ////////////////////////////////////////////////////////////////////////// + }; + + using ${SanitizedCppName}RequestBus = AZ::EBus<${SanitizedCppName}Requests, ${SanitizedCppName}BusTraits>; + using ${SanitizedCppName}Interface = AZ::Interface<${SanitizedCppName}Requests>; + +} // namespace ${SanitizedCppName} diff --git a/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake b/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake new file mode 100644 index 0000000000..2f58a2e6f5 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Linux +# i.e. ../Source/Linux/${Name}Linux.cpp +# ../Source/Linux/${Name}Linux.h +# ../Include/Linux/${Name}Linux.h + +set(FILES +) diff --git a/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake b/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake new file mode 100644 index 0000000000..2f58a2e6f5 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Linux +# i.e. ../Source/Linux/${Name}Linux.cpp +# ../Source/Linux/${Name}Linux.h +# ../Include/Linux/${Name}Linux.h + +set(FILES +) diff --git a/Templates/PythonGem/Template/Code/Platform/Linux/PAL_linux.cmake b/Templates/PythonGem/Template/Code/Platform/Linux/PAL_linux.cmake new file mode 100644 index 0000000000..0abcd887e8 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Linux/PAL_linux.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE) \ No newline at end of file diff --git a/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake b/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake new file mode 100644 index 0000000000..1cf737a2f1 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Mac +# i.e. ../Source/Mac/${Name}Mac.cpp +# ../Source/Mac/${Name}Mac.h +# ../Include/Mac/${Name}Mac.h + +set(FILES +) diff --git a/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake b/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake new file mode 100644 index 0000000000..1cf737a2f1 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Mac +# i.e. ../Source/Mac/${Name}Mac.cpp +# ../Source/Mac/${Name}Mac.h +# ../Include/Mac/${Name}Mac.h + +set(FILES +) diff --git a/Templates/PythonGem/Template/Code/Platform/Mac/PAL_mac.cmake b/Templates/PythonGem/Template/Code/Platform/Mac/PAL_mac.cmake new file mode 100644 index 0000000000..0abcd887e8 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Mac/PAL_mac.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE) \ No newline at end of file diff --git a/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake b/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake new file mode 100644 index 0000000000..712aad1207 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Windows +# i.e. ../Source/Windows/${Name}Windows.cpp +# ../Source/Windows/${Name}Windows.h +# ../Include/Windows/${Name}Windows.h + +set(FILES +) diff --git a/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake b/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake new file mode 100644 index 0000000000..712aad1207 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Windows +# i.e. ../Source/Windows/${Name}Windows.cpp +# ../Source/Windows/${Name}Windows.h +# ../Include/Windows/${Name}Windows.h + +set(FILES +) diff --git a/Templates/PythonGem/Template/Code/Platform/Windows/PAL_windows.cmake b/Templates/PythonGem/Template/Code/Platform/Windows/PAL_windows.cmake new file mode 100644 index 0000000000..0abcd887e8 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Windows/PAL_windows.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE) \ No newline at end of file diff --git a/Templates/PythonGem/Template/Code/Source/${Name}EditorModule.cpp b/Templates/PythonGem/Template/Code/Source/${Name}EditorModule.cpp new file mode 100644 index 0000000000..644c513747 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Source/${Name}EditorModule.cpp @@ -0,0 +1,47 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include <${Name}ModuleInterface.h> +#include <${Name}EditorSystemComponent.h> + +namespace ${SanitizedCppName} +{ + class ${SanitizedCppName}EditorModule + : public ${SanitizedCppName}ModuleInterface + { + public: + AZ_RTTI(${SanitizedCppName}EditorModule, "${ModuleClassId}", ${SanitizedCppName}ModuleInterface); + AZ_CLASS_ALLOCATOR(${SanitizedCppName}EditorModule, AZ::SystemAllocator, 0); + + ${SanitizedCppName}EditorModule() + { + // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. + // Add ALL components descriptors associated with this gem to m_descriptors. + // This will associate the AzTypeInfo information for the components with the the SerializeContext, BehaviorContext and EditContext. + // This happens through the [MyComponent]::Reflect() function. + m_descriptors.insert(m_descriptors.end(), { + ${SanitizedCppName}EditorSystemComponent::CreateDescriptor(), + }); + } + + /** + * Add required SystemComponents to the SystemEntity. + * Non-SystemComponents should not be added here + */ + AZ::ComponentTypeList GetRequiredSystemComponents() const override + { + return AZ::ComponentTypeList { + azrtti_typeid<${SanitizedCppName}EditorSystemComponent>(), + }; + } + }; +}// namespace ${SanitizedCppName} + +AZ_DECLARE_MODULE_CLASS(Gem_${SanitizedCppName}, ${SanitizedCppName}::${SanitizedCppName}EditorModule) diff --git a/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.cpp b/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.cpp new file mode 100644 index 0000000000..1493c98e68 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.cpp @@ -0,0 +1,70 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ + // {END_LICENSE} + +#include +#include <${Name}EditorSystemComponent.h> + +namespace ${SanitizedCppName} +{ + void ${SanitizedCppName}EditorSystemComponent::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class<${SanitizedCppName}EditorSystemComponent, AZ::Component>(); + } + } + + ${SanitizedCppName}EditorSystemComponent::${SanitizedCppName}EditorSystemComponent() + { + if (${SanitizedCppName}Interface::Get() == nullptr) + { + ${SanitizedCppName}Interface::Register(this); + } + } + + ${SanitizedCppName}EditorSystemComponent::~${SanitizedCppName}EditorSystemComponent() + { + if (${SanitizedCppName}Interface::Get() == this) + { + ${SanitizedCppName}Interface::Unregister(this); + } + } + + void ${SanitizedCppName}EditorSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("${SanitizedCppName}EditorService")); + } + + void ${SanitizedCppName}EditorSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC_CE("${SanitizedCppName}EditorService")); + } + + void ${SanitizedCppName}EditorSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required) + { + } + + void ${SanitizedCppName}EditorSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + } + + void ${SanitizedCppName}EditorSystemComponent::Activate() + { + ${SanitizedCppName}RequestBus::Handler::BusConnect(); + AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); + } + + void ${SanitizedCppName}EditorSystemComponent::Deactivate() + { + AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); + ${SanitizedCppName}RequestBus::Handler::BusDisconnect(); + } + +} // namespace ${SanitizedCppName} diff --git a/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.h b/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.h new file mode 100644 index 0000000000..1db8725a9e --- /dev/null +++ b/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.h @@ -0,0 +1,42 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ + // {END_LICENSE} + +#pragma once +#include +#include <${Name}/${Name}Bus.h> + +#include + +namespace ${SanitizedCppName} +{ + /// System component for ${SanitizedCppName} editor + class ${SanitizedCppName}EditorSystemComponent + : public ${SanitizedCppName}RequestBus::Handler + , private AzToolsFramework::EditorEvents::Bus::Handler + , public AZ::Component + { + public: + AZ_COMPONENT(${SanitizedCppName}EditorSystemComponent, "${EditorSysCompClassId}"); + static void Reflect(AZ::ReflectContext* context); + + ${SanitizedCppName}EditorSystemComponent(); + ~${SanitizedCppName}EditorSystemComponent(); + + private: + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + + // AZ::Component + void Activate(); + void Deactivate(); + }; +} // namespace ${SanitizedCppName} diff --git a/Templates/PythonGem/Template/Code/Source/${Name}ModuleInterface.h b/Templates/PythonGem/Template/Code/Source/${Name}ModuleInterface.h new file mode 100644 index 0000000000..4ddfc9c007 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Source/${Name}ModuleInterface.h @@ -0,0 +1,36 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include +#include + +namespace ${SanitizedCppName} +{ + class ${SanitizedCppName}ModuleInterface + : public AZ::Module + { + public: + AZ_RTTI(${SanitizedCppName}ModuleInterface, "{${Random_Uuid}}", AZ::Module); + AZ_CLASS_ALLOCATOR(${SanitizedCppName}ModuleInterface, AZ::SystemAllocator, 0); + + ${SanitizedCppName}ModuleInterface() + { + } + + /** + * Add required SystemComponents to the SystemEntity. + */ + AZ::ComponentTypeList GetRequiredSystemComponents() const override + { + return AZ::ComponentTypeList{ + }; + } + }; +}// namespace ${SanitizedCppName} diff --git a/Templates/PythonGem/Template/Code/Tests/${Name}EditorTest.cpp b/Templates/PythonGem/Template/Code/Tests/${Name}EditorTest.cpp new file mode 100644 index 0000000000..9b84575fa0 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Tests/${Name}EditorTest.cpp @@ -0,0 +1,13 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include + +AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); diff --git a/Templates/PythonGem/Template/Editor/Scripts/${NameLower}_dialog.py b/Templates/PythonGem/Template/Editor/Scripts/${NameLower}_dialog.py new file mode 100644 index 0000000000..39515711ae --- /dev/null +++ b/Templates/PythonGem/Template/Editor/Scripts/${NameLower}_dialog.py @@ -0,0 +1,46 @@ +""" +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 +""" +# ------------------------------------------------------------------------- +"""${SanitizedCppName}\\editor\\scripts\\${SanitizedCppName}_dialog.py +Generated from O3DE PythonGem Template""" + +import azlmbr +from shiboken2 import wrapInstance, getCppPointer +from PySide2 import QtCore, QtWidgets, QtGui +from PySide2.QtCore import QEvent, Qt +from PySide2.QtWidgets import QVBoxLayout, QAction, QDialog, QHeaderView, QLabel, QLineEdit, QPushButton, QSplitter, QTreeWidget, QTreeWidgetItem, QWidget, QAbstractButton + +# Once PySide2 has been bootstrapped, register our ${SanitizedCppName}Dialog with the Editor + +class ${SanitizedCppName}Dialog(QDialog): + def __init__(self, parent=None): + super(${SanitizedCppName}Dialog, self).__init__(parent) + + self.setObjectName("${SanitizedCppName}Dialog") + + self.setWindowTitle("HelloWorld, ${SanitizedCppName} Dialog") + + self.mainLayout = QVBoxLayout(self) + + self.introLabel = QLabel("Put your cool stuff here!") + + self.mainLayout.addWidget(self.introLabel, 0, Qt.AlignCenter) + + self.helpText = str("For help getting started," + "visit the UI Development documentation
" + "or come ask a question in the sig-ui-ux channel on Discord") + + self.helpLabel = QLabel() + self.helpLabel.setTextFormat(Qt.RichText) + self.helpLabel.setText(self.helpText) + self.helpLabel.setOpenExternalLinks(True) + + self.mainLayout.addWidget(self.helpLabel, 0, Qt.AlignCenter) + + self.setLayout(self.mainLayout) + + return \ No newline at end of file diff --git a/Templates/PythonGem/Template/Editor/Scripts/__init__.py b/Templates/PythonGem/Template/Editor/Scripts/__init__.py new file mode 100644 index 0000000000..b5da0c7ff0 --- /dev/null +++ b/Templates/PythonGem/Template/Editor/Scripts/__init__.py @@ -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 +""" +# ------------------------------------------------------------------------- + +__ALL__ = ['bootstrap','${NameLower}_dialog'] \ No newline at end of file diff --git a/Templates/PythonGem/Template/Editor/Scripts/bootstrap.py b/Templates/PythonGem/Template/Editor/Scripts/bootstrap.py new file mode 100644 index 0000000000..060116d36c --- /dev/null +++ b/Templates/PythonGem/Template/Editor/Scripts/bootstrap.py @@ -0,0 +1,117 @@ +""" +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 +""" +# ------------------------------------------------------------------------- +"""${SanitizedCppName}\\editor\\scripts\\boostrap.py +Generated from O3DE PythonGem Template""" + +import azlmbr +import az_qt_helpers +from PySide2 import QtCore, QtWidgets, QtGui +from PySide2.QtCore import QEvent, Qt +from PySide2.QtWidgets import QMainWindow, QAction, QDialog, QHeaderView, QLabel, QLineEdit, QPushButton, QSplitter, QTreeWidget, QTreeWidgetItem, QWidget, QAbstractButton +# ------------------------------------------------------------------------- + + +# ------------------------------------------------------------------------- +class SampleUI(QtWidgets.QDialog): + """Lightweight UI Test Class created a button""" + def __init__(self, parent, title='Not Set'): + super(SampleUI, self).__init__(parent) + self.setWindowTitle(title) + self.initUI() + + def initUI(self): + mainLayout = QtWidgets.QHBoxLayout() + testBtn = QtWidgets.QPushButton("I am just a Button man!") + mainLayout.addWidget(testBtn) + self.setLayout(mainLayout) +# ------------------------------------------------------------------------- + +if __name__ == "__main__": + print("${SanitizedCppName}.boostrap, Generated from O3DE PythonGem Template") + + # --------------------------------------------------------------------- + # validate pyside before continuing + try: + azlmbr.qt.QtForPythonRequestBus(azlmbr.bus.Broadcast, 'IsActive') + params = azlmbr.qt.QtForPythonRequestBus(azlmbr.bus.Broadcast, 'GetQtBootstrapParameters') + params is not None and params.mainWindowId is not 0 + from PySide2 import QtWidgets + except Exception as e: + _LOGGER.error(f'Pyside not available, exception: {e}') + raise e + + # keep going, import the other PySide2 bits we will use + from PySide2 import QtGui + from PySide2.QtCore import Slot + from shiboken2 import wrapInstance, getCppPointer + + # Get our Editor main window + _widget_main_window = None + try: + _widget_main_window = az_qt_helpers.get_editor_main_window() + except: + pass # may be booting in the AP? + # --------------------------------------------------------------------- + + + # --------------------------------------------------------------------- + if _widget_main_window: + # creat a custom menu + _tag_str = '${SanitizedCppName}' + + # create our own menuBar + ${SanitizedCppName}_menu = _widget_main_window.menuBar().addMenu(f"&{_tag_str}") + + # nest a menu for util/tool launching + ${SanitizedCppName}_launch_menu = ${SanitizedCppName}_menu.addMenu("examples") + else: + print('No O3DE MainWindow') + # --------------------------------------------------------------------- + + + # --------------------------------------------------------------------- + if _widget_main_window: + # (1) add the first SampleUI + action_launch_sample_ui = ${SanitizedCppName}_launch_menu.addAction("O3DE:SampleUI") + + @Slot() + def clicked_sample_ui(): + while 1: # simple PySide2 test, set to 0 to disable + ui = SampleUI(parent=_widget_main_window, title='O3DE:SampleUI') + ui.show() + break + return + # Add click event to menu bar + action_launch_sample_ui.triggered.connect(clicked_sample_ui) + # --------------------------------------------------------------------- + + + # --------------------------------------------------------------------- + if _widget_main_window: + # (1) and custom external module Qwidget + action_launch_${SanitizedCppName}_dialog = ${SanitizedCppName}_launch_menu.addAction("O3DE:${SanitizedCppName}_dialog") + + @Slot() + def clicked_${SanitizedCppName}_dialog(): + while 1: # simple PySide2 test, set to 0 to disable + try: + import az_qt_helpers + from ${NameLower}_dialog import ${SanitizedCppName}Dialog + az_qt_helpers.register_view_pane('${SanitizedCppName} Popup', ${SanitizedCppName}Dialog) + except Exception as e: + print(f'Error: {e}') + print('Skipping register our ${SanitizedCppName}Dialog with the Editor.') + ${SanitizedCppName}_dialog = ${SanitizedCppName}Dialog(parent=_widget_main_window) + ${SanitizedCppName}_dialog.show() + break + return + # Add click event to menu bar + action_launch_${SanitizedCppName}_dialog.triggered.connect(clicked_${SanitizedCppName}_dialog) + # --------------------------------------------------------------------- + + # end \ No newline at end of file diff --git a/Templates/PythonGem/Template/gem.json b/Templates/PythonGem/Template/gem.json new file mode 100644 index 0000000000..353ad6bf8d --- /dev/null +++ b/Templates/PythonGem/Template/gem.json @@ -0,0 +1,16 @@ +{ + "gem_name": "${Name}", + "display_name": "${Name}", + "license": "What license ${Name} uses goes here: i.e. https://opensource.org/licenses/MIT", + "origin": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", + "type": "Code", + "summary": "A short description of ${Name}.", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "${Name}" + ], + "icon_path": "preview.png", + "requirements": "" +} diff --git a/Templates/PythonGem/Template/preview.png b/Templates/PythonGem/Template/preview.png new file mode 100644 index 0000000000..0f393ac886 --- /dev/null +++ b/Templates/PythonGem/Template/preview.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ac9dd09bde78f389e3725ac49d61eff109857e004840bc0bc3881739df9618d +size 2217 diff --git a/Templates/PythonGem/template.json b/Templates/PythonGem/template.json new file mode 100644 index 0000000000..75be757abb --- /dev/null +++ b/Templates/PythonGem/template.json @@ -0,0 +1,216 @@ +{ + "template_name": "PythonGem", + "restricted_name": "o3de", + "restricted_platform_relative_path": "Templates", + "origin": "The primary repo for PythonGem goes here: i.e. http://www.mydomain.com", + "license": "What license PythonGem uses goes here: i.e. https://opensource.org/licenses/MIT", + "display_name": "PythonGem", + "summary": "A short description of PythonGem.", + "canonical_tags": [], + "user_tags": [ + "PythonGem" + ], + "icon_path": "preview.png", + "copyFiles": [ + { + "file": "CMakeLists.txt", + "origin": "CMakeLists.txt", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/${NameLower}_editor_files.cmake", + "origin": "Code/${NameLower}_editor_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/${NameLower}_editor_shared_files.cmake", + "origin": "Code/${NameLower}_editor_shared_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/${NameLower}_editor_tests_files.cmake", + "origin": "Code/${NameLower}_editor_tests_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/CMakeLists.txt", + "origin": "Code/CMakeLists.txt", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Include/${Name}/${Name}Bus.h", + "origin": "Code/Include/${Name}/${Name}Bus.h", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Linux/${NameLower}_linux_files.cmake", + "origin": "Code/Platform/Linux/${NameLower}_linux_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", + "origin": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Linux/PAL_linux.cmake", + "origin": "Code/Platform/Linux/PAL_linux.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Mac/${NameLower}_mac_files.cmake", + "origin": "Code/Platform/Mac/${NameLower}_mac_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", + "origin": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Mac/PAL_mac.cmake", + "origin": "Code/Platform/Mac/PAL_mac.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", + "origin": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Windows/${NameLower}_windows_files.cmake", + "origin": "Code/Platform/Windows/${NameLower}_windows_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Windows/PAL_windows.cmake", + "origin": "Code/Platform/Windows/PAL_windows.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}EditorModule.cpp", + "origin": "Code/Source/${Name}EditorModule.cpp", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}EditorSystemComponent.cpp", + "origin": "Code/Source/${Name}EditorSystemComponent.cpp", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}EditorSystemComponent.h", + "origin": "Code/Source/${Name}EditorSystemComponent.h", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}ModuleInterface.h", + "origin": "Code/Source/${Name}ModuleInterface.h", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Tests/${Name}EditorTest.cpp", + "origin": "Code/Tests/${Name}EditorTest.cpp", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Editor/Scripts/__init__.py", + "origin": "Editor/Scripts/__init__.py", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Editor/Scripts/bootstrap.py", + "origin": "Editor/Scripts/bootstrap.py", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Editor/Scripts/${NameLower}_dialog.py", + "origin": "Editor/Scripts/${NameLower}_dialog.py", + "isTemplated": true, + "isOptional": false + }, + { + "file": "gem.json", + "origin": "gem.json", + "isTemplated": true, + "isOptional": false + }, + { + "file": "preview.png", + "origin": "preview.png", + "isTemplated": false, + "isOptional": false + } + ], + "createDirectories": [ + { + "dir": "Assets", + "origin": "Assets" + }, + { + "dir": "Code", + "origin": "Code" + }, + { + "dir": "Editor", + "origin": "Editor" + }, + { + "dir": "Editor/Scripts", + "origin": "Editor/Scripts" + }, + { + "dir": "Code/Include", + "origin": "Code/Include" + }, + { + "dir": "Code/Include/${Name}", + "origin": "Code/Include/${Name}" + }, + { + "dir": "Code/Platform", + "origin": "Code/Platform" + }, + { + "dir": "Code/Platform/Linux", + "origin": "Code/Platform/Linux" + }, + { + "dir": "Code/Platform/Mac", + "origin": "Code/Platform/Mac" + }, + { + "dir": "Code/Platform/Windows", + "origin": "Code/Platform/Windows" + }, + { + "dir": "Code/Source", + "origin": "Code/Source" + }, + { + "dir": "Code/Tests", + "origin": "Code/Tests" + } + ] +} From b7b79efd6938c0c7aa9622acb9ca481e46f4da99 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 27 Oct 2021 10:17:27 -0700 Subject: [PATCH 23/77] fixes monolithic vs non-monolithic installation (generates, monolithic doesnt build) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../RPI.Reflect/Material/MaterialAsset.cpp | 2 +- cmake/LYWrappers.cmake | 7 ++-- cmake/Platform/Common/Install_common.cmake | 39 ++++++++++--------- .../install/ConfigurationType_config.cmake.in | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp index e9d8a42641..36f4947e3d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp @@ -208,7 +208,7 @@ namespace AZ return; } - const uint32_t originalVersion = m_materialTypeVersion; + [[maybe_unused]] const uint32_t originalVersion = m_materialTypeVersion; bool changesWereApplied = false; diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index fb3d420c26..c617603fa3 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -403,7 +403,7 @@ function(ly_target_link_libraries TARGET) message(FATAL_ERROR "You must provide a target") endif() - set_property(GLOBAL APPEND PROPERTY LY_DELAYED_LINK_${TARGET} ${ARGN}) + set_property(TARGET ${TARGET} APPEND PROPERTY LY_DELAYED_LINK ${ARGN}) set_property(GLOBAL APPEND PROPERTY LY_DELAYED_LINK_TARGETS ${TARGET}) # to walk them at the end endfunction() @@ -430,7 +430,7 @@ function(ly_delayed_target_link_libraries) get_property(delayed_targets GLOBAL PROPERTY LY_DELAYED_LINK_TARGETS) foreach(target ${delayed_targets}) - get_property(delayed_link GLOBAL PROPERTY LY_DELAYED_LINK_${target}) + get_property(delayed_link TARGET ${target} PROPERTY LY_DELAYED_LINK) if(delayed_link) cmake_parse_arguments(ly_delayed_target_link_libraries "" "" "${visibilities}" ${delayed_link}) @@ -458,9 +458,8 @@ function(ly_delayed_target_link_libraries) endforeach() endforeach() - set_property(GLOBAL PROPERTY LY_DELAYED_LINK_${target}) - endif() + endif() endforeach() set_property(GLOBAL PROPERTY LY_DELAYED_LINK_TARGETS) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 622100b4d8..8a06d1b584 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -85,6 +85,16 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar continue() endif() + # For some cases (e.g. codegen) we generate headers that end up in the BUILD_DIR. Since the BUILD_DIR + # is per-permutation, we need to install such headers per permutation. For the other cases, we can install + # under the default component since they are shared across permutations/configs. + cmake_path(IS_PREFIX CMAKE_BINARY_DIR ${include_directory} NORMALIZE include_directory_child_of_build) + if(NOT include_directory_child_of_build) + set(include_directory_component ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) + else() + set(include_directory_component ${LY_INSTALL_PERMUTATION_COMPONENT}) + endif() + unset(rel_include_dir) cmake_path(RELATIVE_PATH include_directory BASE_DIRECTORY ${LY_ROOT_FOLDER} OUTPUT_VARIABLE rel_include_dir) cmake_path(APPEND rel_include_dir "..") @@ -92,7 +102,7 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar ly_install(DIRECTORY ${include_directory} DESTINATION ${destination_dir} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} + COMPONENT ${include_directory_component} FILES_MATCHING PATTERN *.h PATTERN *.hpp @@ -203,24 +213,13 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar endif() string(REPEAT " " 12 PLACEHOLDER_INDENT) - get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) + get_property(inteface_build_dependencies_props TARGET ${TARGET_NAME} PROPERTY LY_DELAYED_LINK) unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) if(inteface_build_dependencies_props) - foreach(build_dependency ${inteface_build_dependencies_props}) + cmake_parse_arguments(build_deps "" "" "PRIVATE;PUBLIC;INTERFACE" ${inteface_build_dependencies_props}) + foreach(build_dependency IN LISTS build_deps_INTERFACE build_deps_PUBLIC) # Skip wrapping produced when targets are not created in the same directory - if(NOT ${build_dependency} MATCHES "^::@") - list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${build_dependency}") - endif() - endforeach() - endif() - # We also need to pass the private link libraries since we will use that to generate the runtime dependencies - get_target_property(private_build_dependencies_props ${TARGET_NAME} LINK_LIBRARIES) - if(private_build_dependencies_props) - foreach(build_dependency ${private_build_dependencies_props}) - # Skip wrapping produced when targets are not created in the same directory - if(NOT ${build_dependency} MATCHES "^::@") - list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${build_dependency}") - endif() + list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${build_dependency}") endforeach() endif() list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) @@ -353,7 +352,7 @@ include(Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cm file(CONFIGURE OUTPUT "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake" CONTENT [[ @cmake_copyright_comment@ if(LY_MONOLITHIC_GAME) - include(Platform/${PAL_PLATFORM_NAME}/Monolithic/permutation.cmake) + include(Platform/${PAL_PLATFORM_NAME}/Monolithic/permutation.cmake OPTIONAL) else() include(Platform/${PAL_PLATFORM_NAME}/Default/permutation.cmake) endif() @@ -394,6 +393,7 @@ function(ly_setup_cmake_install) COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} PATTERN "__pycache__" EXCLUDE PATTERN "Findo3de.cmake" EXCLUDE + PATTERN "cmake/ConfigurationTypes.cmake" EXCLUDE REGEX "3rdParty/Platform\/.*\/BuiltInPackages_.*\.cmake" EXCLUDE ) @@ -739,7 +739,7 @@ function(ly_setup_o3de_install) # Misc ly_install(FILES - ${LY_ROOT_FOLDER}/ctest_pytest.ini + ${LY_ROOT_FOLDER}/pytest.ini ${LY_ROOT_FOLDER}/LICENSE.txt ${LY_ROOT_FOLDER}/README.md DESTINATION . @@ -750,7 +750,8 @@ function(ly_setup_o3de_install) foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS}) ly_install(CODE "set(LY_CORE_COMPONENT_ALREADY_INCLUDED TRUE) -include(${external_dir}/cmake_install.cmake)" +include(${external_dir}/cmake_install.cmake) +set(LY_CORE_COMPONENT_ALREADY_INCLUDED FALSE)" ALL_COMPONENTS ) endforeach() diff --git a/cmake/install/ConfigurationType_config.cmake.in b/cmake/install/ConfigurationType_config.cmake.in index 074e034899..0a6940d7ff 100644 --- a/cmake/install/ConfigurationType_config.cmake.in +++ b/cmake/install/ConfigurationType_config.cmake.in @@ -8,4 +8,4 @@ include_guard(GLOBAL) -list(APPEND CMAKE_CONFIGURATION_TYPES @CMAKE_INSTALL_CONFIG_NAME@) +list(APPEND CMAKE_CONFIGURATION_TYPES @conf@) From 9e0756f3c11ae5218246fec732e1ceb4da14caeb Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Wed, 27 Oct 2021 11:28:21 -0700 Subject: [PATCH 24/77] ATOM-16656 PassTree tool: ParentPass image attachment preview doesn't work (#5032) Move imageAttachmentCopy instance from RenderPass to Pass so it can support preview image for all passes but not only for RenderPass. Fixed an issue with image attachment preview when switching render pipeline with attachment preview on. Signed-off-by: Qing Tao --- .../Source/FrameCaptureSystemComponent.cpp | 2 +- .../Code/Include/Atom/RPI.Public/Pass/Pass.h | 10 ++ .../Include/Atom/RPI.Public/Pass/RenderPass.h | 7 - .../Specific/ImageAttachmentPreviewPass.h | 2 +- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 18 +++ .../Source/RPI.Public/Pass/RenderPass.cpp | 12 +- .../Specific/ImageAttachmentPreviewPass.cpp | 4 +- .../Code/Include/Atom/Utils/ImGuiPassTree.h | 2 + .../Code/Include/Atom/Utils/ImGuiPassTree.inl | 138 +++++++++++------- 9 files changed, 118 insertions(+), 77 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index ed2d8a1d9f..a9bb7271ab 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index e7b9825ecb..be7ac9e7a4 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,7 @@ namespace AZ struct PassRequest; struct PassValidationResults; class AttachmentReadback; + class ImageAttachmentCopy; using SortedPipelineViewTags = AZStd::set; using PassesByDrawList = AZStd::map; @@ -94,6 +96,8 @@ namespace AZ { AZ_RPI_PASS(Pass); + friend class ImageAttachmentPreviewPass; + public: using ChildPassIndex = RHI::Handle; @@ -369,6 +373,9 @@ namespace AZ void UpdateReadbackAttachment(FramePrepareParams params, bool beforeAddScopes); + // Setup ImageAttachmentCopy + void UpdateAttachmentCopy(FramePrepareParams params); + // --- Protected Members --- const Name PassNameThis{"This"}; @@ -466,6 +473,9 @@ namespace AZ AZStd::shared_ptr m_attachmentReadback; PassAttachmentReadbackOption m_readbackOption; + // For image attachment preview + AZStd::weak_ptr m_attachmentCopy; + private: // Return the Timestamp result of this pass virtual TimestampResult GetTimestampResultInternal() const; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h index 5fb90d044e..ec51e34897 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h @@ -13,9 +13,7 @@ #include #include -#include #include -#include #include namespace AZ @@ -29,7 +27,6 @@ namespace AZ namespace RPI { - class ImageAttachmentCopy; class RenderPass; class Query; @@ -41,8 +38,6 @@ namespace AZ { AZ_RPI_PASS(RenderPass); - friend class ImageAttachmentPreviewPass; - using ScopeQuery = AZStd::array, static_cast(ScopeQueryType::Count)>; public: @@ -143,8 +138,6 @@ namespace AZ // Readback the results from the ScopeQueries void ReadbackScopeQueryResults(); - AZStd::weak_ptr m_attachmentCopy; - // Readback results from the Timestamp queries TimestampResult m_timestampResult; // Readback results from the PipelineStatistics queries diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h index 2e2b14a699..8ee7a44b6f 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h @@ -78,7 +78,7 @@ namespace AZ ~ImageAttachmentPreviewPass(); //! Preview the PassAttachment of a pass' PassAttachmentBinding - void PreviewImageAttachmentForPass(RenderPass* pass, const PassAttachment* passAttachment); + void PreviewImageAttachmentForPass(Pass* pass, const PassAttachment* passAttachment); //! Set the output color attachment for this pass void SetOutputColorAttachment(RHI::Ptr outputImageAttachment); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index 3c1de28d6a..d04a35a10b 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -1215,6 +1216,12 @@ namespace AZ m_queueState = PassQueueState::NoQueue; InitializeInternal(); + + // Need to recreate the dest attachment because the source attachment might be changed + if (!m_attachmentCopy.expired()) + { + m_attachmentCopy.lock()->InvalidateDestImage(); + } m_state = PassState::Initialized; } @@ -1301,6 +1308,9 @@ namespace AZ // readback attachment with output state UpdateReadbackAttachment(params, false); + // update attachment copy for preview + UpdateAttachmentCopy(params); + UpdateConnectedOutputBindings(); } @@ -1489,6 +1499,14 @@ namespace AZ } } + void Pass::UpdateAttachmentCopy(FramePrepareParams params) + { + if (!m_attachmentCopy.expired()) + { + m_attachmentCopy.lock()->FrameBegin(params); + } + } + bool Pass::IsTimestampQueryEnabled() const { return m_flags.m_timestampQueryEnabled; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp index b8115dff10..8353762c0f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp @@ -177,12 +177,6 @@ namespace AZ } } } - - // Need to recreate the dest attachment because the source attachment might be changed - if (!m_attachmentCopy.expired()) - { - m_attachmentCopy.lock()->InvalidateDestImage(); - } } void RenderPass::FrameBeginInternal(FramePrepareParams params) @@ -196,11 +190,7 @@ namespace AZ // Read back the ScopeQueries submitted from previous frames ReadbackScopeQueryResults(); - - if (!m_attachmentCopy.expired()) - { - m_attachmentCopy.lock()->FrameBegin(params); - } + CollectSrgs(); PassSystemInterface::Get()->IncrementFrameRenderPassCount(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp index 105936f64d..8f83e4efe1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -131,7 +131,7 @@ namespace AZ Data::AssetBus::Handler::BusDisconnect(); } - void ImageAttachmentPreviewPass::PreviewImageAttachmentForPass(RenderPass* pass, const PassAttachment* passAttachment) + void ImageAttachmentPreviewPass::PreviewImageAttachmentForPass(Pass* pass, const PassAttachment* passAttachment) { if (passAttachment->GetAttachmentType() != RHI::AttachmentType::Image) { diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.h index 12e9776ae2..0e942bca58 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.h @@ -39,6 +39,8 @@ namespace AZ bool m_showAttachments = false; AZ::RPI::Pass* m_selectedPass = nullptr; + AZ::RPI::Pass* m_lastSelectedPass = nullptr; + AZ::Name m_selectedPassPath; AZ::RHI::AttachmentId m_attachmentId; AZ::Name m_slotName; bool m_selectedChanged = false; diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl index fa649ed47b..55e457926a 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl @@ -31,7 +31,7 @@ namespace AZ::Render { - inline AZ::RPI::PassAttachment* FindPassAttachment(AZ::RPI::RenderPass* pass, AZ::RHI::AttachmentId attachmentId) + inline AZ::RPI::PassAttachment* FindPassAttachment(AZ::RPI::Pass* pass, AZ::RHI::AttachmentId attachmentId) { for (auto& binding : pass->GetAttachmentBindings()) { @@ -47,6 +47,10 @@ namespace AZ::Render { using namespace AZ; + // always set m_selectedPass to empty and use m_selectedPassPath to find it when render the pass tree + m_selectedPass = nullptr; + bool needSaveAttachment = false; + ImGui::SetNextWindowSize(ImVec2(200.f, 200.f), ImGuiCond_FirstUseEver); if (ImGui::Begin("PassTree View", &draw, ImGuiWindowFlags_None)) { @@ -83,60 +87,16 @@ namespace AZ::Render if (Scriptable_ImGui::Button("Save Attachment")) { - m_attachmentReadbackInfo = ""; - if (!m_readback) - { - m_readback = AZStd::make_shared(AZ::RHI::ScopeId{ "AttachmentReadback" }); - m_readback->SetCallback(AZStd::bind(&ImGuiPassTree::ReadbackCallback, this, AZStd::placeholders::_1)); - } - - if (m_selectedPass && !m_slotName.IsEmpty()) - { - bool readbackResult = m_selectedPass->ReadbackAttachment(m_readback, m_slotName); - if (!readbackResult) - { - AZ_Error("ImGuiPassTree", false, "Failed to readback attachment from pass [%s] slot [%s]", m_selectedPass->GetName().GetCStr(), m_slotName.GetCStr()); - } - } + needSaveAttachment = true; } ImGui::TextWrapped("%s", m_attachmentReadbackInfo.c_str()); } - if (m_previewAttachment && m_selectedChanged) - { - m_selectedChanged = false; - if (!m_attachmentId.IsEmpty() && m_selectedPass) - { - AZ::RPI::RenderPass* renderPass = azrtti_cast(m_selectedPass); - if (renderPass) - { - if (!m_previewPass->GetParent()) - { - RPI::PassSystemInterface::Get()->GetRootPass()->AddChild(m_previewPass); - } - AZ::RPI::PassAttachment* attachment = FindPassAttachment(renderPass, m_attachmentId); - if (attachment) - { - // Reset output attachment to empty so the preview will use pass's owner render pipeline's output - m_previewPass->SetOutputColorAttachment(nullptr); - m_previewPass->PreviewImageAttachmentForPass(renderPass, attachment); - } - } - else - { - m_previewPass->ClearPreviewAttachment(); - if (m_previewPass->GetParent()) - { - m_previewPass->QueueForRemoval(); - } - } - } - } - ImGui::End(); // Draw the hierarchical view + // It will assign m_seletedPass if there is a pass matches m_seletedPassPath ImGui::SetNextWindowPos(ImVec2(300, 60), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(300, 500), ImGuiCond_FirstUseEver); if (ImGui::Begin("PassTree", nullptr, ImGuiWindowFlags_None)) @@ -144,6 +104,63 @@ namespace AZ::Render DrawTreeView(rootPass); } ImGui::End(); + + // It's possible that the pass pointer changed but selected pass path wasn't changed + if (m_selectedPass != m_lastSelectedPass) + { + m_selectedChanged = true; + if (m_selectedPass == nullptr) + { + m_selectedPassPath = AZ::Name{}; + } + } + m_lastSelectedPass = m_selectedPass; + + if (m_previewAttachment && m_selectedChanged) + { + m_selectedChanged = false; + if (!m_attachmentId.IsEmpty() && m_selectedPass) + { + if (!m_previewPass->GetParent()) + { + RPI::PassSystemInterface::Get()->GetRootPass()->AddChild(m_previewPass); + } + AZ::RPI::PassAttachment* attachment = FindPassAttachment(m_selectedPass, m_attachmentId); + if (attachment) + { + // Reset output attachment to empty so the preview will use pass's owner render pipeline's output + m_previewPass->SetOutputColorAttachment(nullptr); + m_previewPass->PreviewImageAttachmentForPass(m_selectedPass, attachment); + } + } + else + { + m_previewPass->ClearPreviewAttachment(); + if (m_previewPass->GetParent()) + { + m_previewPass->QueueForRemoval(); + } + } + } + + if (needSaveAttachment) + { + m_attachmentReadbackInfo = ""; + if (!m_readback) + { + m_readback = AZStd::make_shared(AZ::RHI::ScopeId{ "AttachmentReadback" }); + m_readback->SetCallback(AZStd::bind(&ImGuiPassTree::ReadbackCallback, this, AZStd::placeholders::_1)); + } + + if (m_selectedPass && !m_slotName.IsEmpty()) + { + bool readbackResult = m_selectedPass->ReadbackAttachment(m_readback, m_slotName); + if (!readbackResult) + { + AZ_Error("ImGuiPassTree", false, "Failed to readback attachment from pass [%s] slot [%s]", m_selectedPass->GetName().GetCStr(), m_slotName.GetCStr()); + } + } + } } inline void ImGuiPassTree::DrawPassAttachments(AZ::RPI::Pass* pass) @@ -202,6 +219,7 @@ namespace AZ::Render if (Scriptable_ImGui::Selectable(label.c_str(), m_attachmentId == binding.m_attachment->GetAttachmentId())) { + m_selectedPassPath = pass->GetPathName(); m_selectedPass = pass; m_attachmentId = binding.m_attachment->GetAttachmentId(); m_slotName = binding.m_name; @@ -232,9 +250,9 @@ namespace AZ::Render if (!m_showAttachments) { // Only draw the leaf pass as selectable if we are not showing attachments as its children - if (Scriptable_ImGui::Selectable(pass->GetName().GetCStr(), m_selectedPass == pass)) + if (Scriptable_ImGui::Selectable(pass->GetName().GetCStr(), m_selectedPassPath == pass->GetPathName())) { - m_selectedPass = pass; + m_selectedPassPath = pass->GetPathName(); m_attachmentId = AZ::RHI::AttachmentId{}; m_slotName = AZ::Name{}; m_selectedChanged = true; @@ -244,13 +262,13 @@ namespace AZ::Render { // Draw the pass as a tree node which has attachments as its children ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_DefaultOpen - | ((m_selectedPass == pass) ? ImGuiTreeNodeFlags_Selected : 0); + | ((m_selectedPassPath == pass->GetPathName()) ? ImGuiTreeNodeFlags_Selected : 0); bool nodeOpen = Scriptable_ImGui::TreeNodeEx(pass->GetName().GetCStr(), flags); if (ImGui::IsItemClicked()) { - m_selectedPass = pass; + m_selectedPassPath = pass->GetPathName(); m_attachmentId = AZ::RHI::AttachmentId{}; m_slotName = AZ::Name{}; m_selectedChanged = true; @@ -259,7 +277,6 @@ namespace AZ::Render if (nodeOpen) { DrawPassAttachments(pass); - Scriptable_ImGui::TreePop(); } } @@ -268,13 +285,13 @@ namespace AZ::Render { // For a ParentPasse, draw it as a tree node ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_DefaultOpen - | ((m_selectedPass == pass) ? ImGuiTreeNodeFlags_Selected : 0); + | ((m_selectedPassPath == pass->GetPathName()) ? ImGuiTreeNodeFlags_Selected : 0); bool nodeOpen = ImGui::TreeNodeEx(pass->GetName().GetCStr(), flags); if (ImGui::IsItemClicked()) { - m_selectedPass = pass; + m_selectedPassPath = pass->GetPathName(); m_attachmentId = AZ::RHI::AttachmentId{}; m_slotName = AZ::Name{}; m_selectedChanged = true; @@ -282,7 +299,10 @@ namespace AZ::Render if (nodeOpen) { - DrawPassAttachments(pass); + if (m_showAttachments) + { + DrawPassAttachments(pass); + } for (const auto& child : asParent->GetChildren()) { DrawTreeView(child.get()); @@ -296,6 +316,12 @@ namespace AZ::Render { ImGui::PopStyleColor(); } + + // set m_selectedPass if pass path matches + if (pass->GetPathName() == m_selectedPassPath) + { + m_selectedPass = pass; + } } inline void ImGuiPassTree::ReadbackCallback(const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult) @@ -364,7 +390,9 @@ namespace AZ::Render m_previewAttachment = false; m_showAttachments = false; + m_selectedPassPath = AZ::Name{}; m_selectedPass = nullptr; + m_lastSelectedPass = nullptr; m_attachmentId = AZ::RHI::AttachmentId{}; m_slotName = AZ::Name{}; m_selectedChanged = false; From 35467b63d9964f8c308c7a4c07b9373181c48b6c Mon Sep 17 00:00:00 2001 From: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> Date: Wed, 27 Oct 2021 19:31:30 +0100 Subject: [PATCH 25/77] Unit tests for Heightfield collider (#5042) Signed-off-by: John Jones-Steele --- Gems/PhysX/Code/CMakeLists.txt | 13 ++ .../MockPhysXHeightfieldProviderComponent.h | 74 ++++++ ...ditorHeightfieldColliderComponentTests.cpp | 215 ++++++++++++++++++ .../PhysX/Code/physx_editor_tests_files.cmake | 1 + Gems/PhysX/Code/physx_mocks_files.cmake | 11 + 5 files changed, 314 insertions(+) create mode 100644 Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h create mode 100644 Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp create mode 100644 Gems/PhysX/Code/physx_mocks_files.cmake diff --git a/Gems/PhysX/Code/CMakeLists.txt b/Gems/PhysX/Code/CMakeLists.txt index 1acfae3bfd..c59db45aa7 100644 --- a/Gems/PhysX/Code/CMakeLists.txt +++ b/Gems/PhysX/Code/CMakeLists.txt @@ -17,6 +17,7 @@ if(PAL_TRAIT_PHYSX_SUPPORTED) set(physx_dependency 3rdParty::PhysX) set(physx_files physx_files.cmake) set(physx_shared_files physx_shared_files.cmake) + set(physx_mock_files physx_mocks_files.cmake) set(physx_editor_files physx_editor_files.cmake) else() set(physx_files physx_unsupported_files.cmake) @@ -151,6 +152,17 @@ endif() # Tests ################################################################################ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + ly_add_target( + NAME PhysX.Mocks HEADERONLY + NAMESPACE Gem + OUTPUT_NAME PhysX.Mocks.Gem + FILES_CMAKE + physx_mocks_files.cmake + INCLUDE_DIRECTORIES + INTERFACE + Mocks + ) + ly_add_target( NAME PhysX.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} NAMESPACE Gem @@ -213,6 +225,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest AZ::AzToolsFrameworkTestCommon Gem::PhysX.Static + Gem::PhysX.Mocks Gem::PhysX.Editor.Static RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor diff --git a/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h b/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h new file mode 100644 index 0000000000..7e500881c0 --- /dev/null +++ b/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h @@ -0,0 +1,74 @@ +/* + * 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 +#include +#include +#include + +namespace UnitTest +{ + class MockPhysXHeightfieldProviderComponent + : public AZ::Component + { + public: + AZ_COMPONENT(MockPhysXHeightfieldProviderComponent, "{C5F7CCCF-FDB2-40DF-992D-CF028F4A1B59}"); + + static void Reflect([[maybe_unused]] AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1); + } + } + + void Activate() override + { + } + + void Deactivate() override + { + } + + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("PhysicsHeightfieldProviderService")); + } + + }; + + class MockPhysXHeightfieldProvider + : protected Physics::HeightfieldProviderRequestsBus::Handler + { + public: + MockPhysXHeightfieldProvider(AZ::EntityId entityId) + { + Physics::HeightfieldProviderRequestsBus::Handler::BusConnect(entityId); + } + + ~MockPhysXHeightfieldProvider() + { + Physics::HeightfieldProviderRequestsBus::Handler::BusDisconnect(); + } + + MOCK_CONST_METHOD0(GetHeightsAndMaterials, AZStd::vector()); + MOCK_CONST_METHOD0(GetHeightfieldGridSpacing, AZ::Vector2()); + MOCK_CONST_METHOD2(GetHeightfieldGridSize, void(int32_t&, int32_t&)); + MOCK_CONST_METHOD2(GetHeightfieldHeightBounds, void(float&, float&)); + MOCK_CONST_METHOD0(GetHeightfieldTransform, AZ::Transform()); + MOCK_CONST_METHOD0(GetMaterialList, AZStd::vector()); + MOCK_CONST_METHOD0(GetHeights, AZStd::vector()); + MOCK_CONST_METHOD1(UpdateHeights, AZStd::vector(const AZ::Aabb& dirtyRegion)); + MOCK_CONST_METHOD1(UpdateHeightsAndMaterials, AZStd::vector(const AZ::Aabb& dirtyRegion)); + MOCK_CONST_METHOD0(GetHeightfieldAabb, AZ::Aabb()); + }; + +} // namespace UnitTest diff --git a/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp b/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp new file mode 100644 index 0000000000..ef112d8623 --- /dev/null +++ b/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp @@ -0,0 +1,215 @@ +/* + * 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 + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using ::testing::NiceMock; +using ::testing::Return; + +namespace PhysXEditorTests +{ + AZStd::vector GetSamples() + { + AZStd::vector samples{ { 3.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, + { 2.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, + { 1.5f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, + { 1.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, + { 3.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, + { 1.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, + { 3.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, + { 0.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, + { 3.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight } }; + return samples; + } + + EntityPtr SetupHeightfieldComponent() + { + // create an editor entity with a shape collider component and a box shape component + EntityPtr editorEntity = CreateInactiveEditorEntity("HeightfieldColliderComponentEditorEntity"); + editorEntity->CreateComponent(); + editorEntity->CreateComponent(LmbrCentral::EditorAxisAlignedBoxShapeComponentTypeId); + editorEntity->CreateComponent(); + AZ::ComponentApplicationBus::Broadcast( + &AZ::ComponentApplicationRequests::RegisterComponentDescriptor, + UnitTest::MockPhysXHeightfieldProviderComponent::CreateDescriptor()); + return editorEntity; + } + + void CleanupHeightfieldComponent() + { + AZ::ComponentApplicationBus::Broadcast( + &AZ::ComponentApplicationRequests::UnregisterComponentDescriptor, + UnitTest::MockPhysXHeightfieldProviderComponent::CreateDescriptor()); + } + + void SetupMockMethods(NiceMock& mockShapeRequests) + { + ON_CALL(mockShapeRequests, GetHeightfieldTransform).WillByDefault(Return(AZ::Transform::CreateTranslation({ 1, 2, 0 }))); + ON_CALL(mockShapeRequests, GetHeightfieldGridSpacing).WillByDefault(Return(AZ::Vector2(1, 1))); + ON_CALL(mockShapeRequests, GetHeightsAndMaterials).WillByDefault(Return(GetSamples())); + ON_CALL(mockShapeRequests, GetHeightfieldGridSize) + .WillByDefault( + [](int32_t& numColumns, int32_t& numRows) + { + numColumns = 3; + numRows = 3; + }); + ON_CALL(mockShapeRequests, GetHeightfieldHeightBounds) + .WillByDefault( + [](float& x, float& y) + { + x = -3.0f; + y = 3.0f; + }); + } + + EntityPtr TestCreateActiveGameEntityFromEditorEntity(AZ::Entity* editorEntity) + { + EntityPtr gameEntity = AZStd::make_unique(); + AzToolsFramework::ToolsApplicationRequestBus::Broadcast( + &AzToolsFramework::ToolsApplicationRequests::PreExportEntity, *editorEntity, *gameEntity); + gameEntity->Init(); + return gameEntity; + } + + + TEST_F(PhysXEditorFixture, EditorHeightfieldColliderComponentDependenciesSatisfiedEntityIsValid) + { + EntityPtr entity = CreateInactiveEditorEntity("HeightfieldColliderComponentEditorEntity"); + entity->CreateComponent(); + entity->CreateComponent(LmbrCentral::EditorAxisAlignedBoxShapeComponentTypeId); + entity->CreateComponent()->CreateDescriptor(); + + // the entity should be in a valid state because the shape component and + // the Terrain Physics Collider Component requirement is satisfied. + AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails(); + EXPECT_TRUE(sortOutcome.IsSuccess()); + } + + TEST_F(PhysXEditorFixture, EditorHeightfieldColliderComponentDependenciesMissingEntityIsInvalid) + { + EntityPtr entity = CreateInactiveEditorEntity("HeightfieldColliderComponentEditorEntity"); + entity->CreateComponent(); + + // the entity should not be in a valid state because the heightfield collider component requires + // a shape component and the Terrain Physics Collider Component + AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails(); + EXPECT_FALSE(sortOutcome.IsSuccess()); + EXPECT_TRUE(sortOutcome.GetError().m_code == AZ::Entity::DependencySortResult::MissingRequiredService); + } + + TEST_F(PhysXEditorFixture, EditorHeightfieldColliderComponentMultipleHeightfieldColliderComponentsEntityIsInvalid) + { + EntityPtr entity = CreateInactiveEditorEntity("HeightfieldColliderComponentEditorEntity"); + entity->CreateComponent(); + entity->CreateComponent(LmbrCentral::EditorAxisAlignedBoxShapeComponentTypeId); + + // adding a second heightfield collider component should make the entity invalid + entity->CreateComponent(); + + AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails(); + EXPECT_FALSE(sortOutcome.IsSuccess()); + EXPECT_TRUE(sortOutcome.GetError().m_code == AZ::Entity::DependencySortResult::HasIncompatibleServices); + } + + TEST_F(PhysXEditorFixture, EditorHeightfieldColliderComponentHeightfieldColliderWithCorrectComponentsCorrectRuntimeComponents) + { + EntityPtr editorEntity = SetupHeightfieldComponent(); + NiceMock mockShapeRequests(editorEntity->GetId()); + SetupMockMethods(mockShapeRequests); + editorEntity->Activate(); + + EntityPtr gameEntity = TestCreateActiveGameEntityFromEditorEntity(editorEntity.get()); + NiceMock mockShapeRequests2(gameEntity->GetId()); + SetupMockMethods(mockShapeRequests2); + gameEntity->Activate(); + + // check that the runtime entity has the expected components + EXPECT_TRUE(gameEntity->FindComponent() != nullptr); + EXPECT_TRUE(gameEntity->FindComponent() != nullptr); + EXPECT_TRUE(gameEntity->FindComponent(LmbrCentral::AxisAlignedBoxShapeComponentTypeId) != nullptr); + + CleanupHeightfieldComponent(); + } + + TEST_F(PhysXEditorFixture, EditorHeightfieldColliderComponentHeightfieldColliderWithAABoxCorrectRuntimeGeometry) + { + EntityPtr editorEntity = SetupHeightfieldComponent(); + NiceMock mockShapeRequests(editorEntity->GetId()); + SetupMockMethods(mockShapeRequests); + editorEntity->Activate(); + + EntityPtr gameEntity = TestCreateActiveGameEntityFromEditorEntity(editorEntity.get()); + NiceMock mockShapeRequests2(gameEntity->GetId()); + SetupMockMethods(mockShapeRequests2); + gameEntity->Activate(); + + AzPhysics::SimulatedBody* staticBody = nullptr; + AzPhysics::SimulatedBodyComponentRequestsBus::EventResult( + staticBody, gameEntity->GetId(), &AzPhysics::SimulatedBodyComponentRequests::GetSimulatedBody); + const auto* pxRigidStatic = static_cast(staticBody->GetNativePointer()); + + PHYSX_SCENE_READ_LOCK(pxRigidStatic->getScene()); + + // there should be a single shape on the rigid body and it should be a heightfield + EXPECT_EQ(pxRigidStatic->getNbShapes(), 1); + + physx::PxShape* shape = nullptr; + pxRigidStatic->getShapes(&shape, 1, 0); + EXPECT_EQ(shape->getGeometryType(), physx::PxGeometryType::eHEIGHTFIELD); + + physx::PxHeightFieldGeometry heightfieldGeometry; + shape->getHeightFieldGeometry(heightfieldGeometry); + + physx::PxHeightField* heightfield = heightfieldGeometry.heightField; + + int32_t numRows{ 0 }; + int32_t numColumns{ 0 }; + Physics::HeightfieldProviderRequestsBus::Event( + gameEntity->GetId(), &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldGridSize, numColumns, numRows); + EXPECT_EQ(numColumns, heightfield->getNbColumns()); + EXPECT_EQ(numRows, heightfield->getNbRows()); + + for (int sampleRow = 0; sampleRow < numRows; ++sampleRow) + { + for (int sampleColumn = 0; sampleColumn < numColumns; ++sampleColumn) + { + float minHeightBounds{ 0.0f }; + float maxHeightBounds{ 0.0f }; + Physics::HeightfieldProviderRequestsBus::Event( + gameEntity->GetId(), &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldHeightBounds, minHeightBounds, + maxHeightBounds); + + AZStd::vector samples; + Physics::HeightfieldProviderRequestsBus::EventResult( + samples, gameEntity->GetId(), &Physics::HeightfieldProviderRequestsBus::Events::GetHeightsAndMaterials); + const float halfBounds{ (maxHeightBounds - minHeightBounds) / 2.0f }; + const float scaleFactor = (maxHeightBounds <= minHeightBounds) ? 1.0f : AZStd::numeric_limits::max() / halfBounds; + + physx::PxHeightFieldSample samplePhysX = heightfield->getSample(sampleRow, sampleColumn); + Physics::HeightMaterialPoint samplePhysics = samples[sampleRow * numColumns + sampleColumn]; + EXPECT_EQ(samplePhysX.height, azlossy_cast(samplePhysics.m_height * scaleFactor)); + } + } + CleanupHeightfieldComponent(); + } + +} // namespace PhysXEditorTests + diff --git a/Gems/PhysX/Code/physx_editor_tests_files.cmake b/Gems/PhysX/Code/physx_editor_tests_files.cmake index 36fb139514..953e2a167e 100644 --- a/Gems/PhysX/Code/physx_editor_tests_files.cmake +++ b/Gems/PhysX/Code/physx_editor_tests_files.cmake @@ -18,6 +18,7 @@ set(FILES Tests/PolygonPrismMeshUtilsTest.cpp Tests/PhysXColliderComponentModeTests.cpp Tests/ShapeColliderComponentTests.cpp + Tests/EditorHeightfieldColliderComponentTests.cpp Tests/TestColliderComponent.h Tests/SystemComponentTest.cpp Tests/RigidBodyComponentTests.cpp diff --git a/Gems/PhysX/Code/physx_mocks_files.cmake b/Gems/PhysX/Code/physx_mocks_files.cmake new file mode 100644 index 0000000000..49843eeb6f --- /dev/null +++ b/Gems/PhysX/Code/physx_mocks_files.cmake @@ -0,0 +1,11 @@ +# +# 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 + Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h +) From 5ceb9ee2144e91fe09d1514c7ed110e7f6f122fa Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 27 Oct 2021 14:24:16 -0500 Subject: [PATCH 26/77] Material component property inspector indicator changes Shows indicator icon for differences between the overrides and the active material asset, not the material type. So, the indicator will only be shown for property changes that have an effect and will be stored in the component. Signed-off-by: Guthrie Adams --- .../EditorMaterialComponentInspector.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index 9af3b41b12..bfa9f1d36f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -314,12 +314,21 @@ namespace AZ AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, propertyDefinition); + const auto& propertyIndex = + m_editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id); + propertyConfig.m_groupName = groupDisplayName; - const auto& propertyIndex = m_editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id); propertyConfig.m_showThumbnail = true; - propertyConfig.m_defaultValue = AtomToolsFramework::ConvertToEditableType(m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]); - propertyConfig.m_parentValue = AtomToolsFramework::ConvertToEditableType(m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]); - propertyConfig.m_originalValue = AtomToolsFramework::ConvertToEditableType(m_editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]); + + propertyConfig.m_defaultValue = AtomToolsFramework::ConvertToEditableType( + m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]); + + // There is no explicit parent material here. Material instance property overrides replace the values from the + // assigned material asset. Its values should be treated as parent, for comparison, in this case. + propertyConfig.m_parentValue = AtomToolsFramework::ConvertToEditableType( + m_editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]); + propertyConfig.m_originalValue = AtomToolsFramework::ConvertToEditableType( + m_editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]); group.m_properties.emplace_back(propertyConfig); } } From 46fc1a720c120455d4eaf5f212905f2e3c30095a Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 27 Oct 2021 13:04:10 -0700 Subject: [PATCH 27/77] Fixes monolithic and non-monolithic installed builds (test project builds against debug/profile non-monolithic and release monolithic) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Gems/Atom/RHI/DX12/Code/CMakeLists.txt | 3 +- .../Code/inapppurchases_files.cmake | 1 + cmake/Platform/Common/Install_common.cmake | 36 ++++++++++++------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Gems/Atom/RHI/DX12/Code/CMakeLists.txt b/Gems/Atom/RHI/DX12/Code/CMakeLists.txt index b913ad58bf..975b838ffa 100644 --- a/Gems/Atom/RHI/DX12/Code/CMakeLists.txt +++ b/Gems/Atom/RHI/DX12/Code/CMakeLists.txt @@ -107,7 +107,7 @@ ly_add_target( Gem::Atom_RHI.Reflect Gem::Atom_RHI_DX12.Reflect 3rdParty::d3dx12 - ${AFTERMATH_BUILD_DEPENDENCY} + ${AFTERMATH_BUILD_DEPENDENCY} COMPILE_DEFINITIONS PRIVATE ${USE_NSIGHT_AFTERMATH_DEFINE} @@ -128,7 +128,6 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE AZ::AzCore - Gem::Atom_RHI.Reflect Gem::Atom_RHI.Public Gem::Atom_RHI_DX12.Reflect diff --git a/Gems/InAppPurchases/Code/inapppurchases_files.cmake b/Gems/InAppPurchases/Code/inapppurchases_files.cmake index 5eab792206..2669cbf930 100644 --- a/Gems/InAppPurchases/Code/inapppurchases_files.cmake +++ b/Gems/InAppPurchases/Code/inapppurchases_files.cmake @@ -10,6 +10,7 @@ set(FILES Include/InAppPurchases/InAppPurchasesBus.h Include/InAppPurchases/InAppPurchasesInterface.h Include/InAppPurchases/InAppPurchasesResponseBus.h + Source/InAppPurchasesSystemComponent.h Source/InAppPurchasesSystemComponent.cpp Source/InAppPurchasesInterface.cpp ) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 8a06d1b584..ceab70162e 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -192,16 +192,15 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar endif() # Includes need additional processing to add the install root - if(include_directories) - foreach(include ${include_directories}) - string(GENEX_STRIP ${include} include_genex_expr) - if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions - # Make the include path relative to the source dir where the target will be declared - cmake_path(RELATIVE_PATH include BASE_DIRECTORY ${absolute_target_source_dir} OUTPUT_VARIABLE target_include) - string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${target_include}\n") - endif() - endforeach() - endif() + foreach(include IN LISTS include_directories) + string(GENEX_STRIP ${include} include_genex_expr) + if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions + # Make the include path relative to the source dir where the target will be declared + cmake_path(RELATIVE_PATH include BASE_DIRECTORY ${absolute_target_source_dir} OUTPUT_VARIABLE target_include) + list(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${target_include}") + endif() + endforeach() + list(JOIN INCLUDE_DIRECTORIES_PLACEHOLDER "\n" INCLUDE_DIRECTORIES_PLACEHOLDER) string(REPEAT " " 8 PLACEHOLDER_INDENT) get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES) @@ -217,12 +216,23 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) if(inteface_build_dependencies_props) cmake_parse_arguments(build_deps "" "" "PRIVATE;PUBLIC;INTERFACE" ${inteface_build_dependencies_props}) - foreach(build_dependency IN LISTS build_deps_INTERFACE build_deps_PUBLIC) + # Interface and public dependencies should always be exposed + set(build_deps_target ${build_deps_INTERFACE}) + if(build_deps_PUBLIC) + set(build_deps_target "${build_deps_target};${build_deps_PUBLIC}") + endif() + # Private dependencies should only be exposed if it is a static library, since in those cases, link + # dependencies are transfered to the downstream dependencies + if("${target_type}" STREQUAL "STATIC_LIBRARY") + set(build_deps_target "${build_deps_target};${build_deps_PRIVATE}") + endif() + foreach(build_dependency IN LISTS build_deps_target) # Skip wrapping produced when targets are not created in the same directory - list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${build_dependency}") + if(build_dependency) + list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${build_dependency}") + endif() endforeach() endif() - list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) list(JOIN INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) string(REPEAT " " 8 PLACEHOLDER_INDENT) From 59c898fc4853f898fc01ff6145a71bebad3caac6 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Wed, 27 Oct 2021 13:55:32 -0700 Subject: [PATCH 28/77] Fix notification queue and add gem action (#4985) (#5024) Signed-off-by: AMZN-alexpete <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Components/ToastNotification.cpp | 9 +- .../Components/ToastNotification.h | 4 +- .../Notifications/ToastNotificationsView.cpp | 34 ++++++++ .../UI/Notifications/ToastNotificationsView.h | 5 ++ .../Source/GemCatalog/GemCatalogScreen.cpp | 87 ++++++++++--------- .../Source/GemCatalog/GemCatalogScreen.h | 1 + 6 files changed, 95 insertions(+), 45 deletions(-) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp index f79f355ccb..8831bef89c 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp @@ -22,6 +22,7 @@ namespace AzQtComponents , m_closeOnClick(true) , m_ui(new Ui::ToastNotification()) , m_fadeAnimation(nullptr) + , m_configuration(toastConfiguration) { setProperty("HasNoWindowDecorations", true); @@ -80,7 +81,13 @@ namespace AzQtComponents } ToastNotification::~ToastNotification() - { + { + } + + bool ToastNotification::IsDuplicate(const ToastConfiguration& toastConfiguration) + { + return toastConfiguration.m_title == m_configuration.m_title + && toastConfiguration.m_description == m_configuration.m_description; } void ToastNotification::paintEvent(QPaintEvent* event) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h index 7f2701a803..4343f37df4 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h @@ -45,6 +45,8 @@ namespace AzQtComponents void ShowToastAtPoint(const QPoint& screenPosition, const QPointF& anchorPoint); void UpdatePosition(const QPoint& screenPosition, const QPointF& anchorPoint); + + bool IsDuplicate(const ToastConfiguration& toastConfiguration); // QDialog void showEvent(QShowEvent* showEvent) override; @@ -64,7 +66,7 @@ namespace AzQtComponents private: QPropertyAnimation* m_fadeAnimation; - + ToastConfiguration m_configuration; bool m_closeOnClick; QTimer m_lifeSpan; uint32_t m_borderRadius = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp index e039230783..a88711a9ed 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp @@ -63,6 +63,12 @@ namespace AzToolsFramework ToastId ToastNotificationsView::ShowToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration) { + // reject duplicate messages + if (m_rejectDuplicates && DuplicateNotificationInQueue(toastConfiguration)) + { + return ToastId(); + } + ToastId toastId = CreateToastNotification(toastConfiguration); m_queuedNotifications.emplace_back(toastId); @@ -70,10 +76,28 @@ namespace AzToolsFramework { DisplayQueuedNotification(); } + else if (m_queuedNotifications.size() >= m_maxQueuedNotifications) + { + // hiding the active toast will cause the next toast to be displayed + HideToastNotification(m_activeNotification); + } return toastId; } + bool ToastNotificationsView::DuplicateNotificationInQueue(const AzQtComponents::ToastConfiguration& toastConfiguration) + { + for (auto iter : m_notifications) + { + if (iter.second && iter.second->IsDuplicate(toastConfiguration)) + { + return true; + } + } + + return false; + } + ToastId ToastNotificationsView::ShowToastAtCursor(const AzQtComponents::ToastConfiguration& toastConfiguration) { ToastId toastId = CreateToastNotification(toastConfiguration); @@ -187,4 +211,14 @@ namespace AzToolsFramework { m_anchorPoint = anchorPoint; } + + void ToastNotificationsView::SetMaxQueuedNotifications(AZ::u32 maxQueuedNotifications) + { + m_maxQueuedNotifications = maxQueuedNotifications; + } + + void ToastNotificationsView::SetRejectDuplicates(bool rejectDuplicates) + { + m_rejectDuplicates = rejectDuplicates; + } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.h index e13f129467..c64ce00f4c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.h @@ -52,10 +52,13 @@ namespace AzToolsFramework void SetOffset(const QPoint& offset); void SetAnchorPoint(const QPointF& anchorPoint); + void SetMaxQueuedNotifications(AZ::u32 maxQueuedNotifications); + void SetRejectDuplicates(bool rejectDuplicates); private: ToastId CreateToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration); void DisplayQueuedNotification(); + bool DuplicateNotificationInQueue(const AzQtComponents::ToastConfiguration& toastConfiguration); QPoint GetGlobalPoint(); ToastId m_activeNotification; @@ -64,5 +67,7 @@ namespace AzToolsFramework QPoint m_offset = QPoint(10, 10); QPointF m_anchorPoint = QPointF(1, 0); + AZ::u32 m_maxQueuedNotifications = 5; + bool m_rejectDuplicates = true; }; } // AzToolsFramework diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index b3d0ab83ed..a22f41d054 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -42,7 +42,9 @@ namespace O3DE::ProjectManager m_headerWidget = new GemCatalogHeaderWidget(m_gemModel, m_proxModel, m_downloadController); vLayout->addWidget(m_headerWidget); + connect(m_gemModel, &GemModel::gemStatusChanged, this, &GemCatalogScreen::OnGemStatusChanged); connect(m_headerWidget, &GemCatalogHeaderWidget::OpenGemsRepo, this, &GemCatalogScreen::HandleOpenGemRepo); + connect(m_headerWidget, &GemCatalogHeaderWidget::AddGem, this, &GemCatalogScreen::OnAddGemClicked); QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setMargin(0); @@ -73,6 +75,7 @@ namespace O3DE::ProjectManager m_notificationsView = AZStd::make_unique(this, AZ_CRC("GemCatalogNotificationsView")); m_notificationsView->SetOffset(QPoint(10, 70)); + m_notificationsView->SetMaxQueuedNotifications(1); } void GemCatalogScreen::ReinitForProject(const QString& projectPath) @@ -94,48 +97,6 @@ namespace O3DE::ProjectManager m_headerWidget->ReinitForProject(); connect(m_gemModel, &GemModel::dataChanged, m_filterWidget, &GemFilterWidget::ResetGemStatusFilter); - connect(m_gemModel, &GemModel::gemStatusChanged, this, &GemCatalogScreen::OnGemStatusChanged); - connect( - m_headerWidget, &GemCatalogHeaderWidget::AddGem, - [&]() - { - EngineInfo engineInfo; - QString defaultPath; - - AZ::Outcome engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo(); - if (engineInfoResult.IsSuccess()) - { - engineInfo = engineInfoResult.GetValue(); - defaultPath = engineInfo.m_defaultGemsFolder; - } - - if (defaultPath.isEmpty()) - { - defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); - } - - QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Browse"), defaultPath)); - if (!directory.isEmpty()) - { - // register the gem to the o3de_manifest.json and to the project after the user confirms - // project creation/update - auto registerResult = PythonBindingsInterface::Get()->RegisterGem(directory); - if(!registerResult) - { - QMessageBox::critical(this, tr("Failed to add gem"), registerResult.GetError().c_str()); - } - else - { - m_gemsToRegisterWithProject.insert(directory); - AZ::Outcome gemInfoResult = PythonBindingsInterface::Get()->GetGemInfo(directory); - if (gemInfoResult) - { - m_gemModel->AddGem(gemInfoResult.GetValue()); - m_gemModel->UpdateGemDependencies(); - } - } - } - }); // Select the first entry after everything got correctly sized QTimer::singleShot(200, [=]{ @@ -144,6 +105,46 @@ namespace O3DE::ProjectManager }); } + void GemCatalogScreen::OnAddGemClicked() + { + EngineInfo engineInfo; + QString defaultPath; + + AZ::Outcome engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo(); + if (engineInfoResult.IsSuccess()) + { + engineInfo = engineInfoResult.GetValue(); + defaultPath = engineInfo.m_defaultGemsFolder; + } + + if (defaultPath.isEmpty()) + { + defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); + } + + QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Browse"), defaultPath)); + if (!directory.isEmpty()) + { + // register the gem to the o3de_manifest.json and to the project after the user confirms + // project creation/update + auto registerResult = PythonBindingsInterface::Get()->RegisterGem(directory); + if(!registerResult) + { + QMessageBox::critical(this, tr("Failed to add gem"), registerResult.GetError().c_str()); + } + else + { + m_gemsToRegisterWithProject.insert(directory); + AZ::Outcome gemInfoResult = PythonBindingsInterface::Get()->GetGemInfo(directory); + if (gemInfoResult) + { + m_gemModel->AddGem(gemInfoResult.GetValue()); + m_gemModel->UpdateGemDependencies(); + } + } + } + } + void GemCatalogScreen::OnGemStatusChanged(const QModelIndex& modelIndex, uint32_t numChangedDependencies) { if (m_notificationsEnabled) @@ -178,7 +179,7 @@ namespace O3DE::ProjectManager } else if (numChangedDependencies > 1) { - notification += QString("%d Gem ").arg(numChangedDependencies) + tr("dependencies"); + notification += QString("%1 Gem ").arg(numChangedDependencies) + tr("dependencies"); } notification += " " + (added ? tr("activated") : tr("deactivated")); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 8e9f31c710..1ade87af0c 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -47,6 +47,7 @@ namespace O3DE::ProjectManager public slots: void OnGemStatusChanged(const QModelIndex& modelIndex, uint32_t numChangedDependencies); + void OnAddGemClicked(); protected: void hideEvent(QHideEvent* event) override; From 8bbd8f9807f53130d271f59373f8b2c0b725967d Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Wed, 27 Oct 2021 16:01:02 -0500 Subject: [PATCH 29/77] Renamed the C++ and Python tool gem templates after review. Signed-off-by: Chris Galvan --- Templates/CMakeLists.txt | 4 ++-- .../Template/CMakeLists.txt | 0 .../Template/Code/${NameLower}_editor_files.cmake | 0 .../Code/${NameLower}_editor_shared_files.cmake | 0 .../Code/${NameLower}_editor_tests_files.cmake | 0 .../Template/Code/${NameLower}_files.cmake | 0 .../Template/Code/${NameLower}_shared_files.cmake | 0 .../Template/Code/${NameLower}_tests_files.cmake | 0 .../Template/Code/CMakeLists.txt | 0 .../Template/Code/Include/${Name}/${Name}Bus.h | 0 .../Android/${NameLower}_android_files.cmake | 0 .../Android/${NameLower}_shared_android_files.cmake | 0 .../Template/Code/Platform/Android/PAL_android.cmake | 0 .../Platform/Linux/${NameLower}_linux_files.cmake | 0 .../Linux/${NameLower}_shared_linux_files.cmake | 0 .../Template/Code/Platform/Linux/PAL_linux.cmake | 0 .../Code/Platform/Mac/${NameLower}_mac_files.cmake | 0 .../Platform/Mac/${NameLower}_shared_mac_files.cmake | 0 .../Template/Code/Platform/Mac/PAL_mac.cmake | 0 .../Windows/${NameLower}_shared_windows_files.cmake | 0 .../Windows/${NameLower}_windows_files.cmake | 0 .../Template/Code/Platform/Windows/PAL_windows.cmake | 0 .../Code/Platform/iOS/${NameLower}_ios_files.cmake | 0 .../Platform/iOS/${NameLower}_shared_ios_files.cmake | 0 .../Template/Code/Platform/iOS/PAL_ios.cmake | 0 .../Template/Code/Source/${Name}.qrc | 0 .../Template/Code/Source/${Name}EditorModule.cpp | 0 .../Code/Source/${Name}EditorSystemComponent.cpp | 0 .../Code/Source/${Name}EditorSystemComponent.h | 0 .../Template/Code/Source/${Name}Module.cpp | 0 .../Template/Code/Source/${Name}ModuleInterface.h | 0 .../Template/Code/Source/${Name}SystemComponent.cpp | 0 .../Template/Code/Source/${Name}SystemComponent.h | 0 .../Template/Code/Source/${Name}Widget.cpp | 0 .../Template/Code/Source/${Name}Widget.h | 0 .../Template/Code/Source/toolbar_icon.svg | 0 .../Template/Code/Tests/${Name}EditorTest.cpp | 0 .../Template/Code/Tests/${Name}Test.cpp | 0 .../Template/Platform/Android/android_gem.cmake | 0 .../Template/Platform/Android/android_gem.json | 0 .../Template/Platform/Linux/linux_gem.cmake | 0 .../Template/Platform/Linux/linux_gem.json | 0 .../Template/Platform/Mac/mac_gem.cmake | 0 .../Template/Platform/Mac/mac_gem.json | 0 .../Template/Platform/Windows/windows_gem.cmake | 0 .../Template/Platform/Windows/windows_gem.json | 0 .../Template/Platform/iOS/ios_gem.cmake | 0 .../Template/Platform/iOS/ios_gem.json | 0 .../{CustomTool => CppToolGem}/Template/gem.json | 0 .../{CustomTool => CppToolGem}/Template/preview.png | 0 Templates/{CustomTool => CppToolGem}/template.json | 10 +++++----- .../Template/CMakeLists.txt | 0 .../Template/Code/${NameLower}_editor_files.cmake | 0 .../Code/${NameLower}_editor_shared_files.cmake | 0 .../Code/${NameLower}_editor_tests_files.cmake | 0 .../Template/Code/CMakeLists.txt | 0 .../Template/Code/Include/${Name}/${Name}Bus.h | 0 .../Platform/Linux/${NameLower}_linux_files.cmake | 0 .../Linux/${NameLower}_shared_linux_files.cmake | 0 .../Template/Code/Platform/Linux/PAL_linux.cmake | 0 .../Code/Platform/Mac/${NameLower}_mac_files.cmake | 0 .../Platform/Mac/${NameLower}_shared_mac_files.cmake | 0 .../Template/Code/Platform/Mac/PAL_mac.cmake | 0 .../Windows/${NameLower}_shared_windows_files.cmake | 0 .../Windows/${NameLower}_windows_files.cmake | 0 .../Template/Code/Platform/Windows/PAL_windows.cmake | 0 .../Template/Code/Source/${Name}EditorModule.cpp | 0 .../Code/Source/${Name}EditorSystemComponent.cpp | 0 .../Code/Source/${Name}EditorSystemComponent.h | 0 .../Template/Code/Source/${Name}ModuleInterface.h | 0 .../Template/Code/Tests/${Name}EditorTest.cpp | 0 .../Template/Editor/Scripts/${NameLower}_dialog.py | 0 .../Template/Editor/Scripts/__init__.py | 0 .../Template/Editor/Scripts/bootstrap.py | 0 .../{PythonGem => PythonToolGem}/Template/gem.json | 0 .../Template/preview.png | 0 Templates/{PythonGem => PythonToolGem}/template.json | 12 ++++++------ engine.json | 5 +++-- 78 files changed, 16 insertions(+), 15 deletions(-) rename Templates/{CustomTool => CppToolGem}/Template/CMakeLists.txt (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/${NameLower}_editor_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/${NameLower}_editor_shared_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/${NameLower}_editor_tests_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/${NameLower}_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/${NameLower}_shared_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/${NameLower}_tests_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/CMakeLists.txt (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Include/${Name}/${Name}Bus.h (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/Android/${NameLower}_android_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/Android/${NameLower}_shared_android_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/Android/PAL_android.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/Linux/PAL_linux.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/Mac/PAL_mac.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/Windows/PAL_windows.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/iOS/${NameLower}_shared_ios_files.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Platform/iOS/PAL_ios.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Source/${Name}.qrc (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Source/${Name}EditorModule.cpp (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Source/${Name}EditorSystemComponent.cpp (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Source/${Name}EditorSystemComponent.h (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Source/${Name}Module.cpp (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Source/${Name}ModuleInterface.h (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Source/${Name}SystemComponent.cpp (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Source/${Name}SystemComponent.h (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Source/${Name}Widget.cpp (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Source/${Name}Widget.h (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Source/toolbar_icon.svg (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Tests/${Name}EditorTest.cpp (100%) rename Templates/{CustomTool => CppToolGem}/Template/Code/Tests/${Name}Test.cpp (100%) rename Templates/{CustomTool => CppToolGem}/Template/Platform/Android/android_gem.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Platform/Android/android_gem.json (100%) rename Templates/{CustomTool => CppToolGem}/Template/Platform/Linux/linux_gem.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Platform/Linux/linux_gem.json (100%) rename Templates/{CustomTool => CppToolGem}/Template/Platform/Mac/mac_gem.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Platform/Mac/mac_gem.json (100%) rename Templates/{CustomTool => CppToolGem}/Template/Platform/Windows/windows_gem.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Platform/Windows/windows_gem.json (100%) rename Templates/{CustomTool => CppToolGem}/Template/Platform/iOS/ios_gem.cmake (100%) rename Templates/{CustomTool => CppToolGem}/Template/Platform/iOS/ios_gem.json (100%) rename Templates/{CustomTool => CppToolGem}/Template/gem.json (100%) rename Templates/{CustomTool => CppToolGem}/Template/preview.png (100%) rename Templates/{CustomTool => CppToolGem}/template.json (98%) rename Templates/{PythonGem => PythonToolGem}/Template/CMakeLists.txt (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/${NameLower}_editor_files.cmake (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/${NameLower}_editor_shared_files.cmake (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/${NameLower}_editor_tests_files.cmake (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/CMakeLists.txt (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Include/${Name}/${Name}Bus.h (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Platform/Linux/PAL_linux.cmake (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Platform/Mac/PAL_mac.cmake (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Platform/Windows/PAL_windows.cmake (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Source/${Name}EditorModule.cpp (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Source/${Name}EditorSystemComponent.cpp (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Source/${Name}EditorSystemComponent.h (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Source/${Name}ModuleInterface.h (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Code/Tests/${Name}EditorTest.cpp (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Editor/Scripts/${NameLower}_dialog.py (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Editor/Scripts/__init__.py (100%) rename Templates/{PythonGem => PythonToolGem}/Template/Editor/Scripts/bootstrap.py (100%) rename Templates/{PythonGem => PythonToolGem}/Template/gem.json (100%) rename Templates/{PythonGem => PythonToolGem}/Template/preview.png (100%) rename Templates/{PythonGem => PythonToolGem}/template.json (94%) diff --git a/Templates/CMakeLists.txt b/Templates/CMakeLists.txt index 84a708989a..9735907a6a 100644 --- a/Templates/CMakeLists.txt +++ b/Templates/CMakeLists.txt @@ -9,8 +9,8 @@ ly_install_directory( DIRECTORIES AssetGem - CustomTool - PythonGem + CppToolGem + PythonToolGem DefaultGem DefaultProject MinimalProject diff --git a/Templates/CustomTool/Template/CMakeLists.txt b/Templates/CppToolGem/Template/CMakeLists.txt similarity index 100% rename from Templates/CustomTool/Template/CMakeLists.txt rename to Templates/CppToolGem/Template/CMakeLists.txt diff --git a/Templates/CustomTool/Template/Code/${NameLower}_editor_files.cmake b/Templates/CppToolGem/Template/Code/${NameLower}_editor_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/${NameLower}_editor_files.cmake rename to Templates/CppToolGem/Template/Code/${NameLower}_editor_files.cmake diff --git a/Templates/CustomTool/Template/Code/${NameLower}_editor_shared_files.cmake b/Templates/CppToolGem/Template/Code/${NameLower}_editor_shared_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/${NameLower}_editor_shared_files.cmake rename to Templates/CppToolGem/Template/Code/${NameLower}_editor_shared_files.cmake diff --git a/Templates/CustomTool/Template/Code/${NameLower}_editor_tests_files.cmake b/Templates/CppToolGem/Template/Code/${NameLower}_editor_tests_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/${NameLower}_editor_tests_files.cmake rename to Templates/CppToolGem/Template/Code/${NameLower}_editor_tests_files.cmake diff --git a/Templates/CustomTool/Template/Code/${NameLower}_files.cmake b/Templates/CppToolGem/Template/Code/${NameLower}_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/${NameLower}_files.cmake rename to Templates/CppToolGem/Template/Code/${NameLower}_files.cmake diff --git a/Templates/CustomTool/Template/Code/${NameLower}_shared_files.cmake b/Templates/CppToolGem/Template/Code/${NameLower}_shared_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/${NameLower}_shared_files.cmake rename to Templates/CppToolGem/Template/Code/${NameLower}_shared_files.cmake diff --git a/Templates/CustomTool/Template/Code/${NameLower}_tests_files.cmake b/Templates/CppToolGem/Template/Code/${NameLower}_tests_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/${NameLower}_tests_files.cmake rename to Templates/CppToolGem/Template/Code/${NameLower}_tests_files.cmake diff --git a/Templates/CustomTool/Template/Code/CMakeLists.txt b/Templates/CppToolGem/Template/Code/CMakeLists.txt similarity index 100% rename from Templates/CustomTool/Template/Code/CMakeLists.txt rename to Templates/CppToolGem/Template/Code/CMakeLists.txt diff --git a/Templates/CustomTool/Template/Code/Include/${Name}/${Name}Bus.h b/Templates/CppToolGem/Template/Code/Include/${Name}/${Name}Bus.h similarity index 100% rename from Templates/CustomTool/Template/Code/Include/${Name}/${Name}Bus.h rename to Templates/CppToolGem/Template/Code/Include/${Name}/${Name}Bus.h diff --git a/Templates/CustomTool/Template/Code/Platform/Android/${NameLower}_android_files.cmake b/Templates/CppToolGem/Template/Code/Platform/Android/${NameLower}_android_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/Android/${NameLower}_android_files.cmake rename to Templates/CppToolGem/Template/Code/Platform/Android/${NameLower}_android_files.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/Android/${NameLower}_shared_android_files.cmake b/Templates/CppToolGem/Template/Code/Platform/Android/${NameLower}_shared_android_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/Android/${NameLower}_shared_android_files.cmake rename to Templates/CppToolGem/Template/Code/Platform/Android/${NameLower}_shared_android_files.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/Android/PAL_android.cmake b/Templates/CppToolGem/Template/Code/Platform/Android/PAL_android.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/Android/PAL_android.cmake rename to Templates/CppToolGem/Template/Code/Platform/Android/PAL_android.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake b/Templates/CppToolGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake rename to Templates/CppToolGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake b/Templates/CppToolGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake rename to Templates/CppToolGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/Linux/PAL_linux.cmake b/Templates/CppToolGem/Template/Code/Platform/Linux/PAL_linux.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/Linux/PAL_linux.cmake rename to Templates/CppToolGem/Template/Code/Platform/Linux/PAL_linux.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake b/Templates/CppToolGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake rename to Templates/CppToolGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake b/Templates/CppToolGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake rename to Templates/CppToolGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/Mac/PAL_mac.cmake b/Templates/CppToolGem/Template/Code/Platform/Mac/PAL_mac.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/Mac/PAL_mac.cmake rename to Templates/CppToolGem/Template/Code/Platform/Mac/PAL_mac.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake b/Templates/CppToolGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake rename to Templates/CppToolGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake b/Templates/CppToolGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake rename to Templates/CppToolGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/Windows/PAL_windows.cmake b/Templates/CppToolGem/Template/Code/Platform/Windows/PAL_windows.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/Windows/PAL_windows.cmake rename to Templates/CppToolGem/Template/Code/Platform/Windows/PAL_windows.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake b/Templates/CppToolGem/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake rename to Templates/CppToolGem/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/iOS/${NameLower}_shared_ios_files.cmake b/Templates/CppToolGem/Template/Code/Platform/iOS/${NameLower}_shared_ios_files.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/iOS/${NameLower}_shared_ios_files.cmake rename to Templates/CppToolGem/Template/Code/Platform/iOS/${NameLower}_shared_ios_files.cmake diff --git a/Templates/CustomTool/Template/Code/Platform/iOS/PAL_ios.cmake b/Templates/CppToolGem/Template/Code/Platform/iOS/PAL_ios.cmake similarity index 100% rename from Templates/CustomTool/Template/Code/Platform/iOS/PAL_ios.cmake rename to Templates/CppToolGem/Template/Code/Platform/iOS/PAL_ios.cmake diff --git a/Templates/CustomTool/Template/Code/Source/${Name}.qrc b/Templates/CppToolGem/Template/Code/Source/${Name}.qrc similarity index 100% rename from Templates/CustomTool/Template/Code/Source/${Name}.qrc rename to Templates/CppToolGem/Template/Code/Source/${Name}.qrc diff --git a/Templates/CustomTool/Template/Code/Source/${Name}EditorModule.cpp b/Templates/CppToolGem/Template/Code/Source/${Name}EditorModule.cpp similarity index 100% rename from Templates/CustomTool/Template/Code/Source/${Name}EditorModule.cpp rename to Templates/CppToolGem/Template/Code/Source/${Name}EditorModule.cpp diff --git a/Templates/CustomTool/Template/Code/Source/${Name}EditorSystemComponent.cpp b/Templates/CppToolGem/Template/Code/Source/${Name}EditorSystemComponent.cpp similarity index 100% rename from Templates/CustomTool/Template/Code/Source/${Name}EditorSystemComponent.cpp rename to Templates/CppToolGem/Template/Code/Source/${Name}EditorSystemComponent.cpp diff --git a/Templates/CustomTool/Template/Code/Source/${Name}EditorSystemComponent.h b/Templates/CppToolGem/Template/Code/Source/${Name}EditorSystemComponent.h similarity index 100% rename from Templates/CustomTool/Template/Code/Source/${Name}EditorSystemComponent.h rename to Templates/CppToolGem/Template/Code/Source/${Name}EditorSystemComponent.h diff --git a/Templates/CustomTool/Template/Code/Source/${Name}Module.cpp b/Templates/CppToolGem/Template/Code/Source/${Name}Module.cpp similarity index 100% rename from Templates/CustomTool/Template/Code/Source/${Name}Module.cpp rename to Templates/CppToolGem/Template/Code/Source/${Name}Module.cpp diff --git a/Templates/CustomTool/Template/Code/Source/${Name}ModuleInterface.h b/Templates/CppToolGem/Template/Code/Source/${Name}ModuleInterface.h similarity index 100% rename from Templates/CustomTool/Template/Code/Source/${Name}ModuleInterface.h rename to Templates/CppToolGem/Template/Code/Source/${Name}ModuleInterface.h diff --git a/Templates/CustomTool/Template/Code/Source/${Name}SystemComponent.cpp b/Templates/CppToolGem/Template/Code/Source/${Name}SystemComponent.cpp similarity index 100% rename from Templates/CustomTool/Template/Code/Source/${Name}SystemComponent.cpp rename to Templates/CppToolGem/Template/Code/Source/${Name}SystemComponent.cpp diff --git a/Templates/CustomTool/Template/Code/Source/${Name}SystemComponent.h b/Templates/CppToolGem/Template/Code/Source/${Name}SystemComponent.h similarity index 100% rename from Templates/CustomTool/Template/Code/Source/${Name}SystemComponent.h rename to Templates/CppToolGem/Template/Code/Source/${Name}SystemComponent.h diff --git a/Templates/CustomTool/Template/Code/Source/${Name}Widget.cpp b/Templates/CppToolGem/Template/Code/Source/${Name}Widget.cpp similarity index 100% rename from Templates/CustomTool/Template/Code/Source/${Name}Widget.cpp rename to Templates/CppToolGem/Template/Code/Source/${Name}Widget.cpp diff --git a/Templates/CustomTool/Template/Code/Source/${Name}Widget.h b/Templates/CppToolGem/Template/Code/Source/${Name}Widget.h similarity index 100% rename from Templates/CustomTool/Template/Code/Source/${Name}Widget.h rename to Templates/CppToolGem/Template/Code/Source/${Name}Widget.h diff --git a/Templates/CustomTool/Template/Code/Source/toolbar_icon.svg b/Templates/CppToolGem/Template/Code/Source/toolbar_icon.svg similarity index 100% rename from Templates/CustomTool/Template/Code/Source/toolbar_icon.svg rename to Templates/CppToolGem/Template/Code/Source/toolbar_icon.svg diff --git a/Templates/CustomTool/Template/Code/Tests/${Name}EditorTest.cpp b/Templates/CppToolGem/Template/Code/Tests/${Name}EditorTest.cpp similarity index 100% rename from Templates/CustomTool/Template/Code/Tests/${Name}EditorTest.cpp rename to Templates/CppToolGem/Template/Code/Tests/${Name}EditorTest.cpp diff --git a/Templates/CustomTool/Template/Code/Tests/${Name}Test.cpp b/Templates/CppToolGem/Template/Code/Tests/${Name}Test.cpp similarity index 100% rename from Templates/CustomTool/Template/Code/Tests/${Name}Test.cpp rename to Templates/CppToolGem/Template/Code/Tests/${Name}Test.cpp diff --git a/Templates/CustomTool/Template/Platform/Android/android_gem.cmake b/Templates/CppToolGem/Template/Platform/Android/android_gem.cmake similarity index 100% rename from Templates/CustomTool/Template/Platform/Android/android_gem.cmake rename to Templates/CppToolGem/Template/Platform/Android/android_gem.cmake diff --git a/Templates/CustomTool/Template/Platform/Android/android_gem.json b/Templates/CppToolGem/Template/Platform/Android/android_gem.json similarity index 100% rename from Templates/CustomTool/Template/Platform/Android/android_gem.json rename to Templates/CppToolGem/Template/Platform/Android/android_gem.json diff --git a/Templates/CustomTool/Template/Platform/Linux/linux_gem.cmake b/Templates/CppToolGem/Template/Platform/Linux/linux_gem.cmake similarity index 100% rename from Templates/CustomTool/Template/Platform/Linux/linux_gem.cmake rename to Templates/CppToolGem/Template/Platform/Linux/linux_gem.cmake diff --git a/Templates/CustomTool/Template/Platform/Linux/linux_gem.json b/Templates/CppToolGem/Template/Platform/Linux/linux_gem.json similarity index 100% rename from Templates/CustomTool/Template/Platform/Linux/linux_gem.json rename to Templates/CppToolGem/Template/Platform/Linux/linux_gem.json diff --git a/Templates/CustomTool/Template/Platform/Mac/mac_gem.cmake b/Templates/CppToolGem/Template/Platform/Mac/mac_gem.cmake similarity index 100% rename from Templates/CustomTool/Template/Platform/Mac/mac_gem.cmake rename to Templates/CppToolGem/Template/Platform/Mac/mac_gem.cmake diff --git a/Templates/CustomTool/Template/Platform/Mac/mac_gem.json b/Templates/CppToolGem/Template/Platform/Mac/mac_gem.json similarity index 100% rename from Templates/CustomTool/Template/Platform/Mac/mac_gem.json rename to Templates/CppToolGem/Template/Platform/Mac/mac_gem.json diff --git a/Templates/CustomTool/Template/Platform/Windows/windows_gem.cmake b/Templates/CppToolGem/Template/Platform/Windows/windows_gem.cmake similarity index 100% rename from Templates/CustomTool/Template/Platform/Windows/windows_gem.cmake rename to Templates/CppToolGem/Template/Platform/Windows/windows_gem.cmake diff --git a/Templates/CustomTool/Template/Platform/Windows/windows_gem.json b/Templates/CppToolGem/Template/Platform/Windows/windows_gem.json similarity index 100% rename from Templates/CustomTool/Template/Platform/Windows/windows_gem.json rename to Templates/CppToolGem/Template/Platform/Windows/windows_gem.json diff --git a/Templates/CustomTool/Template/Platform/iOS/ios_gem.cmake b/Templates/CppToolGem/Template/Platform/iOS/ios_gem.cmake similarity index 100% rename from Templates/CustomTool/Template/Platform/iOS/ios_gem.cmake rename to Templates/CppToolGem/Template/Platform/iOS/ios_gem.cmake diff --git a/Templates/CustomTool/Template/Platform/iOS/ios_gem.json b/Templates/CppToolGem/Template/Platform/iOS/ios_gem.json similarity index 100% rename from Templates/CustomTool/Template/Platform/iOS/ios_gem.json rename to Templates/CppToolGem/Template/Platform/iOS/ios_gem.json diff --git a/Templates/CustomTool/Template/gem.json b/Templates/CppToolGem/Template/gem.json similarity index 100% rename from Templates/CustomTool/Template/gem.json rename to Templates/CppToolGem/Template/gem.json diff --git a/Templates/CustomTool/Template/preview.png b/Templates/CppToolGem/Template/preview.png similarity index 100% rename from Templates/CustomTool/Template/preview.png rename to Templates/CppToolGem/Template/preview.png diff --git a/Templates/CustomTool/template.json b/Templates/CppToolGem/template.json similarity index 98% rename from Templates/CustomTool/template.json rename to Templates/CppToolGem/template.json index e3221db106..b516dbaec3 100644 --- a/Templates/CustomTool/template.json +++ b/Templates/CppToolGem/template.json @@ -1,12 +1,12 @@ { - "template_name": "CustomTool", - "origin": "The primary repo for CustomTool goes here: i.e. http://www.mydomain.com", - "license": "What license CustomTool uses goes here: i.e. https://opensource.org/licenses/MIT", - "display_name": "CustomTool", + "template_name": "CppToolGem", + "origin": "The primary repo for CppToolGem goes here: i.e. http://www.mydomain.com", + "license": "What license CppToolGem uses goes here: i.e. https://opensource.org/licenses/MIT", + "display_name": "CppToolGem", "summary": "A gem template for a custom tool in C++ that gets registered with the Editor.", "canonical_tags": [], "user_tags": [ - "CustomTool" + "CppToolGem" ], "icon_path": "preview.png", "copyFiles": [ diff --git a/Templates/PythonGem/Template/CMakeLists.txt b/Templates/PythonToolGem/Template/CMakeLists.txt similarity index 100% rename from Templates/PythonGem/Template/CMakeLists.txt rename to Templates/PythonToolGem/Template/CMakeLists.txt diff --git a/Templates/PythonGem/Template/Code/${NameLower}_editor_files.cmake b/Templates/PythonToolGem/Template/Code/${NameLower}_editor_files.cmake similarity index 100% rename from Templates/PythonGem/Template/Code/${NameLower}_editor_files.cmake rename to Templates/PythonToolGem/Template/Code/${NameLower}_editor_files.cmake diff --git a/Templates/PythonGem/Template/Code/${NameLower}_editor_shared_files.cmake b/Templates/PythonToolGem/Template/Code/${NameLower}_editor_shared_files.cmake similarity index 100% rename from Templates/PythonGem/Template/Code/${NameLower}_editor_shared_files.cmake rename to Templates/PythonToolGem/Template/Code/${NameLower}_editor_shared_files.cmake diff --git a/Templates/PythonGem/Template/Code/${NameLower}_editor_tests_files.cmake b/Templates/PythonToolGem/Template/Code/${NameLower}_editor_tests_files.cmake similarity index 100% rename from Templates/PythonGem/Template/Code/${NameLower}_editor_tests_files.cmake rename to Templates/PythonToolGem/Template/Code/${NameLower}_editor_tests_files.cmake diff --git a/Templates/PythonGem/Template/Code/CMakeLists.txt b/Templates/PythonToolGem/Template/Code/CMakeLists.txt similarity index 100% rename from Templates/PythonGem/Template/Code/CMakeLists.txt rename to Templates/PythonToolGem/Template/Code/CMakeLists.txt diff --git a/Templates/PythonGem/Template/Code/Include/${Name}/${Name}Bus.h b/Templates/PythonToolGem/Template/Code/Include/${Name}/${Name}Bus.h similarity index 100% rename from Templates/PythonGem/Template/Code/Include/${Name}/${Name}Bus.h rename to Templates/PythonToolGem/Template/Code/Include/${Name}/${Name}Bus.h diff --git a/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake b/Templates/PythonToolGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake similarity index 100% rename from Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake rename to Templates/PythonToolGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake diff --git a/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake b/Templates/PythonToolGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake similarity index 100% rename from Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake rename to Templates/PythonToolGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake diff --git a/Templates/PythonGem/Template/Code/Platform/Linux/PAL_linux.cmake b/Templates/PythonToolGem/Template/Code/Platform/Linux/PAL_linux.cmake similarity index 100% rename from Templates/PythonGem/Template/Code/Platform/Linux/PAL_linux.cmake rename to Templates/PythonToolGem/Template/Code/Platform/Linux/PAL_linux.cmake diff --git a/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake b/Templates/PythonToolGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake similarity index 100% rename from Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake rename to Templates/PythonToolGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake diff --git a/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake b/Templates/PythonToolGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake similarity index 100% rename from Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake rename to Templates/PythonToolGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake diff --git a/Templates/PythonGem/Template/Code/Platform/Mac/PAL_mac.cmake b/Templates/PythonToolGem/Template/Code/Platform/Mac/PAL_mac.cmake similarity index 100% rename from Templates/PythonGem/Template/Code/Platform/Mac/PAL_mac.cmake rename to Templates/PythonToolGem/Template/Code/Platform/Mac/PAL_mac.cmake diff --git a/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake b/Templates/PythonToolGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake similarity index 100% rename from Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake rename to Templates/PythonToolGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake diff --git a/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake b/Templates/PythonToolGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake similarity index 100% rename from Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake rename to Templates/PythonToolGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake diff --git a/Templates/PythonGem/Template/Code/Platform/Windows/PAL_windows.cmake b/Templates/PythonToolGem/Template/Code/Platform/Windows/PAL_windows.cmake similarity index 100% rename from Templates/PythonGem/Template/Code/Platform/Windows/PAL_windows.cmake rename to Templates/PythonToolGem/Template/Code/Platform/Windows/PAL_windows.cmake diff --git a/Templates/PythonGem/Template/Code/Source/${Name}EditorModule.cpp b/Templates/PythonToolGem/Template/Code/Source/${Name}EditorModule.cpp similarity index 100% rename from Templates/PythonGem/Template/Code/Source/${Name}EditorModule.cpp rename to Templates/PythonToolGem/Template/Code/Source/${Name}EditorModule.cpp diff --git a/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.cpp b/Templates/PythonToolGem/Template/Code/Source/${Name}EditorSystemComponent.cpp similarity index 100% rename from Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.cpp rename to Templates/PythonToolGem/Template/Code/Source/${Name}EditorSystemComponent.cpp diff --git a/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.h b/Templates/PythonToolGem/Template/Code/Source/${Name}EditorSystemComponent.h similarity index 100% rename from Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.h rename to Templates/PythonToolGem/Template/Code/Source/${Name}EditorSystemComponent.h diff --git a/Templates/PythonGem/Template/Code/Source/${Name}ModuleInterface.h b/Templates/PythonToolGem/Template/Code/Source/${Name}ModuleInterface.h similarity index 100% rename from Templates/PythonGem/Template/Code/Source/${Name}ModuleInterface.h rename to Templates/PythonToolGem/Template/Code/Source/${Name}ModuleInterface.h diff --git a/Templates/PythonGem/Template/Code/Tests/${Name}EditorTest.cpp b/Templates/PythonToolGem/Template/Code/Tests/${Name}EditorTest.cpp similarity index 100% rename from Templates/PythonGem/Template/Code/Tests/${Name}EditorTest.cpp rename to Templates/PythonToolGem/Template/Code/Tests/${Name}EditorTest.cpp diff --git a/Templates/PythonGem/Template/Editor/Scripts/${NameLower}_dialog.py b/Templates/PythonToolGem/Template/Editor/Scripts/${NameLower}_dialog.py similarity index 100% rename from Templates/PythonGem/Template/Editor/Scripts/${NameLower}_dialog.py rename to Templates/PythonToolGem/Template/Editor/Scripts/${NameLower}_dialog.py diff --git a/Templates/PythonGem/Template/Editor/Scripts/__init__.py b/Templates/PythonToolGem/Template/Editor/Scripts/__init__.py similarity index 100% rename from Templates/PythonGem/Template/Editor/Scripts/__init__.py rename to Templates/PythonToolGem/Template/Editor/Scripts/__init__.py diff --git a/Templates/PythonGem/Template/Editor/Scripts/bootstrap.py b/Templates/PythonToolGem/Template/Editor/Scripts/bootstrap.py similarity index 100% rename from Templates/PythonGem/Template/Editor/Scripts/bootstrap.py rename to Templates/PythonToolGem/Template/Editor/Scripts/bootstrap.py diff --git a/Templates/PythonGem/Template/gem.json b/Templates/PythonToolGem/Template/gem.json similarity index 100% rename from Templates/PythonGem/Template/gem.json rename to Templates/PythonToolGem/Template/gem.json diff --git a/Templates/PythonGem/Template/preview.png b/Templates/PythonToolGem/Template/preview.png similarity index 100% rename from Templates/PythonGem/Template/preview.png rename to Templates/PythonToolGem/Template/preview.png diff --git a/Templates/PythonGem/template.json b/Templates/PythonToolGem/template.json similarity index 94% rename from Templates/PythonGem/template.json rename to Templates/PythonToolGem/template.json index 75be757abb..4d85373ead 100644 --- a/Templates/PythonGem/template.json +++ b/Templates/PythonToolGem/template.json @@ -1,14 +1,14 @@ { - "template_name": "PythonGem", + "template_name": "PythonToolGem", "restricted_name": "o3de", "restricted_platform_relative_path": "Templates", - "origin": "The primary repo for PythonGem goes here: i.e. http://www.mydomain.com", - "license": "What license PythonGem uses goes here: i.e. https://opensource.org/licenses/MIT", - "display_name": "PythonGem", - "summary": "A short description of PythonGem.", + "origin": "The primary repo for PythonToolGem goes here: i.e. http://www.mydomain.com", + "license": "What license PythonToolGem uses goes here: i.e. https://opensource.org/licenses/MIT", + "display_name": "PythonToolGem", + "summary": "A gem template for a custom tool in Python that gets registered with the Editor.", "canonical_tags": [], "user_tags": [ - "PythonGem" + "PythonToolGem" ], "icon_path": "preview.png", "copyFiles": [ diff --git a/engine.json b/engine.json index 14deffecb8..05ccd0abfd 100644 --- a/engine.json +++ b/engine.json @@ -92,8 +92,9 @@ "templates": [ "Templates/AssetGem", "Templates/DefaultGem", - "Templates/CustomTool", "Templates/DefaultProject", - "Templates/MinimalProject" + "Templates/CppToolGem", + "Templates/MinimalProject", + "Templates/PythonToolGem" ] } From b48073b1712c737fe3627fb9f5713859b8e5326e Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 27 Oct 2021 14:41:00 -0700 Subject: [PATCH 30/77] fixes PR comments Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/LYWrappers.cmake | 2 +- cmake/Platform/Common/Install_common.cmake | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index c617603fa3..0416d41ece 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -459,7 +459,7 @@ function(ly_delayed_target_link_libraries) endforeach() endforeach() - endif() + endif() endforeach() set_property(GLOBAL PROPERTY LY_DELAYED_LINK_TARGETS) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index ceab70162e..6d43661b99 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -212,10 +212,10 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar endif() string(REPEAT " " 12 PLACEHOLDER_INDENT) - get_property(inteface_build_dependencies_props TARGET ${TARGET_NAME} PROPERTY LY_DELAYED_LINK) + get_property(interface_build_dependencies_props TARGET ${TARGET_NAME} PROPERTY LY_DELAYED_LINK) unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) - if(inteface_build_dependencies_props) - cmake_parse_arguments(build_deps "" "" "PRIVATE;PUBLIC;INTERFACE" ${inteface_build_dependencies_props}) + if(interface_build_dependencies_props) + cmake_parse_arguments(build_deps "" "" "PRIVATE;PUBLIC;INTERFACE" ${interface_build_dependencies_props}) # Interface and public dependencies should always be exposed set(build_deps_target ${build_deps_INTERFACE}) if(build_deps_PUBLIC) @@ -309,7 +309,7 @@ set_property(TARGET ${NAME_PLACEHOLDER} ly_install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/${NAME_PLACEHOLDER}_${conf}.cmake" DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} - CONFIGURATIONS ${conf} + CONFIGURATIONS ${conf} ) endforeach() From c82f97c03ccdbb32036dcbfe71b622af34e3ed69 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 27 Oct 2021 16:59:39 -0700 Subject: [PATCH 31/77] Moves the inclusion of the platform-specific install files to the end of cmake/Install.cmake so the install wrapper functions are available Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Install.cmake | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cmake/Install.cmake b/cmake/Install.cmake index a7340c29f3..b558590b9e 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -8,11 +8,6 @@ set(LY_INSTALL_ENABLED TRUE CACHE BOOL "Indicates if the install process is enabled") -if(LY_INSTALL_ENABLED) - ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}) - include(${pal_dir}/Install_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) -endif() - #! ly_install: wrapper to install that handles common functionality # # \notes: @@ -22,6 +17,10 @@ endif() # function(ly_install) + if(NOT LY_INSTALL_ENABLED) + return() + endif() + cmake_parse_arguments(ly_install "" "COMPONENT" "" ${ARGN}) if (NOT ly_install_COMPONENT OR "${ly_install_COMPONENT}" STREQUAL "${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}") # if it is installing under the default component, we need to de-duplicate since we can have @@ -194,3 +193,8 @@ function(ly_install_run_script SCRIPT) ) endfunction() + +if(LY_INSTALL_ENABLED) + ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}) + include(${pal_dir}/Install_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) +endif() From dd0780f6ec93abc5092beda86752f5a27264ba7a Mon Sep 17 00:00:00 2001 From: greerdv Date: Thu, 28 Oct 2021 12:26:05 +0100 Subject: [PATCH 32/77] make sure joint frame rotations are editable for ragdoll setup Signed-off-by: greerdv --- .../Configuration/JointConfiguration.cpp | 68 ++++++++++++++++++- .../Configuration/JointConfiguration.h | 24 ++++++- .../CommandSystem/Source/RagdollCommands.cpp | 2 + 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.cpp index d2f74510e5..bcc71e0cf6 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.cpp @@ -10,6 +10,7 @@ #include #include +#include namespace AzPhysics { @@ -28,6 +29,71 @@ namespace AzPhysics ->Field("ChildLocalPosition", &JointConfiguration::m_childLocalPosition) ->Field("StartSimulationEnabled", &JointConfiguration::m_startSimulationEnabled) ; + + if (auto* editContext = serializeContext->GetEditContext()) + { + editContext->Class("Joint Configuration", "Joint configuration.") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_parentLocalRotation, + "Parent local rotation", "Parent joint frame relative to parent body.") + ->Attribute(AZ::Edit::Attributes::Visibility, &GetParentLocalRotationVisibility) + ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_parentLocalPosition, + "Parent local position", "Joint position relative to parent body.") + ->Attribute(AZ::Edit::Attributes::Visibility, &GetParentLocalPositionVisibility) + ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_childLocalRotation, + "Child local rotation", "Child joint frame relative to child body.") + ->Attribute(AZ::Edit::Attributes::Visibility, &GetChildLocalRotationVisibility) + ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_childLocalPosition, + "Child local position", "Joint position relative to child body.") + ->Attribute(AZ::Edit::Attributes::Visibility, &GetChildLocalPositionVisibility) + ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_startSimulationEnabled, + "Start simulation enabled", "When active, the joint will be enabled when the simulation begins.") + ->Attribute(AZ::Edit::Attributes::Visibility, &GetStartSimulationEnabledVisibility) + ; + } } } -} + + AZ::Crc32 JointConfiguration::GetPropertyVisibility(JointConfiguration::PropertyVisibility property) const + { + return (m_propertyVisibilityFlags & property) != 0 ? AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide; + } + + void JointConfiguration::SetPropertyVisibility(JointConfiguration::PropertyVisibility property, bool isVisible) + { + if (isVisible) + { + m_propertyVisibilityFlags |= property; + } + else + { + m_propertyVisibilityFlags &= ~property; + } + } + + AZ::Crc32 JointConfiguration::GetParentLocalRotationVisibility() const + { + return GetPropertyVisibility(JointConfiguration::PropertyVisibility::ParentLocalRotation); + } + + AZ::Crc32 JointConfiguration::GetParentLocalPositionVisibility() const + { + return GetPropertyVisibility(JointConfiguration::PropertyVisibility::ParentLocalPosition); + } + + AZ::Crc32 JointConfiguration::GetChildLocalRotationVisibility() const + { + return GetPropertyVisibility(JointConfiguration::PropertyVisibility::ChildLocalRotation); + } + + AZ::Crc32 JointConfiguration::GetChildLocalPositionVisibility() const + { + return GetPropertyVisibility(JointConfiguration::PropertyVisibility::ChildLocalPosition); + } + + AZ::Crc32 JointConfiguration::GetStartSimulationEnabledVisibility() const + { + return GetPropertyVisibility(JointConfiguration::PropertyVisibility::StartSimulationEnabled); + } +} // namespace AzPhysics diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.h b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.h index ff9bfb5bea..2a246692d7 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.h @@ -31,6 +31,25 @@ namespace AzPhysics JointConfiguration() = default; virtual ~JointConfiguration() = default; + // Visibility helpers for use in the Editor when reflected. + enum PropertyVisibility : AZ::u8 + { + ParentLocalRotation = 1 << 0, //!< Whether the parent local rotation is visible. + ParentLocalPosition = 1 << 1, //!< Whether the parent local position is visible. + ChildLocalRotation = 1 << 2, //!< Whether the child local rotation is visible. + ChildLocalPosition = 1 << 3, //!< Whether the child local position is visible. + StartSimulationEnabled = 1 << 4 //!< Whether the start simulation enabled setting is visible. + }; + + AZ::Crc32 GetPropertyVisibility(PropertyVisibility property) const; + void SetPropertyVisibility(PropertyVisibility property, bool isVisible); + + AZ::Crc32 GetParentLocalRotationVisibility() const; + AZ::Crc32 GetParentLocalPositionVisibility() const; + AZ::Crc32 GetChildLocalRotationVisibility() const; + AZ::Crc32 GetChildLocalPositionVisibility() const; + AZ::Crc32 GetStartSimulationEnabledVisibility() const; + // Entity/object association. void* m_customUserData = nullptr; @@ -40,8 +59,11 @@ namespace AzPhysics AZ::Quaternion m_childLocalRotation = AZ::Quaternion::CreateIdentity(); ///< Child joint frame relative to child body. AZ::Vector3 m_childLocalPosition = AZ::Vector3::CreateZero(); ///< Joint position relative to child body. bool m_startSimulationEnabled = true; - + // For debugging/tracking purposes only. AZStd::string m_debugName; + + // Default all visibility settings to invisible, since most joint configurations don't need to display these. + AZ::u8 m_propertyVisibilityFlags = 0; }; } diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/RagdollCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/RagdollCommands.cpp index e51c9ece0b..d7c7bf69e5 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/RagdollCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/RagdollCommands.cpp @@ -105,6 +105,8 @@ namespace EMotionFX *jointTypeId, parentBindRotationWorld, nodeBindRotationWorld, boneDirection, exampleRotationsLocal); AZ_Assert(jointLimitConfig, "Could not create joint limit configuration."); + jointLimitConfig->SetPropertyVisibility(AzPhysics::JointConfiguration::PropertyVisibility::ParentLocalRotation, true); + jointLimitConfig->SetPropertyVisibility(AzPhysics::JointConfiguration::PropertyVisibility::ChildLocalRotation, true); return jointLimitConfig; } } From 9b2afbc39b9fb619ba10604823027304851e4c1e Mon Sep 17 00:00:00 2001 From: greerdv Date: Thu, 28 Oct 2021 12:51:33 +0100 Subject: [PATCH 33/77] fix explicit qualification of member function addresses Signed-off-by: greerdv --- .../Physics/Configuration/JointConfiguration.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.cpp index bcc71e0cf6..0a0e1bb8e3 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.cpp @@ -37,19 +37,19 @@ namespace AzPhysics ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_parentLocalRotation, "Parent local rotation", "Parent joint frame relative to parent body.") - ->Attribute(AZ::Edit::Attributes::Visibility, &GetParentLocalRotationVisibility) + ->Attribute(AZ::Edit::Attributes::Visibility, &JointConfiguration::GetParentLocalRotationVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_parentLocalPosition, "Parent local position", "Joint position relative to parent body.") - ->Attribute(AZ::Edit::Attributes::Visibility, &GetParentLocalPositionVisibility) + ->Attribute(AZ::Edit::Attributes::Visibility, &JointConfiguration::GetParentLocalPositionVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_childLocalRotation, "Child local rotation", "Child joint frame relative to child body.") - ->Attribute(AZ::Edit::Attributes::Visibility, &GetChildLocalRotationVisibility) + ->Attribute(AZ::Edit::Attributes::Visibility, &JointConfiguration::GetChildLocalRotationVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_childLocalPosition, "Child local position", "Joint position relative to child body.") - ->Attribute(AZ::Edit::Attributes::Visibility, &GetChildLocalPositionVisibility) + ->Attribute(AZ::Edit::Attributes::Visibility, &JointConfiguration::GetChildLocalPositionVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_startSimulationEnabled, "Start simulation enabled", "When active, the joint will be enabled when the simulation begins.") - ->Attribute(AZ::Edit::Attributes::Visibility, &GetStartSimulationEnabledVisibility) + ->Attribute(AZ::Edit::Attributes::Visibility, &JointConfiguration::GetStartSimulationEnabledVisibility) ; } } From a661189ea9d9318939f5ea2daca9ec54bfed2f4a Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Thu, 28 Oct 2021 10:53:57 -0500 Subject: [PATCH 34/77] Fix for rendering artifacts on height map update. (#5066) * Fix for rendering artifacts on height map update. This was being caused by not always lining up update aabbs with the query resolution correctly. In the future the float -> integer aabb calculations should be abstracted away. Some of this is done in the detail material ID work, but doesn't exist in the stabilization branch so we can circle around to it later. Signed-off-by: Ken Pruiksma * PR review updates - fixing cast, making constexpr for bytes per pixel. Signed-off-by: Ken Pruiksma --- .../TerrainFeatureProcessor.cpp | 91 +++++++++++-------- .../TerrainRenderer/TerrainFeatureProcessor.h | 4 - 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp index e6aed28897..1b13d3bb98 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp @@ -155,9 +155,11 @@ namespace Terrain const AZ::Transform transform = AZ::Transform::CreateTranslation(worldBounds.GetCenter()); - AZ::Vector2 queryResolution = AZ::Vector2(1.0f); + AZ::Vector2 queryResolution2D = AZ::Vector2(1.0f); AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( - queryResolution, &AzFramework::Terrain::TerrainDataRequests::GetTerrainHeightQueryResolution); + queryResolution2D, &AzFramework::Terrain::TerrainDataRequests::GetTerrainHeightQueryResolution); + // Currently query resolution is multidimensional but the rendering system only supports this changing in one dimension. + float queryResolution = queryResolution2D.GetX(); // Sectors need to be rebuilt if the world bounds change in the x/y, or the sample spacing changes. m_areaData.m_rebuildSectors = m_areaData.m_rebuildSectors || @@ -165,16 +167,11 @@ namespace Terrain m_areaData.m_terrainBounds.GetMin().GetY() != worldBounds.GetMin().GetY() || m_areaData.m_terrainBounds.GetMax().GetX() != worldBounds.GetMax().GetX() || m_areaData.m_terrainBounds.GetMax().GetY() != worldBounds.GetMax().GetY() || - m_areaData.m_sampleSpacing != queryResolution.GetX(); + m_areaData.m_sampleSpacing != queryResolution; m_areaData.m_transform = transform; m_areaData.m_terrainBounds = worldBounds; - m_areaData.m_heightmapImageWidth = aznumeric_cast(worldBounds.GetXExtent() / queryResolution.GetX()); - m_areaData.m_heightmapImageHeight = aznumeric_cast(worldBounds.GetYExtent() / queryResolution.GetY()); - m_areaData.m_updateWidth = aznumeric_cast(m_dirtyRegion.GetXExtent() / queryResolution.GetX()); - m_areaData.m_updateHeight = aznumeric_cast(m_dirtyRegion.GetYExtent() / queryResolution.GetY()); - // Currently query resolution is multidimensional but the rendering system only supports this changing in one dimension. - m_areaData.m_sampleSpacing = queryResolution.GetX(); + m_areaData.m_sampleSpacing = queryResolution; m_areaData.m_heightmapUpdated = true; } @@ -261,31 +258,42 @@ namespace Terrain void TerrainFeatureProcessor::UpdateTerrainData() { static const AZ::Name TerrainHeightmapName = AZ::Name(TerrainHeightmapChars); - - uint32_t width = m_areaData.m_updateWidth; - uint32_t height = m_areaData.m_updateHeight; - const AZ::Aabb& worldBounds = m_areaData.m_terrainBounds; + const float queryResolution = m_areaData.m_sampleSpacing; + const AZ::Aabb& worldBounds = m_areaData.m_terrainBounds; - const AZ::RHI::Size worldSize = AZ::RHI::Size(m_areaData.m_heightmapImageWidth, m_areaData.m_heightmapImageHeight, 1); + int32_t heightmapImageXStart = aznumeric_cast(AZStd::ceilf(worldBounds.GetMin().GetX() / queryResolution)); + int32_t heightmapImageXEnd = aznumeric_cast(AZStd::floorf(worldBounds.GetMax().GetX() / queryResolution)) + 1; + int32_t heightmapImageYStart = aznumeric_cast(AZStd::ceilf(worldBounds.GetMin().GetY() / queryResolution)); + int32_t heightmapImageYEnd = aznumeric_cast(AZStd::floorf(worldBounds.GetMax().GetY() / queryResolution)) + 1; + uint32_t heightmapImageWidth = heightmapImageXEnd - heightmapImageXStart; + uint32_t heightmapImageHeight = heightmapImageYEnd - heightmapImageYStart; - if (!m_areaData.m_heightmapImage || m_areaData.m_heightmapImage->GetDescriptor().m_size != worldSize) + const AZ::RHI::Size heightmapSize = AZ::RHI::Size(heightmapImageWidth, heightmapImageHeight, 1); + + if (!m_areaData.m_heightmapImage || m_areaData.m_heightmapImage->GetDescriptor().m_size != heightmapSize) { - // World size changed, so the whole world needs updating. - width = worldSize.m_width; - height = worldSize.m_height; - m_dirtyRegion = worldBounds; - const AZ::Data::Instance imagePool = AZ::RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool(); AZ::RHI::ImageDescriptor imageDescriptor = AZ::RHI::ImageDescriptor::Create2D( - AZ::RHI::ImageBindFlags::ShaderRead, width, height, AZ::RHI::Format::R16_UNORM + AZ::RHI::ImageBindFlags::ShaderRead, heightmapSize.m_width, heightmapSize.m_height, AZ::RHI::Format::R16_UNORM ); + m_areaData.m_heightmapImage = AZ::RPI::AttachmentImage::Create(*imagePool.get(), imageDescriptor, TerrainHeightmapName, nullptr, nullptr); AZ_Error(TerrainFPName, m_areaData.m_heightmapImage, "Failed to initialize the heightmap image!"); + + // World size changed, so the whole height map needs updating. + m_dirtyRegion = worldBounds; } + + int32_t xStart = aznumeric_cast(AZStd::ceilf(m_dirtyRegion.GetMin().GetX() / queryResolution)); + int32_t xEnd = aznumeric_cast(AZStd::floorf(m_dirtyRegion.GetMax().GetX() / queryResolution)) + 1; + int32_t yStart = aznumeric_cast(AZStd::ceilf(m_dirtyRegion.GetMin().GetY() / queryResolution)); + int32_t yEnd = aznumeric_cast(AZStd::floorf(m_dirtyRegion.GetMax().GetY() / queryResolution)) + 1; + uint32_t updateWidth = xEnd - xStart; + uint32_t updateHeight = yEnd - yStart; AZStd::vector pixels; - pixels.reserve(width * height); + pixels.reserve(updateWidth * updateHeight); { // Block other threads from accessing the surface data bus while we are in GetHeightFromFloats (which may call into the SurfaceData bus). @@ -297,18 +305,17 @@ namespace Terrain auto& surfaceDataContext = SurfaceData::SurfaceDataSystemRequestBus::GetOrCreateContext(false); typename SurfaceData::SurfaceDataSystemRequestBus::Context::DispatchLockGuard scopeLock(surfaceDataContext.m_contextMutex); - for (uint32_t y = 0; y < height; y++) + for (int32_t y = yStart; y < yEnd; y++) { - for (uint32_t x = 0; x < width; x++) + for (int32_t x = xStart; x < xEnd; x++) { bool terrainExists = true; float terrainHeight = 0.0f; + float xPos = x * queryResolution; + float yPos = y * queryResolution; AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( terrainHeight, &AzFramework::Terrain::TerrainDataRequests::GetHeightFromFloats, - (x * queryResolution) + m_dirtyRegion.GetMin().GetX(), - (y * queryResolution) + m_dirtyRegion.GetMin().GetY(), - AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT, - &terrainExists); + xPos, yPos, AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT, &terrainExists); const float clampedHeight = AZ::GetClamp((terrainHeight - worldBounds.GetMin().GetZ()) / worldBounds.GetExtents().GetZ(), 0.0f, 1.0f); const float expandedHeight = AZStd::roundf(clampedHeight * AZStd::numeric_limits::max()); @@ -321,16 +328,18 @@ namespace Terrain if (m_areaData.m_heightmapImage) { - const float left = (m_dirtyRegion.GetMin().GetX() - worldBounds.GetMin().GetX()) / queryResolution; - const float top = (m_dirtyRegion.GetMin().GetY() - worldBounds.GetMin().GetY()) / queryResolution; + constexpr uint32_t BytesPerPixel = sizeof(uint16_t); + const float left = xStart - (worldBounds.GetMin().GetX() / queryResolution); + const float top = yStart - (worldBounds.GetMin().GetY() / queryResolution); + AZ::RHI::ImageUpdateRequest imageUpdateRequest; imageUpdateRequest.m_imageSubresourcePixelOffset.m_left = aznumeric_cast(left); imageUpdateRequest.m_imageSubresourcePixelOffset.m_top = aznumeric_cast(top); - imageUpdateRequest.m_sourceSubresourceLayout.m_bytesPerRow = width * sizeof(uint16_t); - imageUpdateRequest.m_sourceSubresourceLayout.m_bytesPerImage = width * height * sizeof(uint16_t); - imageUpdateRequest.m_sourceSubresourceLayout.m_rowCount = height; - imageUpdateRequest.m_sourceSubresourceLayout.m_size.m_width = width; - imageUpdateRequest.m_sourceSubresourceLayout.m_size.m_height = height; + imageUpdateRequest.m_sourceSubresourceLayout.m_bytesPerRow = updateWidth * BytesPerPixel; + imageUpdateRequest.m_sourceSubresourceLayout.m_bytesPerImage = updateWidth * updateHeight * BytesPerPixel; + imageUpdateRequest.m_sourceSubresourceLayout.m_rowCount = updateHeight; + imageUpdateRequest.m_sourceSubresourceLayout.m_size.m_width = updateWidth; + imageUpdateRequest.m_sourceSubresourceLayout.m_size.m_height = updateHeight; imageUpdateRequest.m_sourceSubresourceLayout.m_size.m_depth = 1; imageUpdateRequest.m_sourceData = pixels.data(); imageUpdateRequest.m_image = m_areaData.m_heightmapImage->GetRHIImage(); @@ -492,6 +501,12 @@ namespace Terrain m_areaData.m_heightmapUpdated = false; m_areaData.m_macroMaterialsUpdated = false; + AZStd::array uvStep = + { + 1.0f / aznumeric_cast(m_areaData.m_terrainBounds.GetXExtent() / m_areaData.m_sampleSpacing), + 1.0f / aznumeric_cast(m_areaData.m_terrainBounds.GetYExtent() / m_areaData.m_sampleSpacing), + }; + for (SectorData& sectorData : m_sectorData) { ShaderTerrainData terrainDataForSrg; @@ -509,11 +524,7 @@ namespace Terrain ((yPatch + GridMeters) - terrainBounds.GetMin().GetY()) / terrainBounds.GetYExtent() }; - terrainDataForSrg.m_uvStep = - { - 1.0f / m_areaData.m_heightmapImageWidth, - 1.0f / m_areaData.m_heightmapImageHeight, - }; + terrainDataForSrg.m_uvStep = uvStep; AZ::Transform transform = m_areaData.m_transform; transform.SetTranslation(xPatch, yPatch, m_areaData.m_transform.GetTranslation().GetZ()); diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h index f82fd8ecb0..91e3ce9a5c 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h @@ -169,10 +169,6 @@ namespace Terrain AZ::Transform m_transform{ AZ::Transform::CreateIdentity() }; AZ::Aabb m_terrainBounds{ AZ::Aabb::CreateNull() }; AZ::Data::Instance m_heightmapImage; - uint32_t m_heightmapImageWidth{ 0 }; - uint32_t m_heightmapImageHeight{ 0 }; - uint32_t m_updateWidth{ 0 }; - uint32_t m_updateHeight{ 0 }; float m_sampleSpacing{ 0.0f }; bool m_heightmapUpdated{ true }; bool m_macroMaterialsUpdated{ true }; From 67f90a9b37d9a402ed896a4acd7704dcc7a9f64b Mon Sep 17 00:00:00 2001 From: Tommy Walton <82672795+amzn-tommy@users.noreply.github.com> Date: Thu, 28 Oct 2021 10:22:20 -0700 Subject: [PATCH 35/77] Add missing dependencies to pass builder (#4884) * Adding shaders and attimage files as runtime depenencies for pass files, so that they are included in asset bundles. Also using the correct job key for attimage files. Signed-off-by: Tommy Walton * Use a reference to avoid a copy Signed-off-by: Tommy Walton * Bumping the AnyAsset builder version Signed-off-by: Tommy Walton * Revert "Bumping the AnyAsset builder version" This reverts commit 778798ae9cdd93ebe93248b3113e4cfb7609020d. Signed-off-by: Tommy Walton --- .../Source/RPI.Builders/Pass/PassBuilder.cpp | 58 ++++++++++++++++--- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp index d5e243c687..6a0b10633e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp @@ -10,8 +10,8 @@ #include #include - #include +#include #include #include @@ -33,11 +33,27 @@ namespace AZ static const char* PassAssetExtension = "pass"; } + namespace PassBuilderNamespace + { + enum PassDependencies + { + Shader, + AttachmentImage, + Count + }; + + static const AZStd::tuple DependencyExtensionJobKeyTable[PassDependencies::Count] = + { + {".shader", "Shader Asset"}, + {".attimage", "Any Asset Builder"} + }; + } + void PassBuilder::RegisterBuilder() { AssetBuilderSDK::AssetBuilderDesc builder; builder.m_name = PassBuilderJobKey; - builder.m_version = 13; // antonmic: making .pass files declare dependency on shaders they reference + builder.m_version = 14; // making .pass files emit product dependencies for the shaders they reference so they are picked up by the asset bundler builder.m_busId = azrtti_typeid(); builder.m_createJobFunction = AZStd::bind(&PassBuilder::CreateJobs, this, AZStd::placeholders::_1, AZStd::placeholders::_2); builder.m_processJobFunction = AZStd::bind(&PassBuilder::ProcessJob, this, AZStd::placeholders::_1, AZStd::placeholders::_2); @@ -104,8 +120,27 @@ namespace AZ } } + bool SetJobKeyForExtension(const AZStd::string& filePath, FindPassReferenceAssetParams& params) + { + AZStd::string extension; + StringFunc::Path::GetExtension(filePath.c_str(), extension); + for (const auto& [dependencyExtension, jobKey] : PassBuilderNamespace::DependencyExtensionJobKeyTable) + { + if (extension == dependencyExtension) + { + params.jobKey = jobKey; + return true; + } + } + + AZ_Error(PassBuilderName, false, "PassBuilder found a dependency with extension '%s', but does not know the corresponding job key. Add the job key for that extension to SetJobKeyForExtension in PassBuilder.cpp", extension.c_str()); + params.jobKey = "Unknown"; + return false; + } + // Helper function to find all assetId's and object references - bool FindReferencedAssets(FindPassReferenceAssetParams& params, AssetBuilderSDK::JobDescriptor* job) + bool FindReferencedAssets( + FindPassReferenceAssetParams& params, AssetBuilderSDK::JobDescriptor* job, AZStd::vector* productDependencies) { SerializeContext::ErrorHandler errorLogger; errorLogger.Reset(); @@ -129,8 +164,8 @@ namespace AZ if (job != nullptr) // Create Job Phase { params.dependencySourceFile = path; - bool dependencyAddedSuccessfully = AddDependency(params, job); - success = dependencyAddedSuccessfully && success; + success &= SetJobKeyForExtension(path, params); + success &= AddDependency(params, job); } else // Process Job Phase { @@ -139,6 +174,9 @@ namespace AZ if (assetIdOutcome) { assetReference->m_assetId = assetIdOutcome.GetValue(); + productDependencies->push_back( + AssetBuilderSDK::ProductDependency{assetReference->m_assetId, AZ::Data::ProductDependencyInfo::CreateFlags(Data::AssetLoadBehavior::NoLoad)} + ); } else { @@ -223,9 +261,9 @@ namespace AZ params.passAssetSourceFile = request.m_sourceFile; params.passAssetUuid = passAssetUuid; params.serializeContext = serializeContext; - params.jobKey = "Shader Asset"; + params.jobKey = "Unknown"; - if (!FindReferencedAssets(params, &job)) + if (!FindReferencedAssets(params, &job, nullptr)) { return; } @@ -287,9 +325,10 @@ namespace AZ params.passAssetSourceFile = request.m_sourceFile; params.passAssetUuid = passAssetUuid; params.serializeContext = serializeContext; - params.jobKey = "Shader Asset"; + params.jobKey = "Unknown"; - if (!FindReferencedAssets(params, nullptr)) + AZStd::vector productDependencies; + if (!FindReferencedAssets(params, nullptr, &productDependencies)) { return; } @@ -313,6 +352,7 @@ namespace AZ // --- Save output product(s) to response --- AssetBuilderSDK::JobProduct jobProduct(destPath, PassAsset::RTTI_Type(), 0); + jobProduct.m_dependencies = productDependencies; jobProduct.m_dependenciesHandled = true; response.m_outputProducts.push_back(jobProduct); response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success; From e288ae47b479882ca89969b514c3a0ef3f3c33ac Mon Sep 17 00:00:00 2001 From: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> Date: Thu, 28 Oct 2021 19:36:39 +0100 Subject: [PATCH 36/77] Fix for using too large values on Terrain World (#5091) Signed-off-by: John Jones-Steele --- .../Code/Source/Components/TerrainWorldComponent.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.cpp index d8b7308ef7..bd65cf6abc 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.cpp @@ -32,16 +32,22 @@ namespace Terrain AZ::EditContext* edit = serialize->GetEditContext(); if (edit) { - edit->Class( - "Terrain World Component", "Data required for the terrain system to run") + edit->Class("Terrain World Component", "Data required for the terrain system to run") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector({ AZ_CRC_CE("Level") })) ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_worldMin, "World Bounds (Min)", "") + // Temporary constraint until the rest of the Terrain system is updated to support larger worlds. + ->Attribute(AZ::Edit::Attributes::Min, -2048.0f) + ->Attribute(AZ::Edit::Attributes::Max, 2048.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_worldMax, "World Bounds (Max)", "") - ->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_heightQueryResolution, "Height Query Resolution (m)", "") + // Temporary constraint until the rest of the Terrain system is updated to support larger worlds. + ->Attribute(AZ::Edit::Attributes::Min, -2048.0f) + ->Attribute(AZ::Edit::Attributes::Max, 2048.0f) + ->DataElement( + AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_heightQueryResolution, "Height Query Resolution (m)", "") ; } } From b9147c60a063ce3c4fda5b6807899b2994605d65 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 28 Oct 2021 13:45:19 -0500 Subject: [PATCH 37/77] Added the generated cmake_dependencies.*.setreg files to engine.pak (#5073) * Copied the generated cmake_dependencies.*.setreg file to the Cache directory Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed the platform name from the bootstrap.game.*.setreg Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzCore/Component/ComponentApplication.cpp | 5 ---- .../Settings/SettingsRegistryMergeUtils.cpp | 14 ++++++++--- .../Application/GameApplication.cpp | 2 +- .../SettingsRegistryBuilder.cpp | 14 +++++++---- cmake/Projects.cmake | 25 +++++++++++++++++-- 5 files changed, 43 insertions(+), 17 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index dabf02e260..df8db79db0 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -215,11 +215,6 @@ namespace AZ m_oldProjectPath = newProjectPath; // Merge the project.json file into settings registry under ProjectSettingsRootKey path. - AZ::IO::FixedMaxPath projectMetadataFile{ AZ::SettingsRegistryMergeUtils::FindEngineRoot(m_registry) / newProjectPath }; - projectMetadataFile /= "project.json"; - m_registry.MergeSettingsFile(projectMetadataFile.Native(), - AZ::SettingsRegistryInterface::Format::JsonMergePatch, AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey); - // Update all the runtime file paths based on the new "project_path" value. AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(m_registry); } diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 36f66312d8..5458a3fadf 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -634,12 +634,18 @@ namespace AZ::SettingsRegistryMergeUtils } // Project name - if it was set via merging project.json use that value, otherwise use the project path's folder name. - auto projectNameKey = - AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey) + constexpr auto projectNameKey = + FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey) + "/project_name"; - AZ::SettingsRegistryInterface::FixedValueString projectName; - if (!registry.Get(projectName, projectNameKey)) + // Read the project name from the project.json file if it exists + if (AZ::IO::FixedMaxPath projectJsonPath = normalizedProjectPath / "project.json"; + AZ::IO::SystemFile::Exists(projectJsonPath.c_str())) + { + registry.MergeSettingsFile(projectJsonPath.Native(), + AZ::SettingsRegistryInterface::Format::JsonMergePatch, AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey); + } + if (FixedValueString projectName; !registry.Get(projectName, projectNameKey)) { projectName = path.Filename().Native(); registry.Set(projectNameKey, projectName); diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp index 0cce93d751..6957844452 100644 --- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp +++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp @@ -82,7 +82,7 @@ namespace AzGameFramework // Used the lowercase the platform name since the bootstrap.game...setreg is being loaded // from the asset cache root where all the files are in lowercased from regardless of the filesystem case-sensitivity - static constexpr char filename[] = "bootstrap.game." AZ_BUILD_CONFIGURATION_TYPE "." AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER ".setreg"; + static constexpr char filename[] = "bootstrap.game." AZ_BUILD_CONFIGURATION_TYPE ".setreg"; AZ::IO::FixedMaxPath cacheRootPath; if (registry.Get(cacheRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) diff --git a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp index c65ab24aed..6f15fa5ea2 100644 --- a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp +++ b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp @@ -259,6 +259,11 @@ namespace AssetProcessor scratchBuffer.reserve(512 * 1024); // Reserve 512kb to avoid repeatedly resizing the buffer; AZStd::fixed_vector platformCodes; AzFramework::PlatformHelper::AppendPlatformCodeNames(platformCodes, request.m_platformInfo.m_identifier); + AZ_Assert(platformCodes.size() <= 1, "A one-to-one mapping of asset type platform identifier" + " to platform codename is required in the SettingsRegistryBuilder." + " The bootstrap.game is now only produced per build configuration and doesn't take into account" + " different platforms names"); + const AZStd::string& assetPlatformIdentifier = request.m_jobDescription.GetPlatformIdentifier(); // Determines the suffix that will be used for the launcher based on processing server vs non-server assets const char* launcherType = assetPlatformIdentifier != AzFramework::PlatformHelper::GetPlatformName(AzFramework::PlatformId::SERVER) @@ -293,9 +298,10 @@ namespace AssetProcessor outputBuffer.Reserve(512 * 1024); // Reserve 512kb to avoid repeatedly resizing the buffer; SettingsExporter exporter(outputBuffer, excludes); - for (AZStd::string_view platform : platformCodes) + if (!platformCodes.empty()) { - AZ::u32 productSubID = static_cast(AZStd::hash{}(platform)); // Deliberately ignoring half the bits. + AZStd::string_view platform = platformCodes.front(); + constexpr AZ::u32 productSubID = 0; for (size_t i = 0; i < AZStd::size(specializations); ++i) { const AZ::SettingsRegistryInterface::Specializations& specialization = specializations[i]; @@ -337,7 +343,7 @@ namespace AssetProcessor // The purpose of this section is to copy the Gem's SourcePaths from the Global Settings Registry // the local SettingsRegistry. The reason this is needed is so that the call to // `MergeSettingsToRegistry_GemRegistries` below is able to locate each gem's "/Registry" folder - // that will be merged into the bootstrap.game...setreg file + // that will be merged into the bootstrap.game..setreg file // This is used by the GameLauncher applications to read from a single merged .setreg file // containing the settings needed to run a game/simulation without have access to the source code base registry AZStd::vector gemInfos; @@ -408,8 +414,6 @@ namespace AssetProcessor } outputPath += specialization.GetSpecialization(0); // Append configuration - outputPath += '.'; - outputPath += platform; outputPath += ".setreg"; AZ::IO::SystemFile file; diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index c09fe0fc6f..34ef3efd9b 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -150,22 +150,43 @@ foreach(project ${LY_PROJECTS}) # Get project name o3de_read_json_key(project_name ${full_directory_path}/project.json "project_name") + # The cmake tar command has a bit of a flaw + # Any paths within the archive files it creates are relative to the current working directory. + # That means with the setup of: + # cwd = "/Cache/pc" + # project product assets = "/Cache/pc/*" + # cmake dependency registry files = "/build/bin/Release/Registry/*" + # Running the tar command would result in the assets being placed in the to layout + # correctly, but the registry files + # engine.pak/ + # ../...build/bin/Release/Registry/cmake_dependencies.*.setreg -> Not correct + # project.json -> Correct + # Generate pak for project in release installs cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE install_base_runtime_output_directory) set(install_engine_pak_template [=[ if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$") set(install_output_folder "${CMAKE_INSTALL_PREFIX}/@install_base_runtime_output_directory@/@PAL_PLATFORM_NAME@/${CMAKE_INSTALL_CONFIG_NAME}/@LY_BUILD_PERMUTATION@") set(install_pak_output_folder "${install_output_folder}/Cache/@LY_ASSET_DEPLOY_ASSET_TYPE@") + set(runtime_output_directory_RELEASE @CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE@) if(NOT DEFINED LY_ASSET_DEPLOY_ASSET_TYPE) set(LY_ASSET_DEPLOY_ASSET_TYPE @LY_ASSET_DEPLOY_ASSET_TYPE@) endif() message(STATUS "Generating ${install_pak_output_folder}/engine.pak from @full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") file(MAKE_DIRECTORY "${install_pak_output_folder}") cmake_path(SET cache_product_path "@full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") + # Copy the generated cmake_dependencies.*.setreg files for loading gems in non-monolithic to the cache + file(GLOB gem_source_paths_setreg "${runtime_output_directory_RELEASE}/Registry/*.setreg") + # The MergeSettingsToRegistry_TargetBuildDependencyRegistry function looks for lowercase "registry" + # So make sure the to copy it to a lowercase path, so that it works on non-case sensitive filesystems + file(MAKE_DIRECTORY "${cache_product_path}/registry") + file(COPY ${gem_source_paths_setreg} DESTINATION "${cache_product_path}/registry") + file(GLOB product_assets "${cache_product_path}/*") - if(product_assets) + list(APPEND pak_artifacts ${product_assets}) + if(pak_artifacts) execute_process( - COMMAND ${CMAKE_COMMAND} -E tar "cf" "${install_pak_output_folder}/engine.pak" --format=zip -- ${product_assets} + COMMAND ${CMAKE_COMMAND} -E tar "cf" "${install_pak_output_folder}/engine.pak" --format=zip -- ${pak_artifacts} WORKING_DIRECTORY "${cache_product_path}" RESULT_VARIABLE archive_creation_result ) From b71e307de57724260e014c100a71ee437ca9d0aa Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 28 Oct 2021 00:15:11 -0500 Subject: [PATCH 38/77] Fix issue setting enum values on material component from script Replaced get and set functions with explicit types with templates Added special case handling for setting enum values as strings or numbers from script Signed-off-by: Guthrie Adams --- .../Source/Material/MaterialAssignment.cpp | 53 +++-- .../Material/MaterialComponentBus.h | 59 ++---- .../Material/MaterialComponentController.cpp | 191 ++---------------- .../Material/MaterialComponentController.h | 25 --- 4 files changed, 77 insertions(+), 251 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index c79ceb39ba..e81e46a749 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -139,32 +139,59 @@ namespace AZ { for (const auto& propertyPair : m_propertyOverrides) { - if (!propertyPair.second.empty()) + auto value = propertyPair.second; + if (!value.empty()) { bool wasRenamed = false; Name newName; - RPI::MaterialPropertyIndex materialPropertyIndex = m_materialInstance->FindPropertyIndex(propertyPair.first, &wasRenamed, &newName); + RPI::MaterialPropertyIndex materialPropertyIndex = + m_materialInstance->FindPropertyIndex(propertyPair.first, &wasRenamed, &newName); - // FindPropertyIndex will have already reported a message about what the old and new names are. Here we just add some extra info to help the user resolve it. - AZ_Warning("MaterialAssignment", !wasRenamed, + // FindPropertyIndex will have already reported a message about what the old and new names are. Here we just add + // some extra info to help the user resolve it. + AZ_Warning( + "MaterialAssignment", !wasRenamed, "Consider running \"Apply Automatic Property Updates\" to use the latest property names.", - propertyPair.first.GetCStr(), - newName.GetCStr()); + propertyPair.first.GetCStr(), newName.GetCStr()); if (wasRenamed && m_propertyOverrides.find(newName) != m_propertyOverrides.end()) { materialPropertyIndex.Reset(); - - AZ_Warning("MaterialAssignment", false, - "Material property '%s' has been renamed to '%s', and a property override exists for both. The one with the old name will be ignored.", - propertyPair.first.GetCStr(), - newName.GetCStr()); + + AZ_Warning( + "MaterialAssignment", false, + "Material property '%s' has been renamed to '%s', and a property override exists for both. The one with " + "the old name will be ignored.", + propertyPair.first.GetCStr(), newName.GetCStr()); } if (!materialPropertyIndex.IsNull()) { - m_materialInstance->SetPropertyValue( - materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second)); + const auto propertyDescriptor = + m_materialInstance->GetMaterialPropertiesLayout()->GetPropertyDescriptor(materialPropertyIndex); + + // Special case handling for enum values that need to be converted from numbers or strings + if (propertyDescriptor->GetDataType() == AZ::RPI::MaterialPropertyDataType::Enum) + { + if (value.is()) + { + value = propertyDescriptor->GetEnumValue(AZStd::any_cast(value)); + } + else if (value.is()) + { + value = propertyDescriptor->GetEnumValue(AZ::Name(AZStd::any_cast(value))); + } + else if (value.is()) + { + value = aznumeric_cast(AZStd::any_cast(value)); + } + else if (value.is()) + { + value = aznumeric_cast(AZStd::any_cast(value)); + } + } + + m_materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(value)); } } } 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 293080367d..d8d0c2dbc3 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h @@ -60,52 +60,8 @@ namespace AZ virtual void ClearMaterialOverride(const MaterialAssignmentId& materialAssignmentId) = 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 AZStd::string& propertyName) = 0; //! Clear property overrides for a specific material assignment @@ -122,6 +78,21 @@ namespace AZ const MaterialAssignmentId& materialAssignmentId, const AZ::RPI::MaterialModelUvOverrideMap& modelUvOverrides) = 0; //! Get Model UV overrides for a specific material assignment virtual AZ::RPI::MaterialModelUvOverrideMap GetModelUvOverrides(const MaterialAssignmentId& materialAssignmentId) const = 0; + + //! Set material property override value with a specific type + template + void SetPropertyOverrideT(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const T& value) + { + SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value)); + } + + //! Get material property override value with a specific type + template + T GetPropertyOverrideT(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const + { + const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName); + return !value.empty() && value.is() ? AZStd::any_cast(value) : T{}; + } }; using MaterialComponentRequestBus = EBus; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 07082a87d5..2e13b13b09 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -54,29 +54,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("SetPropertyOverrideBool", &MaterialComponentRequestBus::Events::SetPropertyOverrideT) + ->Event("SetPropertyOverrideInt32", &MaterialComponentRequestBus::Events::SetPropertyOverrideT) + ->Event("SetPropertyOverrideUInt32", &MaterialComponentRequestBus::Events::SetPropertyOverrideT) + ->Event("SetPropertyOverrideFloat", &MaterialComponentRequestBus::Events::SetPropertyOverrideT) + ->Event("SetPropertyOverrideVector2", &MaterialComponentRequestBus::Events::SetPropertyOverrideT) + ->Event("SetPropertyOverrideVector3", &MaterialComponentRequestBus::Events::SetPropertyOverrideT) + ->Event("SetPropertyOverrideVector4", &MaterialComponentRequestBus::Events::SetPropertyOverrideT) + ->Event("SetPropertyOverrideColor", &MaterialComponentRequestBus::Events::SetPropertyOverrideT) + ->Event("SetPropertyOverrideImage", &MaterialComponentRequestBus::Events::SetPropertyOverrideT) + ->Event("SetPropertyOverrideString", &MaterialComponentRequestBus::Events::SetPropertyOverrideT) + ->Event("SetPropertyOverrideEnum", &MaterialComponentRequestBus::Events::SetPropertyOverrideT) ->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("GetPropertyOverrideBool", &MaterialComponentRequestBus::Events::GetPropertyOverrideT) + ->Event("GetPropertyOverrideInt32", &MaterialComponentRequestBus::Events::GetPropertyOverrideT) + ->Event("GetPropertyOverrideUInt32", &MaterialComponentRequestBus::Events::GetPropertyOverrideT) + ->Event("GetPropertyOverrideFloat", &MaterialComponentRequestBus::Events::GetPropertyOverrideT) + ->Event("GetPropertyOverrideVector2", &MaterialComponentRequestBus::Events::GetPropertyOverrideT) + ->Event("GetPropertyOverrideVector3", &MaterialComponentRequestBus::Events::GetPropertyOverrideT) + ->Event("GetPropertyOverrideVector4", &MaterialComponentRequestBus::Events::GetPropertyOverrideT) + ->Event("GetPropertyOverrideColor", &MaterialComponentRequestBus::Events::GetPropertyOverrideT) + ->Event("GetPropertyOverrideImage", &MaterialComponentRequestBus::Events::GetPropertyOverrideT) + ->Event("GetPropertyOverrideString", &MaterialComponentRequestBus::Events::GetPropertyOverrideT) + ->Event("GetPropertyOverrideEnum", &MaterialComponentRequestBus::Events::GetPropertyOverrideT) ->Event("ClearPropertyOverride", &MaterialComponentRequestBus::Events::ClearPropertyOverride) ->Event("ClearPropertyOverrides", &MaterialComponentRequestBus::Events::ClearPropertyOverrides) ->Event("ClearAllPropertyOverrides", &MaterialComponentRequestBus::Events::ClearAllPropertyOverrides) @@ -499,76 +499,6 @@ namespace AZ QueuePropertyChanges(materialAssignmentId); } - 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); @@ -586,83 +516,6 @@ namespace AZ return propertyIt->second; } - 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); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h index ec542c377c..74b1cfda4d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h @@ -65,33 +65,8 @@ namespace AZ void SetMaterialOverride(const MaterialAssignmentId& materialAssignmentId, const AZ::Data::AssetId& materialAssetId) override; AZ::Data::AssetId GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const override; void ClearMaterialOverride(const MaterialAssignmentId& materialAssignmentId) 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; From 1f4967b1682f538e4d5bfe503cab53afa816fbcc Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 28 Oct 2021 11:30:58 -0500 Subject: [PATCH 39/77] extending conversions from script to other numeric types Signed-off-by: Guthrie Adams --- .../Feature/Material/MaterialAssignment.h | 5 ++ .../Source/Material/MaterialAssignment.cpp | 80 +++++++++++++------ 2 files changed, 61 insertions(+), 24 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h index 40555bae00..2a094dc0c9 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h @@ -78,5 +78,10 @@ namespace AZ //! Find an assignment id corresponding to the lod and label substring filters MaterialAssignmentId FindMaterialAssignmentIdInModel( const Data::Instance& model, const MaterialAssignmentLodIndex lodFilter, const AZStd::string& labelFilter); + + // Special case handling to convert script values to suported types + AZ::RPI::MaterialPropertyValue ConvertMaterialPropertyValueFromScript( + const AZ::RPI::MaterialPropertyDescriptor* propertyDescriptor, const AZStd::any& value); + } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index e81e46a749..d99ce211bf 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -139,8 +139,7 @@ namespace AZ { for (const auto& propertyPair : m_propertyOverrides) { - auto value = propertyPair.second; - if (!value.empty()) + if (!propertyPair.second.empty()) { bool wasRenamed = false; Name newName; @@ -170,28 +169,8 @@ namespace AZ const auto propertyDescriptor = m_materialInstance->GetMaterialPropertiesLayout()->GetPropertyDescriptor(materialPropertyIndex); - // Special case handling for enum values that need to be converted from numbers or strings - if (propertyDescriptor->GetDataType() == AZ::RPI::MaterialPropertyDataType::Enum) - { - if (value.is()) - { - value = propertyDescriptor->GetEnumValue(AZStd::any_cast(value)); - } - else if (value.is()) - { - value = propertyDescriptor->GetEnumValue(AZ::Name(AZStd::any_cast(value))); - } - else if (value.is()) - { - value = aznumeric_cast(AZStd::any_cast(value)); - } - else if (value.is()) - { - value = aznumeric_cast(AZStd::any_cast(value)); - } - } - - m_materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(value)); + m_materialInstance->SetPropertyValue( + materialPropertyIndex, ConvertMaterialPropertyValueFromScript(propertyDescriptor, propertyPair.second)); } } } @@ -311,5 +290,58 @@ namespace AZ return MaterialAssignmentId(); } + + template + AZ::RPI::MaterialPropertyValue ConvertMaterialPropertyValueNumericType(const AZStd::any& value) + { + if (value.is()) + { + return aznumeric_cast(AZStd::any_cast(value)); + } + if (value.is()) + { + return aznumeric_cast(AZStd::any_cast(value)); + } + if (value.is()) + { + return aznumeric_cast(AZStd::any_cast(value)); + } + if (value.is()) + { + return aznumeric_cast(AZStd::any_cast(value)); + } + + return AZ::RPI::MaterialPropertyValue::FromAny(value); + } + + AZ::RPI::MaterialPropertyValue ConvertMaterialPropertyValueFromScript( + const AZ::RPI::MaterialPropertyDescriptor* propertyDescriptor, const AZStd::any& value) + { + switch (propertyDescriptor->GetDataType()) + { + case AZ::RPI::MaterialPropertyDataType::Enum: + if (value.is()) + { + return propertyDescriptor->GetEnumValue(AZStd::any_cast(value)); + } + if (value.is()) + { + return propertyDescriptor->GetEnumValue(AZ::Name(AZStd::any_cast(value))); + } + return ConvertMaterialPropertyValueNumericType(value); + case AZ::RPI::MaterialPropertyDataType::Int: + return ConvertMaterialPropertyValueNumericType(value); + case AZ::RPI::MaterialPropertyDataType::UInt: + return ConvertMaterialPropertyValueNumericType(value); + case AZ::RPI::MaterialPropertyDataType::Float: + return ConvertMaterialPropertyValueNumericType(value); + case AZ::RPI::MaterialPropertyDataType::Bool: + return ConvertMaterialPropertyValueNumericType(value); + default: + break; + } + + return AZ::RPI::MaterialPropertyValue::FromAny(value); + } } // namespace Render } // namespace AZ From 5de24437abf441318ec7ca55e51db9ca4129e861 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 28 Oct 2021 13:51:48 -0500 Subject: [PATCH 40/77] fixed comment Signed-off-by: Guthrie Adams --- .../Code/Include/Atom/Feature/Material/MaterialAssignment.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h index 2a094dc0c9..21d9ec1bba 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h @@ -79,7 +79,7 @@ namespace AZ MaterialAssignmentId FindMaterialAssignmentIdInModel( const Data::Instance& model, const MaterialAssignmentLodIndex lodFilter, const AZStd::string& labelFilter); - // Special case handling to convert script values to suported types + //! Special case handling to convert script values to supported types AZ::RPI::MaterialPropertyValue ConvertMaterialPropertyValueFromScript( const AZ::RPI::MaterialPropertyDescriptor* propertyDescriptor, const AZStd::any& value); From e5729fbefe03287f6a968427b90e400d8a9e8697 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 27 Oct 2021 17:32:43 -0500 Subject: [PATCH 41/77] =?UTF-8?q?Fix=20clearing=20material=20component=20d?= =?UTF-8?q?efault=20material=20not=20clearing=20materials=20or=20updating?= =?UTF-8?q?=20preview=20=E2=80=A2=20Changed=20thumbnail=20property=20contr?= =?UTF-8?q?ol=20to=20track=20asset=20key=20even=20if=20image=20is=20overri?= =?UTF-8?q?dden=20so=20that=20it=20will=20be=20restored=20if=20the=20image?= =?UTF-8?q?=20is=20cleared.=20=E2=80=A2=20Changed=20property=20asset=20con?= =?UTF-8?q?trol=20to=20disable=20the=20thumbnail=20image=20by=20default=20?= =?UTF-8?q?whenever=20the=20attribute=20is=20applied.=20It=20will=20only?= =?UTF-8?q?=20enable=20the=20thumbnail=20image=20if=20the=20pixmap=20is=20?= =?UTF-8?q?valid.=20=E2=80=A2=20Changed=20the=20material=20component=20con?= =?UTF-8?q?troller=20to=20always=20use=20an=20empty=20material=20assignmen?= =?UTF-8?q?t=20map=20on=20deactivation=20so=20that=20no=20persistent=20mat?= =?UTF-8?q?erials=20are=20reapplied.=20=E2=80=A2=20Changed=20the=20materia?= =?UTF-8?q?l=20component=20controller=20to=20immediately=20send=20a=20noti?= =?UTF-8?q?fication=20that=20materials=20have=20updated=20if=20no=20materi?= =?UTF-8?q?als=20were=20queued=20for=20load=20but=20the=20configuration=20?= =?UTF-8?q?contained=20pre=20created=20or=20persistent=20material=20instan?= =?UTF-8?q?ces.=20This=20mainly=20affects=20the=20material=20editor=20beca?= =?UTF-8?q?use=20it=20manages=20its=20own=20material=20instances.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guthrie Adams --- .../UI/PropertyEditor/PropertyAssetCtrl.cpp | 14 +++++++++++--- .../UI/PropertyEditor/ThumbnailPropertyCtrl.cpp | 13 +++---------- .../Material/MaterialComponentController.cpp | 12 ++++++++++-- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp index 7f3b9e61fd..24b2c7466e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp @@ -1387,7 +1387,10 @@ namespace AzToolsFramework QDataStream stream(&pixmapBytes, QIODevice::ReadOnly); QPixmap pixmap; stream >> pixmap; - GUI->SetBrowseButtonIcon(pixmap); + if (!pixmap.isNull()) + { + GUI->SetBrowseButtonIcon(pixmap); + } } } } @@ -1417,6 +1420,8 @@ namespace AzToolsFramework } else if (attrib == AZ_CRC_CE("ThumbnailIcon")) { + GUI->SetCustomThumbnailEnabled(false); + AZStd::string iconPath; if (attrValue->Read(iconPath) && !iconPath.empty()) { @@ -1434,8 +1439,11 @@ namespace AzToolsFramework QDataStream stream(&pixmapBytes, QIODevice::ReadOnly); QPixmap pixmap; stream >> pixmap; - GUI->SetCustomThumbnailEnabled(true); - GUI->SetCustomThumbnailPixmap(pixmap); + if (!pixmap.isNull()) + { + GUI->SetCustomThumbnailEnabled(true); + GUI->SetCustomThumbnailPixmap(pixmap); + } } } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp index d8ddee6b76..0bbb898196 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp @@ -67,16 +67,9 @@ namespace AzToolsFramework void ThumbnailPropertyCtrl::SetThumbnailKey(Thumbnailer::SharedThumbnailKey key, const char* contextName) { - if (m_customThumbnailEnabled) - { - ClearThumbnail(); - } - else - { - m_key = key; - m_thumbnail->SetThumbnailKey(m_key, contextName); - m_thumbnailEnlarged->SetThumbnailKey(m_key, contextName); - } + m_key = key; + m_thumbnail->SetThumbnailKey(m_key, contextName); + m_thumbnailEnlarged->SetThumbnailKey(m_key, contextName); UpdateVisibility(); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 07082a87d5..ed6904b4ef 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -121,8 +121,13 @@ namespace AZ MaterialComponentRequestBus::Handler::BusDisconnect(); MaterialReceiverNotificationBus::Handler::BusDisconnect(); TickBus::Handler::BusDisconnect(); + ReleaseMaterials(); + // Sending notification to wipe any previously assigned material overrides + MaterialComponentNotificationBus::Event( + m_entityId, &MaterialComponentNotifications::OnMaterialsUpdated, MaterialAssignmentMap()); + m_queuedMaterialUpdateNotification = false; m_entityId = AZ::EntityId(AZ::EntityId::InvalidEntityId); } @@ -221,6 +226,11 @@ namespace AZ if (!anyQueued) { ReleaseMaterials(); + + // If no other materials were loaded, the notification must still be sent in case there are externally managed material + // instances in the configuration + MaterialComponentNotificationBus::Event( + m_entityId, &MaterialComponentNotifications::OnMaterialsUpdated, m_configuration.m_materials); } } @@ -268,8 +278,6 @@ namespace AZ { materialPair.second.Release(); } - - MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsUpdated, m_configuration.m_materials); } MaterialAssignmentMap MaterialComponentController::GetOriginalMaterialAssignments() const From b6d634c3ed8a431bf5a7be45e9b13a1a6e84f446 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu, 28 Oct 2021 14:37:51 -0500 Subject: [PATCH 42/77] Print all captured messages in Assert Absorber used by FingerprintTest to help debug crash (#5096) Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../Tools/AssetProcessor/native/unittests/UnitTestRunner.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h b/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h index c281b3050a..0c4357f84a 100644 --- a/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h +++ b/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h @@ -21,6 +21,7 @@ #endif #include +#include //! These macros can be used for checking your unit tests, //! you can check AssetScannerUnitTest.cpp for usage @@ -155,6 +156,7 @@ namespace UnitTestUtils bool OnPreWarning([[maybe_unused]] const char* window, [[maybe_unused]] const char* fileName, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* message) override { + UnitTest::ColoredPrintf(UnitTest::COLOR_YELLOW, message); ++m_numWarningsAbsorbed; if (m_debugMessages) { @@ -165,6 +167,7 @@ namespace UnitTestUtils bool OnPreAssert([[maybe_unused]] const char* fileName, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* message) override { + UnitTest::ColoredPrintf(UnitTest::COLOR_YELLOW, message); ++m_numAssertsAbsorbed; if (m_debugMessages) { @@ -175,6 +178,7 @@ namespace UnitTestUtils bool OnPreError([[maybe_unused]] const char* window, [[maybe_unused]] const char* fileName, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* message) override { + UnitTest::ColoredPrintf(UnitTest::COLOR_YELLOW, message); ++m_numErrorsAbsorbed; if (m_debugMessages) { @@ -183,8 +187,9 @@ namespace UnitTestUtils return true; // I handled this, do not forward it } - bool OnPrintf(const char* /*window*/, const char* /*message*/) override + bool OnPrintf(const char* /*window*/, const char* message) override { + UnitTest::ColoredPrintf(UnitTest::COLOR_YELLOW, message); ++m_numMessagesAbsorbed; return true; } From f350ba3042b216369748935800628118b835ca81 Mon Sep 17 00:00:00 2001 From: Tommy Walton <82672795+amzn-tommy@users.noreply.github.com> Date: Thu, 28 Oct 2021 12:49:33 -0700 Subject: [PATCH 43/77] Modify the AssetBundler to correctly identify the Gems that are enabled in the current active project (#5072) * Modify the AssetBundler to correctly identify the Gems that are enabled in the current active project Signed-off-by: Tommy Walton * Removed unnecessary if() statement and updated the comment. Signed-off-by: Tommy Walton * Disabling gem loading in the asset bundler tests, just like the asset bundler itself. Signed-off-by: Tommy Walton --- Code/Tools/AssetBundler/CMakeLists.txt | 8 ++++++++ .../AssetBundler/source/utils/applicationManager.cpp | 7 ++++++- Code/Tools/AssetBundler/tests/applicationManagerTests.cpp | 6 +++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Code/Tools/AssetBundler/CMakeLists.txt b/Code/Tools/AssetBundler/CMakeLists.txt index d613b35ce5..dcc62595c9 100644 --- a/Code/Tools/AssetBundler/CMakeLists.txt +++ b/Code/Tools/AssetBundler/CMakeLists.txt @@ -47,6 +47,10 @@ ly_add_target( AZ::AssetBundlerBatch.Static ) +# Adds a specialized .setreg to identify gems enabled in the active project. +# This associates the AssetBundlerBatch target with the .Builders gem variants. +ly_set_gem_variant_to_load(TARGETS AssetBundlerBatch VARIANTS Builders) + # AssetBundler - Qt GUI Application ly_add_target( NAME AssetBundler ${PAL_TRAIT_BUILD_ASSETBUNDLER_APPLICATION_TYPE} @@ -73,6 +77,10 @@ ly_add_target( ${additional_dependencies} ) +# Adds a specialized .setreg to identify gems enabled in the active project. +# This associates the AssetBundler target with the .Builders gem variants. +ly_set_gem_variant_to_load(TARGETS AssetBundler VARIANTS Builders) + if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_add_target( diff --git a/Code/Tools/AssetBundler/source/utils/applicationManager.cpp b/Code/Tools/AssetBundler/source/utils/applicationManager.cpp index 0742035c1a..0388570fdd 100644 --- a/Code/Tools/AssetBundler/source/utils/applicationManager.cpp +++ b/Code/Tools/AssetBundler/source/utils/applicationManager.cpp @@ -54,7 +54,12 @@ namespace AssetBundler bool ApplicationManager::Init() { AZ::Debug::TraceMessageBus::Handler::BusConnect(); - Start(AzFramework::Application::Descriptor()); + + ComponentApplication::StartupParameters startupParameters; + // The AssetBundler does not need to load gems + startupParameters.m_loadDynamicModules = false; + Start(AzFramework::Application::Descriptor(), startupParameters); + AZ::SerializeContext* context; EBUS_EVENT_RESULT(context, AZ::ComponentApplicationBus, GetSerializeContext); AZ_Assert(context, "No serialize context"); diff --git a/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp b/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp index 35d3a5da1f..0d915dcc49 100644 --- a/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp +++ b/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp @@ -71,7 +71,11 @@ namespace AssetBundler m_data->m_applicationManager.reset(aznew MockApplicationManagerTest(0, 0)); - m_data->m_applicationManager->Start(AzFramework::Application::Descriptor()); + + AZ::ComponentApplication::StartupParameters startupParameters; + // The AssetBundler does not need to load gems + startupParameters.m_loadDynamicModules = false; + m_data->m_applicationManager->Start(AzFramework::Application::Descriptor(), startupParameters); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash From 00a49fa251121eeb13d28a5ff3cc466392ed3ad9 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Thu, 28 Oct 2021 12:53:54 -0700 Subject: [PATCH 44/77] Use source model data instead of filtered (#5071) Signed-off-by: AMZN-alexpete <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Source/GemCatalog/GemCatalogScreen.cpp | 12 +++++++++--- .../Source/GemCatalog/GemCatalogScreen.h | 2 +- .../ProjectManager/Source/GemCatalog/GemModel.cpp | 14 +++++++++----- .../ProjectManager/Source/GemCatalog/GemModel.h | 4 ++-- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index a22f41d054..35ea67bdff 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -145,10 +145,11 @@ namespace O3DE::ProjectManager } } - void GemCatalogScreen::OnGemStatusChanged(const QModelIndex& modelIndex, uint32_t numChangedDependencies) + void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies) { if (m_notificationsEnabled) { + QModelIndex modelIndex = m_gemModel->FindIndexByNameString(gemName); bool added = GemModel::IsAdded(modelIndex); bool dependency = GemModel::IsAddedDependency(modelIndex); @@ -233,7 +234,11 @@ namespace O3DE::ProjectManager const QVector allRepoGemInfos = allRepoGemInfosResult.GetValue(); for (const GemInfo& gemInfo : allRepoGemInfos) { - m_gemModel->AddGem(gemInfo); + // do not add gems that have already been downloaded + if (!m_gemModel->FindIndexByNameString(gemInfo.m_name).isValid()) + { + m_gemModel->AddGem(gemInfo); + } } } else @@ -257,7 +262,8 @@ namespace O3DE::ProjectManager GemModel::SetWasPreviouslyAdded(*m_gemModel, modelIndex, true); GemModel::SetIsAdded(*m_gemModel, modelIndex, true); } - else + // ${Name} is a special name used in templates and is not really an error + else if (enabledGemName != "${Name}") { AZ_Warning("ProjectManager::GemCatalog", false, "Cannot find entry for gem with name '%s'. The CMake target name probably does not match the specified name in the gem.json.", diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 1ade87af0c..1b34019d1a 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -46,7 +46,7 @@ namespace O3DE::ProjectManager DownloadController* GetDownloadController() const { return m_downloadController; } public slots: - void OnGemStatusChanged(const QModelIndex& modelIndex, uint32_t numChangedDependencies); + void OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies); void OnAddGemClicked(); protected: diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index acdef483ae..90eaaf0628 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -276,9 +276,11 @@ namespace O3DE::ProjectManager void GemModel::SetIsAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded) { + // get the gemName first, because the modelIndex data change after adding because of filters + QString gemName = modelIndex.data(RoleName).toString(); model.setData(modelIndex, isAdded, RoleIsAdded); - UpdateDependencies(model, modelIndex); + UpdateDependencies(model, gemName, isAdded); } bool GemModel::HasDependentGems(const QModelIndex& modelIndex) const @@ -294,15 +296,17 @@ namespace O3DE::ProjectManager return false; } - void GemModel::UpdateDependencies(QAbstractItemModel& model, const QModelIndex& modelIndex) + void GemModel::UpdateDependencies(QAbstractItemModel& model, const QString& gemName, bool isAdded) { GemModel* gemModel = GetSourceModel(&model); AZ_Assert(gemModel, "Failed to obtain GemModel"); + QModelIndex modelIndex = gemModel->FindIndexByNameString(gemName); + QVector dependencies = gemModel->GatherGemDependencies(modelIndex); uint32_t numChangedDependencies = 0; - if (IsAdded(modelIndex)) + if (isAdded) { for (const QModelIndex& dependency : dependencies) { @@ -324,7 +328,7 @@ namespace O3DE::ProjectManager bool hasDependentGems = gemModel->HasDependentGems(modelIndex); if (IsAddedDependency(modelIndex) != hasDependentGems) { - SetIsAddedDependency(model, modelIndex, hasDependentGems); + SetIsAddedDependency(*gemModel, modelIndex, hasDependentGems); } for (const QModelIndex& dependency : dependencies) @@ -343,7 +347,7 @@ namespace O3DE::ProjectManager } } - gemModel->emit gemStatusChanged(modelIndex, numChangedDependencies); + gemModel->emit gemStatusChanged(gemName, numChangedDependencies); } void GemModel::SetIsAddedDependency(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index 938543eb39..35231cc105 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -64,7 +64,7 @@ namespace O3DE::ProjectManager static bool NeedsToBeAdded(const QModelIndex& modelIndex, bool includeDependencies = false); static bool NeedsToBeRemoved(const QModelIndex& modelIndex, bool includeDependencies = false); static bool HasRequirement(const QModelIndex& modelIndex); - static void UpdateDependencies(QAbstractItemModel& model, const QModelIndex& modelIndex); + static void UpdateDependencies(QAbstractItemModel& model, const QString& gemName, bool isAdded); static void SetDownloadStatus(QAbstractItemModel& model, const QModelIndex& modelIndex, GemInfo::DownloadStatus status); bool DoGemsToBeAddedHaveRequirements() const; @@ -78,7 +78,7 @@ namespace O3DE::ProjectManager int TotalAddedGems(bool includeDependencies = false) const; signals: - void gemStatusChanged(const QModelIndex& modelIndex, uint32_t numChangedDependencies); + void gemStatusChanged(const QString& gemName, uint32_t numChangedDependencies); private: void FindGemDisplayNamesByNameStrings(QStringList& inOutGemNames); From b8ced0d461f07eb34bba1f543bbea81e51d5d7b9 Mon Sep 17 00:00:00 2001 From: Shirang Jia Date: Thu, 28 Oct 2021 13:31:33 -0700 Subject: [PATCH 45/77] Fix AP log path on S3 (#5068) Signed-off-by: shiranj --- scripts/build/Jenkins/Jenkinsfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index f5e5edcf66..35f6f9a81c 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -449,7 +449,7 @@ def UploadAPLogs(Map options, String branchName, String jobName, String workspac } def command = "${pythonPath} -u ${s3UploadScriptPath} --base_dir ${apLogsPath} " + "--file_regex \".*\" --bucket ${env.AP_LOGS_S3_BUCKET} " + - "--search_subdirectories True --key_prefix ${env.JOB_NAME}/${branchName}/${env.BUILD_NUMBER}/${jobName}" + + "--search_subdirectories True --key_prefix ${env.JENKINS_JOB_NAME}/${branchName}/${env.BUILD_NUMBER}/${jobName} " + "--extra-args {\"ACL\": \"bucket-owner-full-control\"}" palSh(command, "Uploading AP logs for job ${jobName} for branch ${branchName}", false) } @@ -806,6 +806,7 @@ try { platform.value.build_types.each { build_job -> if (IsJobEnabled(branchName, build_job, pipelineName, platform.key)) { // User can filter jobs, jobs are tagged by pipeline def envVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, build_job.value.PIPELINE_ENV ?: EMPTY_JSON, pipelineName) + envVars['JENKINS_JOB_NAME'] = env.JOB_NAME // Save original Jenkins job name to JENKINS_JOB_NAME envVars['JOB_NAME'] = "${branchName}_${platform.key}_${build_job.key}" // backwards compatibility, some scripts rely on this someBuildHappened = true From 7536073df0b362c785aa4459f087f88636c28c60 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Thu, 28 Oct 2021 13:36:48 -0700 Subject: [PATCH 46/77] remove and unused import Signed-off-by: Scott Murray --- .../Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py index a81864f379..efef4c0a43 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py @@ -70,8 +70,6 @@ def AtomEditorComponents_postfx_layer_AddedToEntity(): :return: None """ - import os - import azlmbr.legacy.general as general from editor_python_test_tools.editor_entity_utils import EditorEntity From 86270339d8967de8c983cd4ab96982f347652d0f Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Thu, 28 Oct 2021 16:17:38 -0500 Subject: [PATCH 47/77] Added terrain surface data notifications (#5067) * Fix notifications for surface data changes. Separated the notifications from the surface component and the height component to add a reason to a RefreshArea request. This makes it possible to distinguish between surface changes and height changes and provide the appropriate OnTerrainDataChanged flags. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Reworked to use a changeMask instead of separate calls. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * PR Feedback Judicious use of "using" to reduce a bunch of bulky namespaces. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> --- Gems/Terrain/Code/Mocks/Terrain/MockTerrain.h | 3 +- .../TerrainHeightGradientListComponent.cpp | 8 +++-- .../TerrainLayerSpawnerComponent.cpp | 8 ++++- .../TerrainSurfaceGradientListComponent.cpp | 4 ++- .../Source/TerrainSystem/TerrainSystem.cpp | 36 ++++++++++++++----- .../Code/Source/TerrainSystem/TerrainSystem.h | 4 ++- .../Source/TerrainSystem/TerrainSystemBus.h | 2 +- Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp | 4 +-- .../Tests/TerrainHeightGradientListTests.cpp | 2 +- 9 files changed, 52 insertions(+), 19 deletions(-) diff --git a/Gems/Terrain/Code/Mocks/Terrain/MockTerrain.h b/Gems/Terrain/Code/Mocks/Terrain/MockTerrain.h index 53d93be8ea..f9607fdafb 100644 --- a/Gems/Terrain/Code/Mocks/Terrain/MockTerrain.h +++ b/Gems/Terrain/Code/Mocks/Terrain/MockTerrain.h @@ -34,7 +34,8 @@ namespace UnitTest MOCK_METHOD1(RegisterArea, void(AZ::EntityId areaId)); MOCK_METHOD1(UnregisterArea, void(AZ::EntityId areaId)); - MOCK_METHOD1(RefreshArea, void(AZ::EntityId areaId)); + MOCK_METHOD2(RefreshArea, + void(AZ::EntityId areaId, AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask changeMask)); }; class MockTerrainDataNotificationListener : public AzFramework::Terrain::TerrainDataNotificationBus::Handler diff --git a/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp index 01ad0bb77f..231d5abc28 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp @@ -119,7 +119,9 @@ namespace Terrain LmbrCentral::DependencyNotificationBus::Handler::BusDisconnect(); // Since this height data will no longer exist, notify the terrain system to refresh the area. - TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId()); + TerrainSystemServiceRequestBus::Broadcast( + &TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId(), + AzFramework::Terrain::TerrainDataNotifications::HeightData); } bool TerrainHeightGradientListComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig) @@ -176,7 +178,9 @@ namespace Terrain void TerrainHeightGradientListComponent::OnCompositionChanged() { RefreshMinMaxHeights(); - TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId()); + TerrainSystemServiceRequestBus::Broadcast( + &TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId(), + AzFramework::Terrain::TerrainDataNotifications::HeightData); } void TerrainHeightGradientListComponent::RefreshMinMaxHeights() diff --git a/Gems/Terrain/Code/Source/Components/TerrainLayerSpawnerComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainLayerSpawnerComponent.cpp index 00ed9c004f..c3803c25e8 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainLayerSpawnerComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainLayerSpawnerComponent.cpp @@ -157,6 +157,12 @@ namespace Terrain void TerrainLayerSpawnerComponent::RefreshArea() { - TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId()); + using Terrain = AzFramework::Terrain::TerrainDataNotifications; + + // Notify the terrain system that the entire layer has changed, so both height and surface data can be affected. + TerrainSystemServiceRequestBus::Broadcast( + &TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId(), + static_cast(Terrain::HeightData | Terrain::SurfaceData) + ); } } diff --git a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp index 5b76f15d74..748221d69e 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp @@ -184,7 +184,9 @@ namespace Terrain void TerrainSurfaceGradientListComponent::OnCompositionChanged() { - TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId()); + TerrainSystemServiceRequestBus::Broadcast( + &TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId(), + AzFramework::Terrain::TerrainDataNotifications::SurfaceData); } } // namespace Terrain diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp index fa1d483a5d..8d39340b06 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp @@ -76,6 +76,7 @@ void TerrainSystem::Activate() m_dirtyRegion = AZ::Aabb::CreateNull(); m_terrainHeightDirty = true; m_terrainSettingsDirty = true; + m_terrainSurfacesDirty = true; m_requestedSettings.m_systemActive = true; { @@ -115,6 +116,7 @@ void TerrainSystem::Deactivate() m_dirtyRegion = AZ::Aabb::CreateNull(); m_terrainHeightDirty = true; m_terrainSettingsDirty = true; + m_terrainSurfacesDirty = true; m_requestedSettings.m_systemActive = false; AzFramework::Terrain::TerrainDataNotificationBus::Broadcast( @@ -549,6 +551,7 @@ void TerrainSystem::RegisterArea(AZ::EntityId areaId) m_registeredAreas[areaId] = aabb; m_dirtyRegion.AddAabb(aabb); m_terrainHeightDirty = true; + m_terrainSurfacesDirty = true; } void TerrainSystem::UnregisterArea(AZ::EntityId areaId) @@ -567,14 +570,17 @@ void TerrainSystem::UnregisterArea(AZ::EntityId areaId) { m_dirtyRegion.AddAabb(aabb); m_terrainHeightDirty = true; + m_terrainSurfacesDirty = true; return true; } return false; }); } -void TerrainSystem::RefreshArea(AZ::EntityId areaId) +void TerrainSystem::RefreshArea(AZ::EntityId areaId, AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask changeMask) { + using Terrain = AzFramework::Terrain::TerrainDataNotifications; + AZStd::unique_lock lock(m_areaMutex); auto areaAabb = m_registeredAreas.find(areaId); @@ -588,11 +594,18 @@ void TerrainSystem::RefreshArea(AZ::EntityId areaId) expandedAabb.AddAabb(newAabb); m_dirtyRegion.AddAabb(expandedAabb); - m_terrainHeightDirty = true; + + // Keep track of which types of data have changed so that we can send out the appropriate notifications later. + + m_terrainHeightDirty = m_terrainHeightDirty || ((changeMask & Terrain::HeightData) == Terrain::HeightData); + + m_terrainSurfacesDirty = m_terrainSurfacesDirty || ((changeMask & Terrain::SurfaceData) == Terrain::SurfaceData); } void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/) { + using Terrain = AzFramework::Terrain::TerrainDataNotifications; + bool terrainSettingsChanged = false; if (m_terrainSettingsDirty) @@ -607,6 +620,7 @@ void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/) m_dirtyRegion = m_currentSettings.m_worldBounds; m_dirtyRegion.AddAabb(m_requestedSettings.m_worldBounds); m_terrainHeightDirty = true; + m_terrainSurfacesDirty = true; m_currentSettings.m_worldBounds = m_requestedSettings.m_worldBounds; } @@ -614,12 +628,13 @@ void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/) { m_dirtyRegion = AZ::Aabb::CreateNull(); m_terrainHeightDirty = true; + m_terrainSurfacesDirty = true; } m_currentSettings = m_requestedSettings; } - if (terrainSettingsChanged || m_terrainHeightDirty) + if (terrainSettingsChanged || m_terrainHeightDirty || m_terrainSurfacesDirty) { // Block other threads from accessing the surface data bus while we are in GetValue (which may call into the SurfaceData bus). // We lock our surface data mutex *before* checking / setting "isRequestInProgress" so that we prevent race conditions @@ -629,24 +644,27 @@ void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/) auto& surfaceDataContext = SurfaceData::SurfaceDataSystemRequestBus::GetOrCreateContext(false); typename SurfaceData::SurfaceDataSystemRequestBus::Context::DispatchLockGuard scopeLock(surfaceDataContext.m_contextMutex); - AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask changeMask = - AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask::None; + Terrain::TerrainDataChangedMask changeMask = Terrain::TerrainDataChangedMask::None; if (terrainSettingsChanged) { - changeMask = static_cast( - changeMask | AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask::Settings); + changeMask = static_cast(changeMask | Terrain::TerrainDataChangedMask::Settings); } if (m_terrainHeightDirty) { - changeMask = static_cast( - changeMask | AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask::HeightData); + changeMask = static_cast(changeMask | Terrain::TerrainDataChangedMask::HeightData); + } + + if (m_terrainSurfacesDirty) + { + changeMask = static_cast(changeMask | Terrain::TerrainDataChangedMask::SurfaceData); } // Make sure to set these *before* calling OnTerrainDataChanged, since it's possible that subsystems reacting to that call will // cause the data to become dirty again. AZ::Aabb dirtyRegion = m_dirtyRegion; m_terrainHeightDirty = false; + m_terrainSurfacesDirty = false; m_dirtyRegion = AZ::Aabb::CreateNull(); AzFramework::Terrain::TerrainDataNotificationBus::Broadcast( diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h index 956424f048..022cd218cc 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h @@ -47,7 +47,8 @@ namespace Terrain void RegisterArea(AZ::EntityId areaId) override; void UnregisterArea(AZ::EntityId areaId) override; - void RefreshArea(AZ::EntityId areaId) override; + void RefreshArea( + AZ::EntityId areaId, AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask changeMask) override; /////////////////////////////////////////// // TerrainDataRequestBus::Handler Impl @@ -164,6 +165,7 @@ namespace Terrain bool m_terrainSettingsDirty = true; bool m_terrainHeightDirty = false; + bool m_terrainSurfacesDirty = false; AZ::Aabb m_dirtyRegion; mutable AZStd::shared_mutex m_areaMutex; diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystemBus.h b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystemBus.h index cda6d65a1e..013d82d94d 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystemBus.h +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystemBus.h @@ -44,7 +44,7 @@ namespace Terrain // register an area to override terrain virtual void RegisterArea(AZ::EntityId areaId) = 0; virtual void UnregisterArea(AZ::EntityId areaId) = 0; - virtual void RefreshArea(AZ::EntityId areaId) = 0; + virtual void RefreshArea(AZ::EntityId areaId, AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask changeMask) = 0; }; using TerrainSystemServiceRequestBus = AZ::EBus; diff --git a/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp b/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp index 0ca5e7d99a..3778ba860f 100644 --- a/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp +++ b/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp @@ -190,7 +190,7 @@ TEST_F(LayerSpawnerComponentTest, LayerSpawnerTransformChangedUpdatesTerrainSyst CreateMockTerrainSystem(); // The TransformChanged call should refresh the area. - EXPECT_CALL(*m_terrainSystem, RefreshArea(_)).Times(1); + EXPECT_CALL(*m_terrainSystem, RefreshArea(_, _)).Times(1); AddLayerSpawnerAndShapeComponentToEntity(); @@ -211,7 +211,7 @@ TEST_F(LayerSpawnerComponentTest, LayerSpawnerShapeChangedUpdatesTerrainSystem) CreateMockTerrainSystem(); // The ShapeChanged call should refresh the area. - EXPECT_CALL(*m_terrainSystem, RefreshArea(_)).Times(1); + EXPECT_CALL(*m_terrainSystem, RefreshArea(_, _)).Times(1); AddLayerSpawnerAndShapeComponentToEntity(); diff --git a/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp b/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp index c314e4e968..ec500d6ada 100644 --- a/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp +++ b/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp @@ -93,7 +93,7 @@ TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientRefreshesTer // As the TerrainHeightGradientListComponent subscribes to the dependency monitor, RefreshArea will be called twice: // once due to OnCompositionChanged being picked up by the the dependency monitor and resending the notification, // and once when the HeightGradientListComponent gets the OnCompositionChanged directly through the DependencyNotificationBus. - EXPECT_CALL(terrainSystem, RefreshArea(_)).Times(2); + EXPECT_CALL(terrainSystem, RefreshArea(_, _)).Times(2); LmbrCentral::DependencyNotificationBus::Event(m_entity->GetId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged); From 6cce184340dbce9796234a67a0452d1088474945 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Thu, 28 Oct 2021 14:33:24 -0700 Subject: [PATCH 48/77] Enforce unique gem names in catalog (#5063) Signed-off-by: AMZN-alexpete <26804013+AMZN-alexpete@users.noreply.github.com> --- Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 90eaaf0628..81598f5a6a 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -27,6 +27,14 @@ namespace O3DE::ProjectManager void GemModel::AddGem(const GemInfo& gemInfo) { + if (FindIndexByNameString(gemInfo.m_name).isValid()) + { + // do not add gems with duplicate names + // this can happen by mistake or when a gem repo has a gem with the same name as a local gem + AZ_TracePrintf("GemModel", "Ignoring duplicate gem: %s", gemInfo.m_name.toUtf8().constData()); + return; + } + QStandardItem* item = new QStandardItem(); item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); From 29f5fb1271f30a51e236e101f57fe2d6a7c760c0 Mon Sep 17 00:00:00 2001 From: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu, 28 Oct 2021 16:38:27 -0500 Subject: [PATCH 49/77] {lyn7352} adding more logging around mock_asset_builder.py (#5103) o3de\AutomatedTesting\Gem\PythonTests\PythonAssetBuilder\mock_asset_builder.py - adding more logging - updated keys for platforms (pc, server) Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> --- .../Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py index 443a420b61..a6e8b97b63 100644 --- a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py +++ b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py @@ -23,7 +23,7 @@ def create_jobs(request): jobDescriptorList = [] for platformInfo in request.enabledPlatforms: jobDesc = azlmbr.asset.builder.JobDescriptor() - jobDesc.jobKey = jobKeyName + jobDesc.jobKey = f'{jobKeyName}-{platformInfo.identifier}' jobDesc.set_platform_identifier(platformInfo.identifier) jobDescriptorList.append(jobDesc) @@ -38,7 +38,7 @@ def on_create_jobs(args): return create_jobs(request) except: log_exception_traceback() - # returing back a default CreateJobsResponse() records an asset error + # returning back a default CreateJobsResponse() records an asset error return azlmbr.asset.builder.CreateJobsResponse() def process_file(request): @@ -58,6 +58,7 @@ def process_file(request): fileOutput = open(tempFilename, "w") fileOutput.write('{}') fileOutput.close() + print(f'Wrote mock asset file: {tempFilename}') # generate a product asset file entry subId = binascii.crc32(mockFilename.encode()) From 899bda4631208958cfc46e30a9ed7dd5dcf01c0e Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu, 28 Oct 2021 17:17:18 -0500 Subject: [PATCH 50/77] Add additional logging for Fingerprint test. (#5104) This logging is to help track down a Jenkins only automated test failure. Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../tests/assetmanager/AssetProcessorManagerTest.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp index 6c19213414..0b02b168dc 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp @@ -4447,7 +4447,9 @@ AssetBuilderSDK::AssetBuilderDesc MockBuilderInfoHandler::CreateBuilderDesc(cons void FingerprintTest::SetUp() { + AZ_Printf("FingerprintTest", "SetUp start"); AssetProcessorManagerTest::SetUp(); + AZ_Printf("FingerprintTest", "SetUp self"); // We don't want the mock application manager to provide builder descriptors, mockBuilderInfoHandler will provide our own m_mockApplicationManager->BusDisconnect(); @@ -4466,18 +4468,23 @@ void FingerprintTest::SetUp() }); ASSERT_TRUE(UnitTestUtils::CreateDummyFile(m_absolutePath, "")); + AZ_Printf("FingerprintTest", "SetUp end"); } void FingerprintTest::TearDown() { + AZ_Printf("FingerprintTest", "TearDown start"); m_jobResults = AZStd::vector{}; m_mockBuilderInfoHandler = {}; + AZ_Printf("FingerprintTest", "TearDown parent"); AssetProcessorManagerTest::TearDown(); + AZ_Printf("FingerprintTest", "TearDown end"); } void FingerprintTest::RunFingerprintTest(QString builderFingerprint, QString jobFingerprint, bool expectedResult) { + AZ_Printf("FingerprintTest", "Fingerprint Test Start"); m_mockBuilderInfoHandler.m_builderDesc.m_analysisFingerprint = builderFingerprint.toUtf8().data(); m_mockBuilderInfoHandler.m_jobFingerprint = jobFingerprint; QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, m_absolutePath)); @@ -4486,6 +4493,7 @@ void FingerprintTest::RunFingerprintTest(QString builderFingerprint, QString job ASSERT_EQ(m_mockBuilderInfoHandler.m_createJobsCount, 1); ASSERT_EQ(m_jobResults.size(), 1); ASSERT_EQ(m_jobResults[0].m_autoFail, expectedResult); + AZ_Printf("FingerprintTest", "Fingerprint Test End"); } TEST_F(FingerprintTest, FingerprintChecking_JobFingerprint_NoBuilderFingerprint) From ecf70daca8bf2b4a562832bdfb48db2dcb7adc95 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 28 Oct 2021 17:44:16 -0700 Subject: [PATCH 51/77] does this space affects? Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- scripts/build/Platform/Windows/installer_windows.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index 6f793cab64..87f53adc7f 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -48,7 +48,7 @@ IF ERRORLEVEL 1 ( ) IF NOT "%CPACK_BUCKET%"=="" ( - SET "CPACK_OPTIONS=-DCPACK_UPLOAD_URL=s3://%CPACK_BUCKET% %CPACK_OPTIONS%" + SET "CPACK_OPTIONS=-D CPACK_UPLOAD_URL=s3://%CPACK_BUCKET% %CPACK_OPTIONS%" ) ECHO [ci_build] "!CPACK_PATH!" -C %CONFIGURATION% %CPACK_OPTIONS% From 4dcd60ba086e2216841b5dff4e13292986d6742c Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 28 Oct 2021 17:49:31 -0700 Subject: [PATCH 52/77] testing changes to fix Jenkins Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Platform/Windows/Packaging_windows.cmake | 1 + scripts/build/Platform/Windows/build_config.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index 630817370f..e5aeef6209 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -8,6 +8,7 @@ set(LY_INSTALLER_WIX_ROOT "" CACHE PATH "Path to the WiX install path") +message("LY_INSTALLER_WIX_ROOT ${LY_INSTALLER_WIX_ROOT}") if(LY_INSTALLER_WIX_ROOT) if(NOT EXISTS ${LY_INSTALLER_WIX_ROOT}) message(FATAL_ERROR "Invalid path supplied for LY_INSTALLER_WIX_ROOT argument") diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index bebc91cb4d..b185a845ec 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -363,7 +363,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_INSTALLER_WIX_ROOT=\"!WIX!\"", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_INSTALLER_WIX_ROOT=\"!WIX! \"", "EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=ON -DLY_INSTALLER_DOWNLOAD_URL=!INSTALLER_DOWNLOAD_URL! -DLY_INSTALLER_LICENSE_URL=!INSTALLER_DOWNLOAD_URL!/license", "CPACK_BUCKET": "!INSTALLER_BUCKET!", "CMAKE_LY_PROJECTS": "", From 60e14d3a4ca82b9f183a46195d57e555f4937ee9 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 28 Oct 2021 18:17:26 -0700 Subject: [PATCH 53/77] Fixes PR comments Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Platform/Windows/Packaging_windows.cmake | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index e5aeef6209..7b8f5a6c19 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -8,7 +8,6 @@ set(LY_INSTALLER_WIX_ROOT "" CACHE PATH "Path to the WiX install path") -message("LY_INSTALLER_WIX_ROOT ${LY_INSTALLER_WIX_ROOT}") if(LY_INSTALLER_WIX_ROOT) if(NOT EXISTS ${LY_INSTALLER_WIX_ROOT}) message(FATAL_ERROR "Invalid path supplied for LY_INSTALLER_WIX_ROOT argument") @@ -106,9 +105,8 @@ set(_raw_text_license [[ #(loc.InstallEulaAcceptance) ]]) -# if we are doing an offline installer, there is a limit in size the wix tooling can handle and produces -# issues for our current sizes. If the installer is offline, disable the curstom wix generator generating -# a msi instead. +# The offline installer generation will be a single monolithic MSI. The WIX burn tool for the bootstrapper EXE has a size limitation. +# So we will exclude the generation of the boostrapper EXE in the offline case. if(LY_INSTALLER_DOWNLOAD_URL) set(WIX_THEME_WARNING_IMAGE ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/warning.png) From 4e2de0170c345d1dc69b2589f0492b4bde95fb72 Mon Sep 17 00:00:00 2001 From: evanchia Date: Thu, 28 Oct 2021 19:33:59 -0700 Subject: [PATCH 54/77] reverting typehints Signed-off-by: evanchia --- .../_internal/pytest_plugin/editor_test.py | 11 +-- .../ly_test_tools/o3de/editor_test.py | 82 ++++++++----------- .../ly_test_tools/o3de/editor_test_utils.py | 26 ++---- 3 files changed, 46 insertions(+), 73 deletions(-) diff --git a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/editor_test.py b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/editor_test.py index 19caf7e090..1e9d4c3654 100644 --- a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/editor_test.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/editor_test.py @@ -7,14 +7,13 @@ SPDX-License-Identifier: Apache-2.0 OR MIT Utility for specifying an Editor test, supports seamless parallelization and/or batching of tests. This is not a set of tools to directly invoke, but a plugin with functions intended to be called by only the Pytest framework. """ - +from __future__ import annotations import pytest import inspect __test__ = False -def pytest_addoption(parser): - # type (argparse.ArgumentParser) -> None +def pytest_addoption(parser: argparse.ArgumentParser) -> None: """ Options when running editor tests in batches or parallel. :param parser: The ArgumentParser object @@ -24,8 +23,7 @@ def pytest_addoption(parser): parser.addoption("--no-editor-parallel", action="store_true", help="Don't run multiple editors in parallel") parser.addoption("--editors-parallel", type=int, action="store", help="Override the number editors to run at the same time") -def pytest_pycollect_makeitem(collector, name, obj): - # type (PyCollector, str, object) -> Collector +def pytest_pycollect_makeitem(collector: PyCollector, name: str, obj: object) -> PyCollector: """ Create a custom custom item collection if the class defines pytest_custom_makeitem function. This is used for automatically generating test functions with a custom collector. @@ -40,8 +38,7 @@ def pytest_pycollect_makeitem(collector, name, obj): return base.pytest_custom_makeitem(collector, name, obj) @pytest.hookimpl(hookwrapper=True) -def pytest_collection_modifyitems(session, items, config): - # type (Session, List[EditorTestBase], Config) -> None +def pytest_collection_modifyitems(session: Session, items: list[EditorTestBase], config: Config) -> None: """ Add custom modification of items. This is used for adding the runners into the item list. :param session: The Pytest Session diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py index cf3682e080..ae6ed16321 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py @@ -25,7 +25,7 @@ Usage example: EditorTestSuite does introspection of the defined classes inside of it and automatically prepares the tests, parallelizing/batching as required """ - +from __future__ import annotations import pytest from _pytest.skipping import pytest_runtest_setup as skipping_pytest_runtest_setup @@ -46,6 +46,7 @@ import re import ly_test_tools.environment.file_system as file_system import ly_test_tools.environment.waiter as waiter import ly_test_tools.environment.process_utils as process_utils +import ly_test_tools.o3de.editor_test import ly_test_tools.o3de.editor_test_utils as editor_utils from ly_test_tools.o3de.asset_processor import AssetProcessor @@ -133,8 +134,7 @@ class Result: class Pass(Base): @classmethod - def create(cls, test_spec, output, editor_log): - # type (EditorTestBase, str, str) -> Pass + def create(cls, test_spec: EditorTestBase, output: str, editor_log: str) -> Pass: """ Creates a Pass object with a given test spec, output string, and editor log string. :test_spec: The type of EditorTestBase @@ -160,8 +160,7 @@ class Result: class Fail(Base): @classmethod - def create(cls, test_spec, output, editor_log): - # type (EditorTestBase, str, str) -> Fail + def create(cls, test_spec: EditorTestBase, output: str, editor_log: str) -> Fail: """ Creates a Fail object with a given test spec, output string, and editor log string. :test_spec: The type of EditorTestBase @@ -191,8 +190,7 @@ class Result: class Crash(Base): @classmethod - def create(cls, test_spec, output, ret_code, stacktrace, editor_log): - # type (EditorTestBase, str, int, str, str) -> Crash + def create(cls, test_spec: EditorTestBase, output: str, ret_code: int, stacktrace: str, editor_log: str) -> Crash: """ Creates a Crash object with a given test spec, output string, and editor log string. This also includes the return code and stacktrace. @@ -232,8 +230,7 @@ class Result: class Timeout(Base): @classmethod - def create(cls, test_spec, output, time_secs, editor_log): - # type (EditorTestBase, str, float, str) -> Timeout + def create(cls, test_spec: EditorTestBase, output: str, time_secs: float, editor_log: str) -> Timeout: """ Creates a Timeout object with a given test spec, output string, and editor log string. The timeout time should be provided in seconds @@ -266,8 +263,7 @@ class Result: class Unknown(Base): @classmethod - def create(cls, test_spec, output, extra_info, editor_log): - # type (EditorTestBase, str, str , str) -> Unknown + def create(cls, test_spec: EditorTestBase, output: str, extra_info: str, editor_log: str) -> Unknown: """ Creates an Unknown test results object if something goes wrong. :test_spec: The type of EditorTestBase @@ -318,8 +314,7 @@ class EditorTestSuite(): _TEST_FAIL_RETCODE = 0xF # Return code for test failure @pytest.fixture(scope="class") - def editor_test_data(self, request): - # type (request) -> TestData + def editor_test_data(self, request: Request) -> TestData: """ Yields a per-testsuite structure to store the data of each test result and an AssetProcessor object that will be re-used on the whole suite @@ -328,7 +323,7 @@ class EditorTestSuite(): """ yield from self._editor_test_data(request) - def _editor_test_data(self, request): + def _editor_test_data(self, request: Request) -> TestData: """ A wrapper function for unit testing to call directly """ @@ -513,8 +508,7 @@ class EditorTestSuite(): return EditorTestSuite.EditorTestClass(name, collector) @classmethod - def pytest_custom_modify_items(cls, session, items, config): - # type (Session, List[EditorTestBase], Config) -> None + def pytest_custom_modify_items(cls, session: Session, items: list[EditorTestBase], config: Config) -> None: """ Adds the runners' functions and filters the tests that will run. The runners will be added if they have any selected tests @@ -538,8 +532,7 @@ class EditorTestSuite(): items[:] = items + new_items @classmethod - def get_single_tests(cls): - # type () -> List + def get_single_tests(cls) -> list[EditorSingleTest]: """ Grabs all of the EditorSingleTests subclassed tests from the EditorTestSuite class Usage example: @@ -552,8 +545,7 @@ class EditorTestSuite(): return single_tests @classmethod - def get_shared_tests(cls): - # type () -> List + def get_shared_tests(cls) -> list[EditorSharedTest]: """ Grabs all of the EditorSharedTests from the EditorTestSuite Usage example: @@ -566,8 +558,7 @@ class EditorTestSuite(): return shared_tests @classmethod - def get_session_shared_tests(cls, session): - # type (Session) -> List[EditorTestBase] + def get_session_shared_tests(cls, session: Session) -> list[EditorTestBase]: """ Filters and returns all of the shared tests in a given session. :session: The test session @@ -577,8 +568,7 @@ class EditorTestSuite(): return cls.filter_session_shared_tests(session, shared_tests) @staticmethod - def filter_session_shared_tests(session_items, shared_tests): - # type (List[EditorTestBase, List[EditorSharedTest]) -> List[EditorTestBase] + def filter_session_shared_tests(session_items: list[EditorTestBase], shared_tests: list[EditorSharedTest]) -> list[EditorTestBase]: """ Retrieve the test sub-set that was collected this can be less than the original set if were overriden via -k argument or similars @@ -599,8 +589,8 @@ class EditorTestSuite(): return selected_shared_tests @staticmethod - def filter_shared_tests(shared_tests, is_batchable=False, is_parallelizable=False): - # type (List[EditorSharedTest], bool, bool) -> List[EditorSharedTest] + def filter_shared_tests(shared_tests: list[EditorSharedTest], is_batchable: bool = False, + is_parallelizable: bool = False) -> list[EditorSharedTest]: """ Filters and returns all tests based off of if they are batchable and/or parallelizable :shared_tests: All shared tests @@ -617,8 +607,7 @@ class EditorTestSuite(): ] ### Utils ### - def _prepare_asset_processor(self, workspace, editor_test_data): - # type (AbstractWorkspace, TestData) -> None + def _prepare_asset_processor(self, workspace: AbstractWorkspace, editor_test_data: TestData) -> None: """ Prepares the asset processor for the test depending on whether or not the process is open and if the current test owns it. @@ -643,8 +632,7 @@ class EditorTestSuite(): editor_test_data.asset_processor = None raise ex - def _setup_editor_test(self, editor, workspace, editor_test_data): - # type(Editor, AbstractWorkspace, TestData) -> None + def _setup_editor_test(self, editor: Editor, workspace: AbstractWorkspace, editor_test_data: TestData) -> None: """ Sets up an editor test by preparing the Asset Processor, killing all other O3DE processes, and configuring :editor: The launcher Editor object @@ -657,8 +645,7 @@ class EditorTestSuite(): editor.configure_settings() @staticmethod - def _get_results_using_output(test_spec_list, output, editor_log_content): - # type(List[EditorTestBase], str, str) -> dict{str: Result} + def _get_results_using_output(test_spec_list: list[EditorTestBase], output: str, editor_log_content: str) -> dict[str, Result]: """ Utility function for parsing the output information from the editor. It deserializes the JSON content printed in the output for every test and returns that information. @@ -718,8 +705,7 @@ class EditorTestSuite(): return results @staticmethod - def _report_result(name, result): - # type (str, Result) -> None + def _report_result(name: str, result: Result) -> None: """ Fails the test if the test result is not a PASS, specifying the information :name: Name of the test @@ -734,8 +720,8 @@ class EditorTestSuite(): pytest.fail(error_str) ### Running tests ### - def _exec_editor_test(self, request, workspace, editor, run_id, log_name, test_spec, cmdline_args = []): - # type (Request, AbstractWorkspace, Editor, int, str, EditorTestBase, List[str] -> dict{str: Result} + def _exec_editor_test(self, request: Request, workspace: AbstractWorkspace, editor: Editor, run_id: int, + log_name: str, test_spec: EditorTestBase, cmdline_args: list[str] = []) -> dict[str, Result]: """ Starts the editor with the given test and retuns an result dict with a single element specifying the result :request: The pytest request @@ -796,8 +782,8 @@ class EditorTestSuite(): results[test_spec.__name__] = test_result return results - def _exec_editor_multitest(self, request, workspace, editor, run_id, log_name, test_spec_list, cmdline_args=[]): - # type (Request, AbstractWorkspace, Editor, int, str, List[EditorTestBase], List[str]) -> dict{str: Result} + def _exec_editor_multitest(self, request: Request, workspace: AbstractWorkspace, editor: Editor, run_id: int, log_name: str, + test_spec_list: list[EditorTestBase], cmdline_args: list[str] = []) -> dict[str, Result]: """ Starts an editor executable with a list of tests and returns a dict of the result of every test ran within that editor instance. In case of failure this function also parses the editor output to find out what specific tests @@ -907,8 +893,8 @@ class EditorTestSuite(): return results - def _run_single_test(self, request, workspace, editor, editor_test_data, test_spec): - # type (Request, AbstractWorkspace, Editor, TestData, EditorSingleTest) -> None + def _run_single_test(self, request: Request, workspace: AbstractWorkspace, editor: Editor, + editor_test_data: TestData, test_spec: EditorSingleTest) -> None: """ Runs a single test (one editor, one test) with the given specs :request: The Pytest Request @@ -928,8 +914,8 @@ class EditorTestSuite(): test_name, test_result = next(iter(results.items())) self._report_result(test_name, test_result) - def _run_batched_tests(self, request, workspace, editor, editor_test_data, test_spec_list, extra_cmdline_args=[]): - # type (Request, AbstractWorkspace, Editor, TestData, List[EditorSharedTest], List[str]) -> None + def _run_batched_tests(self, request: Request, workspace: AbstractWorkspace, editor: Editor, editor_test_data: TestData, + test_spec_list: list[EditorSharedTest], extra_cmdline_args: list[str] = []) -> None: """ Runs a batch of tests in one single editor with the given spec list (one editor, multiple tests) :request: The Pytest Request @@ -949,8 +935,8 @@ class EditorTestSuite(): assert results is not None editor_test_data.results.update(results) - def _run_parallel_tests(self, request, workspace, editor, editor_test_data, test_spec_list, extra_cmdline_args=[]): - # type(Request, AbstractWorkspace, Editor, TestData, List[EditorSharedTest], List[str]) -> None + def _run_parallel_tests(self, request: Request, workspace: AbstractWorkspace, editor: Editor, editor_test_data: TestData, + test_spec_list: list[EditorSharedTest], extra_cmdline_args: list[str] = []) -> None: """ Runs multiple editors with one test on each editor (multiple editor, one test each) :request: The Pytest Request @@ -997,9 +983,8 @@ class EditorTestSuite(): for result in results_per_thread: editor_test_data.results.update(result) - def _run_parallel_batched_tests(self, request, workspace, editor, editor_test_data, test_spec_list, - extra_cmdline_args=[]): - # type(Request, AbstractWorkspace, Editor, TestData, List[EditorSharedTest], List[str] -> None + def _run_parallel_batched_tests(self, request: Request, workspace: AbstractWorkspace, editor: Editor, editor_test_data: TestData, + test_spec_list: list[EditorSharedTest], extra_cmdline_args: list[str] = []) -> None: """ Runs multiple editors with a batch of tests for each editor (multiple editor, multiple tests each) :request: The Pytest Request @@ -1047,8 +1032,7 @@ class EditorTestSuite(): for result in results_per_thread: editor_test_data.results.update(result) - def _get_number_parallel_editors(self, request): - # type(Request) -> int + def _get_number_parallel_editors(self, request: Request) -> int: """ Retrieves the number of parallel preference cmdline overrides :request: The Pytest Request diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py index 6e319bb860..35fbe93d37 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py @@ -6,7 +6,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT Utility functions mostly for the editor_test module. They can also be used for assisting Editor tests. """ - +from __future__ import annotations import os import time import logging @@ -16,8 +16,7 @@ import ly_test_tools.environment.waiter as waiter logger = logging.getLogger(__name__) -def kill_all_ly_processes(include_asset_processor=True): - # type (bool) -> None +def kill_all_ly_processes(include_asset_processor: bool = True) -> None: """ Kills all common O3DE processes such as the Editor, Game Launchers, and optionally Asset Processor. Defaults to killing the Asset Processor. @@ -36,8 +35,7 @@ def kill_all_ly_processes(include_asset_processor=True): else: process_utils.kill_processes_named(LY_PROCESSES, ignore_extensions=True) -def get_testcase_module_filepath(testcase_module): - # type: (Module) -> str +def get_testcase_module_filepath(testcase_module: Module) -> str: """ return the full path of the test module using always '.py' extension :param testcase_module: The testcase python module being tested @@ -45,8 +43,7 @@ def get_testcase_module_filepath(testcase_module): """ return os.path.splitext(testcase_module.__file__)[0] + ".py" -def get_module_filename(testcase_module): - # type: (Module) -> str +def get_module_filename(testcase_module: Module): """ return The filename of the module without path Note: This is differs from module.__name__ in the essence of not having the package directory. @@ -56,8 +53,7 @@ def get_module_filename(testcase_module): """ return os.path.splitext(os.path.basename(testcase_module.__file__))[0] -def retrieve_log_path(run_id, workspace): - # type (int, ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager) -> str +def retrieve_log_path(run_id: int, workspace: AbstractWorkspaceManager) -> str: """ return the log/ project path for this test run. :param run_id: editor id that will be used for differentiating paths @@ -66,8 +62,7 @@ def retrieve_log_path(run_id, workspace): """ return os.path.join(workspace.paths.project(), "user", f"log_test_{run_id}") -def retrieve_crash_output(run_id, workspace, timeout=10): - # type (int, ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager, float) -> str +def retrieve_crash_output(run_id: int, workspace: AbstractWorkspaceManager, timeout: float = 10) -> str: """ returns the crash output string for the given test run. :param run_id: editor id that will be used for differentiating paths @@ -90,8 +85,7 @@ def retrieve_crash_output(run_id, workspace, timeout=10): crash_info += f"\n{str(ex)}" return crash_info -def cycle_crash_report(run_id, workspace): - # type (int, ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager) -> None +def cycle_crash_report(run_id: int, workspace: AbstractWorkspaceManager) -> None: """ Attempts to rename error.log and error.dmp(crash files) into new names with the timestamp on it. :param run_id: editor id that will be used for differentiating paths @@ -111,8 +105,7 @@ def cycle_crash_report(run_id, workspace): except Exception as ex: logger.warning(f"Couldn't cycle file {filepath}. Error: {str(ex)}") -def retrieve_editor_log_content(run_id, log_name, workspace, timeout=10): - # type (int , str, ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager, int) -> str +def retrieve_editor_log_content(run_id: int, log_name: str, workspace: AbstractWorkspaceManager, timeout: int = 10) -> str: """ Retrieves the contents of the given editor log file. :param run_id: editor id that will be used for differentiating paths @@ -138,8 +131,7 @@ def retrieve_editor_log_content(run_id, log_name, workspace, timeout=10): editor_info = f"-- Error reading editor.log: {str(ex)} --" return editor_info -def retrieve_last_run_test_index_from_output(test_spec_list, output): - # type (List[EditorTestBase], str) -> int +def retrieve_last_run_test_index_from_output(test_spec_list: list[EditorTestBase], output: str) -> int: """ Finds out what was the last test that was run by inspecting the input. This is used for determining what was the batched test has crashed the editor From 37381489ee2bac06f7600db4fb27f4282eb4ad0d Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Fri, 29 Oct 2021 09:12:27 +0200 Subject: [PATCH 55/77] EMotion FX: Actor component: Skeleton rendering is not working (#5084) Enabling the "Draw skeleton" checkbox in the actor component does not show the skeleton. Signed-off-by: Benjamin Jillich --- .../Code/Source/Integration/Components/ActorComponent.cpp | 2 +- .../Integration/Editor/Components/EditorActorComponent.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp index 8520896dd2..e38e15d124 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp @@ -576,7 +576,7 @@ namespace EMotionFX // The configuration stores some debug option. When that is enabled, we override it on top of the render flags. m_debugRenderFlags[RENDER_AABB] = m_debugRenderFlags[RENDER_AABB] || m_configuration.m_renderBounds; - m_debugRenderFlags[RENDER_SKELETON] = m_debugRenderFlags[RENDER_SKELETON] || m_configuration.m_renderSkeleton; + m_debugRenderFlags[RENDER_LINESKELETON] = m_debugRenderFlags[RENDER_LINESKELETON] || m_configuration.m_renderSkeleton; m_debugRenderFlags[RENDER_EMFX_DEBUG] = true; m_renderActorInstance->DebugDraw(m_debugRenderFlags); } diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp index d0274b3c68..78470a1fa5 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp @@ -606,7 +606,7 @@ namespace EMotionFX m_renderActorInstance->UpdateBounds(); m_debugRenderFlags[RENDER_AABB] = m_renderBounds; - m_debugRenderFlags[RENDER_SKELETON] = m_renderSkeleton; + m_debugRenderFlags[RENDER_LINESKELETON] = m_renderSkeleton; m_debugRenderFlags[RENDER_EMFX_DEBUG] = true; m_renderActorInstance->DebugDraw(m_debugRenderFlags); } From a322d9e2b851c7252370eba2c8aaa7306e727705 Mon Sep 17 00:00:00 2001 From: Artur K <96597+nemerle@users.noreply.github.com> Date: Fri, 29 Oct 2021 10:59:18 +0200 Subject: [PATCH 56/77] Small `Code/Editor` cleanup pass (#4909) * Clean-up in ConfigGroup Removed unused templated AddVar and related code. Replaced legacy types with `AZ::` ones. Cleaned up cpp file. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Add a few missing Q_OBJECT macros, remove some unused variables. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Apply some of clazy suggestions + simplifications * removed `emit` from non-signal function calls. * replaced `QStringLiteral("")` with a constexpr friendly `QLatin1String()` Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Fix a CNewLevelDialog focus bug Fixed an incorrect QTimer::singleShot invocation. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * match lambda to `messageChanged` signature Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * vs compilation fix + applied review Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * apply reviewer recommendation Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> --- Code/Editor/CVarMenu.h | 3 + Code/Editor/ConfigGroup.cpp | 182 +++++++++--------- Code/Editor/ConfigGroup.h | 90 ++------- .../PropertyMiscCtrl.h | 6 +- .../PropertyResourceCtrl.cpp | 12 +- .../PropertyResourceCtrl.h | 1 + .../ReflectedVarWrapper.cpp | 67 ++++--- Code/Editor/Controls/TimelineCtrl.cpp | 2 - Code/Editor/CryEdit.h | 1 + Code/Editor/CustomResolutionDlg.h | 5 +- Code/Editor/CustomizeKeyboardDialog.cpp | 6 +- Code/Editor/ErrorDialog.cpp | 4 +- Code/Editor/KeyboardCustomizationSettings.cpp | 2 +- Code/Editor/MainStatusBar.cpp | 2 +- Code/Editor/NewLevelDialog.cpp | 7 +- 15 files changed, 169 insertions(+), 221 deletions(-) diff --git a/Code/Editor/CVarMenu.h b/Code/Editor/CVarMenu.h index efcc8e8caf..5195bd99d7 100644 --- a/Code/Editor/CVarMenu.h +++ b/Code/Editor/CVarMenu.h @@ -16,9 +16,12 @@ #include #include +struct ICVar; + class CVarMenu : public QMenu { + Q_OBJECT public: // CVar that can be toggled on and off struct CVarToggle diff --git a/Code/Editor/ConfigGroup.cpp b/Code/Editor/ConfigGroup.cpp index 74fe6f7b5c..42236e43dd 100644 --- a/Code/Editor/ConfigGroup.cpp +++ b/Code/Editor/ConfigGroup.cpp @@ -19,10 +19,9 @@ namespace Config CConfigGroup::~CConfigGroup() { - for (TConfigVariables::const_iterator it = m_vars.begin(); - it != m_vars.end(); ++it) + for (IConfigVar* var : m_vars) { - delete (*it); + delete var; } } @@ -31,17 +30,15 @@ namespace Config m_vars.push_back(var); } - uint32 CConfigGroup::GetVarCount() + AZ::u32 CConfigGroup::GetVarCount() { - return static_cast(m_vars.size()); + return aznumeric_cast(m_vars.size()); } IConfigVar* CConfigGroup::GetVar(const char* szName) { - for (TConfigVariables::const_iterator it = m_vars.begin(); - it != m_vars.end(); ++it) + for (IConfigVar* var : m_vars) { - IConfigVar* var = (*it); if (0 == _stricmp(szName, var->GetName().c_str())) { return var; @@ -53,20 +50,19 @@ namespace Config const IConfigVar* CConfigGroup::GetVar(const char* szName) const { - for (TConfigVariables::const_iterator it = m_vars.begin(); - it != m_vars.end(); ++it) + for (const IConfigVar* var : m_vars) { - IConfigVar* var = (*it); if (0 == _stricmp(szName, var->GetName().c_str())) { return var; } + } return nullptr; } - IConfigVar* CConfigGroup::GetVar(uint index) + IConfigVar* CConfigGroup::GetVar(AZ::u32 index) { if (index < m_vars.size()) { @@ -76,7 +72,7 @@ namespace Config return nullptr; } - const IConfigVar* CConfigGroup::GetVar(uint index) const + const IConfigVar* CConfigGroup::GetVar(AZ::u32 index) const { if (index < m_vars.size()) { @@ -89,114 +85,110 @@ namespace Config void CConfigGroup::SaveToXML(XmlNodeRef node) { // save only values that don't have default values - for (TConfigVariables::const_iterator it = m_vars.begin(); - it != m_vars.end(); ++it) + for (const IConfigVar* var : m_vars) { - IConfigVar* var = (*it); - if (!var->IsFlagSet(IConfigVar::eFlag_DoNotSave)) + if (var->IsFlagSet(IConfigVar::eFlag_DoNotSave) || var->IsDefault()) { - if (!var->IsDefault()) - { - const char* szName = var->GetName().c_str(); + continue; + } - switch (var->GetType()) - { - case IConfigVar::eType_BOOL: - { - bool currentValue = false; - var->Get(¤tValue); - node->setAttr(szName, currentValue); - break; - } + const char* szName = var->GetName().c_str(); - case IConfigVar::eType_INT: - { - int currentValue = 0; - var->Get(¤tValue); - node->setAttr(szName, currentValue); - break; - } + switch (var->GetType()) + { + case IConfigVar::eType_BOOL: + { + bool currentValue = false; + var->Get(¤tValue); + node->setAttr(szName, currentValue); + break; + } - case IConfigVar::eType_FLOAT: - { - float currentValue = 0; - var->Get(¤tValue); - node->setAttr(szName, currentValue); - break; - } + case IConfigVar::eType_INT: + { + int currentValue = 0; + var->Get(¤tValue); + node->setAttr(szName, currentValue); + break; + } - case IConfigVar::eType_STRING: - { - AZStd::string currentValue; - var->Get(¤tValue); - node->setAttr(szName, currentValue.c_str()); - break; - } - } - } + case IConfigVar::eType_FLOAT: + { + float currentValue = 0; + var->Get(¤tValue); + node->setAttr(szName, currentValue); + break; + } + + case IConfigVar::eType_STRING: + { + AZStd::string currentValue; + var->Get(¤tValue); + node->setAttr(szName, currentValue.c_str()); + break; + } } } } void CConfigGroup::LoadFromXML(XmlNodeRef node) { - // save only values that don't have default values - for (TConfigVariables::const_iterator it = m_vars.begin(); - it != m_vars.end(); ++it) + // load values that are save-able + for (IConfigVar* var : m_vars) { - IConfigVar* var = (*it); - if (!var->IsFlagSet(IConfigVar::eFlag_DoNotSave)) + if (var->IsFlagSet(IConfigVar::eFlag_DoNotSave)) { - const char* szName = var->GetName().c_str(); + continue; + } + const char* szName = var->GetName().c_str(); - switch (var->GetType()) + switch (var->GetType()) + { + case IConfigVar::eType_BOOL: + { + bool currentValue = false; + var->GetDefault(¤tValue); + if (node->getAttr(szName, currentValue)) { - case IConfigVar::eType_BOOL: - { - bool currentValue = false; - var->GetDefault(¤tValue); - if (node->getAttr(szName, currentValue)) - { - var->Set(¤tValue); - } - break; + var->Set(¤tValue); } + break; + } - case IConfigVar::eType_INT: + case IConfigVar::eType_INT: + { + int currentValue = 0; + var->GetDefault(¤tValue); + if (node->getAttr(szName, currentValue)) { - int currentValue = 0; - var->GetDefault(¤tValue); - if (node->getAttr(szName, currentValue)) - { - var->Set(¤tValue); - } - break; + var->Set(¤tValue); } + break; + } - case IConfigVar::eType_FLOAT: + case IConfigVar::eType_FLOAT: + { + float currentValue = 0; + var->GetDefault(¤tValue); + if (node->getAttr(szName, currentValue)) { - float currentValue = 0; - var->GetDefault(¤tValue); - if (node->getAttr(szName, currentValue)) - { - var->Set(¤tValue); - } - break; + var->Set(¤tValue); } + break; + } - case IConfigVar::eType_STRING: + case IConfigVar::eType_STRING: + { + AZStd::string currentValue; + var->GetDefault(¤tValue); + QString readValue(currentValue.c_str()); + if (node->getAttr(szName, readValue)) { - AZStd::string currentValue; - var->GetDefault(¤tValue); - QString readValue(currentValue.c_str()); - if (node->getAttr(szName, readValue)) - { - currentValue = readValue.toUtf8().data(); - var->Set(¤tValue); - } - break; - } + currentValue = readValue.toUtf8().data(); + var->Set(¤tValue); } + break; + } } } } diff --git a/Code/Editor/ConfigGroup.h b/Code/Editor/ConfigGroup.h index 769a29ba8a..004725e32c 100644 --- a/Code/Editor/ConfigGroup.h +++ b/Code/Editor/ConfigGroup.h @@ -8,8 +8,12 @@ #pragma once -#ifndef CRYINCLUDE_EDITOR_CONFIGGROUP_H -#define CRYINCLUDE_EDITOR_CONFIGGROUP_H +#include +#include +#include + +struct ICVar; +class XmlNodeRef; namespace Config { @@ -32,7 +36,7 @@ namespace Config eFlag_DoNotSave = 1 << 2, }; - IConfigVar(const char* szName, const char* szDescription, EType varType, uint8 flags) + IConfigVar(const char* szName, const char* szDescription, EType varType, AZ::u8 flags) : m_name(szName) , m_description(szDescription) , m_type(varType) @@ -42,22 +46,22 @@ namespace Config virtual ~IConfigVar() = default; - ILINE EType GetType() const + AZ_FORCE_INLINE EType GetType() const { return m_type; } - ILINE const AZStd::string& GetName() const + AZ_FORCE_INLINE const AZStd::string& GetName() const { return m_name; } - ILINE const AZStd::string& GetDescription() const + AZ_FORCE_INLINE const AZStd::string& GetDescription() const { return m_description; } - ILINE bool IsFlagSet(EFlags flag) const + AZ_FORCE_INLINE bool IsFlagSet(EFlags flag) const { return 0 != (m_flags & flag); } @@ -68,73 +72,28 @@ namespace Config virtual void GetDefault(void* outPtr) const = 0; virtual void Reset() = 0; - static EType TranslateType(const bool&) { return eType_BOOL; } - static EType TranslateType(const int&) { return eType_INT; } - static EType TranslateType(const float&) { return eType_FLOAT; } - static EType TranslateType(const AZStd::string&) { return eType_STRING; } + static constexpr EType TranslateType(const bool&) { return eType_BOOL; } + static constexpr EType TranslateType(const int&) { return eType_INT; } + static constexpr EType TranslateType(const float&) { return eType_FLOAT; } + static constexpr EType TranslateType(const AZStd::string&) { return eType_STRING; } protected: EType m_type; - uint8 m_flags; + AZ::u8 m_flags; AZStd::string m_name; AZStd::string m_description; void* m_ptr; ICVar* m_pCVar; }; - // Typed wrapper for config variable - template - class TConfigVar - : public IConfigVar - { - private: - T m_default; - - public: - TConfigVar(const char* szName, const char* szDescription, uint8 flags, T& ptr, const T& defaultValue) - : IConfigVar(szName, szDescription, IConfigVar::TranslateType(ptr), flags) - , m_default(defaultValue) - { - m_ptr = &ptr; - - // reset to default value on initializations - ptr = defaultValue; - } - - virtual void Get(void* outPtr) const - { - *reinterpret_cast(outPtr) = *reinterpret_cast(m_ptr); - } - - virtual void Set(const void* ptr) - { - *reinterpret_cast(m_ptr) = *reinterpret_cast(ptr); - } - - virtual void Reset() - { - *reinterpret_cast(m_ptr) = m_default; - } - - virtual void GetDefault(void* outPtr) const - { - *reinterpret_cast(outPtr) = m_default; - } - - virtual bool IsDefault() const - { - return *reinterpret_cast(m_ptr) == m_default; - } - }; - // Group of configuration variables with optional mapping to CVars class CConfigGroup { private: - typedef std::vector TConfigVariables; + using TConfigVariables = AZStd::vector ; TConfigVariables m_vars; - typedef std::vector TConsoleVariables; + using TConsoleVariables = AZStd::vector; TConsoleVariables m_consoleVars; public: @@ -142,20 +101,13 @@ namespace Config virtual ~CConfigGroup(); void AddVar(IConfigVar* var); - uint32 GetVarCount(); + AZ::u32 GetVarCount(); IConfigVar* GetVar(const char* szName); - IConfigVar* GetVar(uint index); + IConfigVar* GetVar(AZ::u32 index); const IConfigVar* GetVar(const char* szName) const; - const IConfigVar* GetVar(uint index) const; + const IConfigVar* GetVar(AZ::u32 index) const; void SaveToXML(XmlNodeRef node); void LoadFromXML(XmlNodeRef node); - - template - void AddVar(const char* szName, const char* szDescription, T& var, const T& defaultValue, uint8 flags = 0) - { - AddVar(new TConfigVar(szName, szDescription, flags, var, defaultValue)); - } }; }; -#endif // CRYINCLUDE_EDITOR_CONFIGGROUP_H diff --git a/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.h b/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.h index 5ec24b679d..849e44cedd 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.h +++ b/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.h @@ -6,8 +6,6 @@ * */ -#ifndef CRYINCLUDE_EDITOR_UTILS_PROPERTYMISCCTRL_H -#define CRYINCLUDE_EDITOR_UTILS_PROPERTYMISCCTRL_H #pragma once #if !defined(Q_MOC_RUN) @@ -53,6 +51,7 @@ private: class UserPopupWidgetHandler : public QObject, public AzToolsFramework::PropertyHandler < CReflectedVarUser, UserPropertyEditor> { + Q_OBJECT public: AZ_CLASS_ALLOCATOR(UserPopupWidgetHandler, AZ::SystemAllocator, 0); bool IsDefaultHandler() const override { return false; } @@ -67,6 +66,7 @@ public: class FloatCurveHandler : public QObject, public AzToolsFramework::PropertyHandler < CReflectedVarSpline, CSplineCtrl> { + Q_OBJECT public: AZ_CLASS_ALLOCATOR(FloatCurveHandler, AZ::SystemAllocator, 0); bool IsDefaultHandler() const override { return false; } @@ -80,5 +80,3 @@ public: void OnSplineChange(CSplineCtrl*); }; - -#endif // CRYINCLUDE_EDITOR_UTILS_PROPERTYMISCCTRL_H diff --git a/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.cpp b/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.cpp index c5ccc599d6..d26e978ae8 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.cpp @@ -58,17 +58,9 @@ private: void OnClicked() override { QString tempValue(""); - QString ext(""); - if (m_path.isEmpty() == false) + if (!m_path.isEmpty() && !Path::GetExt(m_path).isEmpty()) { - if (Path::GetExt(m_path) == "") - { - tempValue = ""; - } - else - { - tempValue = m_path; - } + tempValue = m_path; } AssetSelectionModel selection; diff --git a/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.h b/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.h index fa30eba034..087ee9f1db 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.h +++ b/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.h @@ -99,6 +99,7 @@ class FileResourceSelectorWidgetHandler : QObject , public AzToolsFramework::PropertyHandler < CReflectedVarResource, FileResourceSelectorWidget > { + Q_OBJECT public: AZ_CLASS_ALLOCATOR(FileResourceSelectorWidgetHandler, AZ::SystemAllocator, 0); diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp index b3f1b35461..2320938f08 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp @@ -446,41 +446,54 @@ void ReflectedVarUserAdapter::SetVariable(IVariable *pVariable) m_reflectedVar.reset(new CReflectedVarUser( pVariable->GetHumanName().toUtf8().data())); } -void ReflectedVarUserAdapter::SyncReflectedVarToIVar(IVariable *pVariable) +void ReflectedVarUserAdapter::SyncReflectedVarToIVar(IVariable* pVariable) { QString value; pVariable->Get(value); m_reflectedVar->m_value = value.toUtf8().data(); - //extract the list of custom items from the IVariable user data - IVariable::IGetCustomItems* pGetCustomItems = static_cast (pVariable->GetUserData().value()); - if (pGetCustomItems != nullptr) - { - std::vector items; - QString dlgTitle; - // call the user supplied callback to fill-in items and get dialog title - bool bShowIt = pGetCustomItems->GetItems(pVariable, items, dlgTitle); - if (bShowIt) // if func didn't veto, show the dialog - { - m_reflectedVar->m_enableEdit = true; - m_reflectedVar->m_useTree = pGetCustomItems->UseTree(); - m_reflectedVar->m_treeSeparator = pGetCustomItems->GetTreeSeparator(); - m_reflectedVar->m_dialogTitle = dlgTitle.toUtf8().data(); - m_reflectedVar->m_itemNames.resize(items.size()); - m_reflectedVar->m_itemDescriptions.resize(items.size()); - - QByteArray ba; - int i = -1; - std::generate(m_reflectedVar->m_itemNames.begin(), m_reflectedVar->m_itemNames.end(), [&items, &i, &ba]() { ++i; ba = items[i].name.toUtf8(); return ba.data(); }); - i = -1; - std::generate(m_reflectedVar->m_itemDescriptions.begin(), m_reflectedVar->m_itemDescriptions.end(), [&items, &i, &ba]() { ++i; ba = items[i].desc.toUtf8(); return ba.data(); }); - - } - } - else + // extract the list of custom items from the IVariable user data + IVariable::IGetCustomItems* pGetCustomItems = static_cast(pVariable->GetUserData().value()); + if (pGetCustomItems == nullptr) { m_reflectedVar->m_enableEdit = false; + return; } + + std::vector items; + QString dlgTitle; + // call the user supplied callback to fill-in items and get dialog title + bool bShowIt = pGetCustomItems->GetItems(pVariable, items, dlgTitle); + if (!bShowIt) // if func vetoed it, don't show the dialog + { + return; + } + m_reflectedVar->m_enableEdit = true; + m_reflectedVar->m_useTree = pGetCustomItems->UseTree(); + m_reflectedVar->m_treeSeparator = pGetCustomItems->GetTreeSeparator(); + m_reflectedVar->m_dialogTitle = dlgTitle.toUtf8().data(); + m_reflectedVar->m_itemNames.resize(items.size()); + m_reflectedVar->m_itemDescriptions.resize(items.size()); + + QByteArray ba; + int i = -1; + AZStd::generate( + m_reflectedVar->m_itemNames.begin(), m_reflectedVar->m_itemNames.end(), + [&items, &i, &ba]() + { + ++i; + ba = items[i].name.toUtf8(); + return ba.data(); + }); + i = -1; + AZStd::generate( + m_reflectedVar->m_itemDescriptions.begin(), m_reflectedVar->m_itemDescriptions.end(), + [&items, &i, &ba]() + { + ++i; + ba = items[i].desc.toUtf8(); + return ba.data(); + }); } void ReflectedVarUserAdapter::SyncIVarToReflectedVar(IVariable *pVariable) diff --git a/Code/Editor/Controls/TimelineCtrl.cpp b/Code/Editor/Controls/TimelineCtrl.cpp index aa30c326ac..3890b46b2b 100644 --- a/Code/Editor/Controls/TimelineCtrl.cpp +++ b/Code/Editor/Controls/TimelineCtrl.cpp @@ -126,7 +126,6 @@ void TimelineWidget::DrawTicks(QPainter* painter) const QPen pOldPen = painter->pen(); const QPen ltgray(QColor(110, 110, 110)); - const QPen black(palette().color(QPalette::Normal, QPalette::Text)); const QPen redpen(QColor(255, 0, 255)); // Draw time ticks every tick step seconds. @@ -598,7 +597,6 @@ void TimelineWidget::DrawSecondTicks(QPainter* painter) { const QPen ltgray(QColor(110, 110, 110)); const QPen black(palette().color(QPalette::Normal, QPalette::Text)); - const QPen redpen(QColor(255, 0, 255)); for (int gx = m_grid.firstGridLine.x(); gx < m_grid.firstGridLine.x() + m_grid.numGridLines.x() + 1; gx++) { diff --git a/Code/Editor/CryEdit.h b/Code/Editor/CryEdit.h index f68cfdc33d..53ee8f1905 100644 --- a/Code/Editor/CryEdit.h +++ b/Code/Editor/CryEdit.h @@ -431,6 +431,7 @@ public: class CCrySingleDocTemplate : public QObject { + Q_OBJECT private: explicit CCrySingleDocTemplate(const QMetaObject* pDocClass) : QObject() diff --git a/Code/Editor/CustomResolutionDlg.h b/Code/Editor/CustomResolutionDlg.h index 5dd9acaae8..e1b8035c65 100644 --- a/Code/Editor/CustomResolutionDlg.h +++ b/Code/Editor/CustomResolutionDlg.h @@ -12,8 +12,6 @@ // Notice : Refer to ViewportTitleDlg.cpp for a use case. -#ifndef CRYINCLUDE_EDITOR_CUSTOMRESOLUTIONDLG_H -#define CRYINCLUDE_EDITOR_CUSTOMRESOLUTIONDLG_H #pragma once #if !defined(Q_MOC_RUN) @@ -28,6 +26,7 @@ namespace Ui class CCustomResolutionDlg : public QDialog { + Q_OBJECT public: CCustomResolutionDlg(int w, int h, QWidget* pParent = nullptr); ~CCustomResolutionDlg(); @@ -42,5 +41,3 @@ protected: QScopedPointer m_ui; }; - -#endif // CRYINCLUDE_EDITOR_CUSTOMRESOLUTIONDLG_H diff --git a/Code/Editor/CustomizeKeyboardDialog.cpp b/Code/Editor/CustomizeKeyboardDialog.cpp index ce09f8d878..280d6c5323 100644 --- a/Code/Editor/CustomizeKeyboardDialog.cpp +++ b/Code/Editor/CustomizeKeyboardDialog.cpp @@ -211,9 +211,9 @@ public: void Reset(QAction& action) { - emit beginResetModel(); + beginResetModel(); m_action = &action; - emit endResetModel(); + endResetModel(); } private: @@ -266,7 +266,7 @@ QStringList CustomizeKeyboardDialog::BuildModels(QWidget* parent) categories.append(category); QMenu* menu = menuAction->menu(); - m_menuActions[category] = GetAllActionsForMenu(menu, QStringLiteral("")); + m_menuActions[category] = GetAllActionsForMenu(menu, QString()); } return categories; diff --git a/Code/Editor/ErrorDialog.cpp b/Code/Editor/ErrorDialog.cpp index 0a45b2bf89..e43df75947 100644 --- a/Code/Editor/ErrorDialog.cpp +++ b/Code/Editor/ErrorDialog.cpp @@ -25,9 +25,9 @@ namespace SandboxEditor connect(m_ui->okButton, &QPushButton::clicked, this, &ErrorDialog::OnOK); connect( m_ui->messages, - SIGNAL(itemSelectionChanged()), + &QTreeWidget::itemSelectionChanged, this, - SLOT(MessageSelectionChanged())); + &ErrorDialog::MessageSelectionChanged); } ErrorDialog::~ErrorDialog() diff --git a/Code/Editor/KeyboardCustomizationSettings.cpp b/Code/Editor/KeyboardCustomizationSettings.cpp index c4f9133f66..81d9375850 100644 --- a/Code/Editor/KeyboardCustomizationSettings.cpp +++ b/Code/Editor/KeyboardCustomizationSettings.cpp @@ -240,7 +240,7 @@ QJsonObject KeyboardCustomizationSettings::ExportGroup() void KeyboardCustomizationSettings::ImportFromFile(QWidget* parent) { - QString fileName = QFileDialog::getOpenFileName(parent, QObject::tr("Export Keyboard Shortcuts"), QStringLiteral(""), QObject::tr("Keyboard Settings (*.keys)")); + QString fileName = QFileDialog::getOpenFileName(parent, QObject::tr("Export Keyboard Shortcuts"), QString(), QObject::tr("Keyboard Settings (*.keys)")); if (fileName.isEmpty()) { return; diff --git a/Code/Editor/MainStatusBar.cpp b/Code/Editor/MainStatusBar.cpp index f955035bd8..acc7f664df 100644 --- a/Code/Editor/MainStatusBar.cpp +++ b/Code/Editor/MainStatusBar.cpp @@ -419,7 +419,7 @@ void MemoryStatusItem::updateStatus() GeneralStatusItem::GeneralStatusItem(QString name, MainStatusBar* parent) : StatusBarItem(name, parent) { - connect(parent, SIGNAL(messageChanged(QString)), this, SLOT(update())); + connect(parent, &MainStatusBar::messageChanged, this, [this](const QString&) { update(); }); } QString GeneralStatusItem::CurrentText() const diff --git a/Code/Editor/NewLevelDialog.cpp b/Code/Editor/NewLevelDialog.cpp index 29445cef2b..c773acdb6f 100644 --- a/Code/Editor/NewLevelDialog.cpp +++ b/Code/Editor/NewLevelDialog.cpp @@ -100,9 +100,10 @@ CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=nullptr*/) m_level = ""; // First of all, keyboard focus is related to widget tab order, and the default tab order is based on the order in which // widgets are constructed. Therefore, creating more widgets changes the keyboard focus. That is why setFocus() is called last. - // Secondly, using singleShot() allows setFocus() slot of the QLineEdit instance to be invoked right after the event system - // is ready to do so. Therefore, it is better to use singleShot() than directly call setFocus(). - QTimer::singleShot(0, ui->LEVEL, SLOT(OnStartup())); + // in OnStartup() + // Secondly, using singleShot() allows OnStartup() slot of the QLineEdit instance to be invoked right after the event system + // is ready to do so. Therefore, it is better to use singleShot() than directly call OnStartup(). + QTimer::singleShot(0, this, &CNewLevelDialog::OnStartup); ReloadLevelFolder(); } From f40191dd8c2dd626a76d203f24dbe5437f64dec3 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Fri, 29 Oct 2021 02:15:22 -0700 Subject: [PATCH 57/77] bugfix: resolve broken focus for viewport (#5059) Signed-off-by: Michael Pollind --- .../AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp index 5155de3087..0f79e3535d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp @@ -301,6 +301,7 @@ namespace AzToolsFramework::ViewportUi::Internal HighlightBorderSize + ViewportUiOverlayMargin, HighlightBorderSize + ViewportUiOverlayMargin); m_componentModeBorderText.setVisible(true); m_componentModeBorderText.setText(borderTitle.c_str()); + UpdateUiOverlayGeometry(); } void ViewportUiDisplay::RemoveViewportBorder() From ca9093c2028e5e48ebc1e940488dc3585b18e2cb Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 29 Oct 2021 09:20:52 -0700 Subject: [PATCH 58/77] Add engine name, folder and fix refresh crash (#5112) Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Resources/ProjectManager.qss | 8 +++-- .../Source/EngineSettingsScreen.cpp | 32 ++++++++++++++++--- .../Source/EngineSettingsScreen.h | 1 - .../Source/FormBrowseEditWidget.cpp | 5 +-- .../Source/FormBrowseEditWidget.h | 5 ++- .../Source/GemCatalog/GemCatalogScreen.cpp | 2 +- .../Source/GemCatalog/GemModel.cpp | 1 + .../Source/UpdateProjectSettingsScreen.cpp | 1 + 8 files changed, 43 insertions(+), 12 deletions(-) diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index fecdc67920..d3ec066be7 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -242,11 +242,15 @@ QTabBar::tab:focus { /************** Project Settings **************/ #projectSettings { - margin-top:42px; + margin-top:30px; +} + +#projectPreviewLabel { + margin: 10px 0 5px 0; } #projectTemplate { - margin: 55px 0 0 50px; + margin: 25px 0 0 50px; } #projectTemplateLabel { font-size:16px; diff --git a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp index dec1c9a257..c7df00f423 100644 --- a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp @@ -11,19 +11,28 @@ #include #include #include +#include #include #include #include #include +#include namespace O3DE::ProjectManager { EngineSettingsScreen::EngineSettingsScreen(QWidget* parent) : ScreenWidget(parent) { - auto* layout = new QVBoxLayout(); + QScrollArea* scrollArea = new QScrollArea(this); + scrollArea->setWidgetResizable(true); + + QWidget* scrollWidget = new QWidget(this); + scrollArea->setWidget(scrollWidget); + + QVBoxLayout* layout = new QVBoxLayout(scrollWidget); layout->setAlignment(Qt::AlignTop); + scrollWidget->setLayout(layout); setObjectName("engineSettingsScreen"); @@ -39,9 +48,18 @@ namespace O3DE::ProjectManager formTitleLabel->setObjectName("formTitleLabel"); layout->addWidget(formTitleLabel); - m_engineVersion = new FormLineEditWidget(tr("Engine Version"), engineInfo.m_version, this); - m_engineVersion->lineEdit()->setReadOnly(true); - layout->addWidget(m_engineVersion); + FormLineEditWidget* engineName = new FormLineEditWidget(tr("Engine Name"), engineInfo.m_name, this); + engineName->lineEdit()->setReadOnly(true); + layout->addWidget(engineName); + + FormLineEditWidget* engineVersion = new FormLineEditWidget(tr("Engine Version"), engineInfo.m_version, this); + engineVersion->lineEdit()->setReadOnly(true); + layout->addWidget(engineVersion); + + FormBrowseEditWidget* engineFolder = new FormBrowseEditWidget(tr("Engine Folder"), engineInfo.m_path, this); + engineFolder->lineEdit()->setReadOnly(true); + connect( engineFolder, &FormBrowseEditWidget::OnBrowse, [engineInfo]{ AzQtComponents::ShowFileOnDesktop(engineInfo.m_path); }); + layout->addWidget(engineFolder); m_thirdParty = new FormFolderBrowseEditWidget(tr("3rd Party Software Folder"), engineInfo.m_thirdPartyPath, this); m_thirdParty->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this)); @@ -71,7 +89,11 @@ namespace O3DE::ProjectManager connect(m_defaultProjectTemplates->lineEdit(), &QLineEdit::textChanged, this, &EngineSettingsScreen::OnTextChanged); layout->addWidget(m_defaultProjectTemplates); - setLayout(layout); + QVBoxLayout* mainLayout = new QVBoxLayout(); + mainLayout->setAlignment(Qt::AlignTop); + mainLayout->setMargin(0); + mainLayout->addWidget(scrollArea); + setLayout(mainLayout); } ProjectManagerScreen EngineSettingsScreen::GetScreenEnum() diff --git a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h index 2f16400405..1efabd4b5e 100644 --- a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h +++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h @@ -29,7 +29,6 @@ namespace O3DE::ProjectManager void OnTextChanged(); private: - FormLineEditWidget* m_engineVersion; FormBrowseEditWidget* m_thirdParty; FormBrowseEditWidget* m_defaultProjects; FormBrowseEditWidget* m_defaultGems; diff --git a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp index 8cd28fcbb4..fe101cf37a 100644 --- a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp +++ b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp @@ -20,7 +20,8 @@ namespace O3DE::ProjectManager setObjectName("formBrowseEditWidget"); QPushButton* browseButton = new QPushButton(this); - connect(browseButton, &QPushButton::pressed, this, &FormBrowseEditWidget::HandleBrowseButton); + connect( browseButton, &QPushButton::pressed, [this]{ emit OnBrowse(); }); + connect( this, &FormBrowseEditWidget::OnBrowse, this, &FormBrowseEditWidget::HandleBrowseButton); m_frameLayout->addWidget(browseButton); } @@ -34,7 +35,7 @@ namespace O3DE::ProjectManager int key = event->key(); if (key == Qt::Key_Return || key == Qt::Key_Enter) { - HandleBrowseButton(); + emit OnBrowse(); } } diff --git a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h index a1f6948ce9..179fe03253 100644 --- a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h +++ b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h @@ -24,10 +24,13 @@ namespace O3DE::ProjectManager explicit FormBrowseEditWidget(const QString& labelText = "", QWidget* parent = nullptr); ~FormBrowseEditWidget() = default; + signals: + void OnBrowse(); + protected: void keyPressEvent(QKeyEvent* event) override; protected slots: - virtual void HandleBrowseButton() = 0; + virtual void HandleBrowseButton() {}; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 35ea67bdff..98121d7cd2 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -80,7 +80,7 @@ namespace O3DE::ProjectManager void GemCatalogScreen::ReinitForProject(const QString& projectPath) { - m_gemModel->clear(); + m_gemModel->Clear(); m_gemsToRegisterWithProject.clear(); FillModel(projectPath); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 81598f5a6a..fb228c0b4a 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -68,6 +68,7 @@ namespace O3DE::ProjectManager void GemModel::Clear() { clear(); + m_nameToIndexMap.clear(); } void GemModel::UpdateGemDependencies() diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp index 6f7f7e1bed..3bfc07c5b0 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp @@ -36,6 +36,7 @@ namespace O3DE::ProjectManager QLabel* projectPreviewLabel = new QLabel(tr("Select an image (PNG). Minimum %1 x %2 pixels.") .arg(QString::number(ProjectPreviewImageWidth), QString::number(ProjectPreviewImageHeight))); + projectPreviewLabel->setObjectName("projectPreviewLabel"); previewExtrasLayout->addWidget(projectPreviewLabel); m_projectPreviewImage = new QLabel(this); From 971e24285fd11af8a53bce40c40aca0d17318404 Mon Sep 17 00:00:00 2001 From: ffarahmand-DPS Date: Fri, 29 Oct 2021 11:28:42 -0700 Subject: [PATCH 59/77] Fixes debug console's "quit" issues (#4975) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixes a crash caused when attempting to ‘quit’ the launcher from the debug console. The change simply ensures that the underlying font data the OnRenderTick() function relies on has not yet been released from memory. Signed-off-by: ffarahmand-DPS * Fixes a crash caused when attempting to ‘quit’ the launcher from the debug console. An object created on the heap was never deleted, causing a chain reaction. Signed-off-by: ffarahmand-DPS * Some quick clean-up for safety. Signed-off-by: ffarahmand-DPS * Changes !defined(DEDICATED_SERVER) to a runtime check since macro is no longer defined. Signed-off-by: ffarahmand-DPS --- .../CrySystem/ViewSystem/ViewSystem.cpp | 36 ++++++++++++++----- ...AtomViewportDisplayInfoSystemComponent.cpp | 3 +- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Code/Legacy/CrySystem/ViewSystem/ViewSystem.cpp b/Code/Legacy/CrySystem/ViewSystem/ViewSystem.cpp index e83676827f..d7e5c081c0 100644 --- a/Code/Legacy/CrySystem/ViewSystem/ViewSystem.cpp +++ b/Code/Legacy/CrySystem/ViewSystem/ViewSystem.cpp @@ -115,17 +115,20 @@ CViewSystem::CViewSystem(ISystem* pSystem) , m_useDeferredViewSystemUpdate(false) , m_bControlsAudioListeners(true) { -#if !defined(_RELEASE) && !defined(DEDICATED_SERVER) - if (!s_debugCamera) +#if !defined(_RELEASE) + if (!gEnv->IsDedicated()) { - s_debugCamera = new DebugCamera; - } + if (!s_debugCamera) + { + s_debugCamera = new DebugCamera; + } - REGISTER_COMMAND("debugCameraToggle", ToggleDebugCamera, VF_DEV_ONLY, "Toggle the debug camera.\n"); - REGISTER_COMMAND("debugCameraInvertY", ToggleDebugCameraInvertY, VF_DEV_ONLY, "Toggle debug camera Y-axis inversion.\n"); - REGISTER_COMMAND("debugCameraMove", DebugCameraMove, VF_DEV_ONLY, "Move the debug camera the specified distance (x y z).\n"); - gEnv->pConsole->CreateKeyBind("ctrl_keyboard_key_punctuation_backslash", "debugCameraToggle"); - gEnv->pConsole->CreateKeyBind("alt_keyboard_key_punctuation_backslash", "debugCameraInvertY"); + REGISTER_COMMAND("debugCameraToggle", ToggleDebugCamera, VF_DEV_ONLY, "Toggle the debug camera.\n"); + REGISTER_COMMAND("debugCameraInvertY", ToggleDebugCameraInvertY, VF_DEV_ONLY, "Toggle debug camera Y-axis inversion.\n"); + REGISTER_COMMAND("debugCameraMove", DebugCameraMove, VF_DEV_ONLY, "Move the debug camera the specified distance (x y z).\n"); + gEnv->pConsole->CreateKeyBind("ctrl_keyboard_key_punctuation_backslash", "debugCameraToggle"); + gEnv->pConsole->CreateKeyBind("alt_keyboard_key_punctuation_backslash", "debugCameraInvertY"); + } #endif REGISTER_CVAR2("cl_camera_noise", &m_fCameraNoise, -1, 0, @@ -167,6 +170,21 @@ CViewSystem::~CViewSystem() { m_pSystem->GetILevelSystem()->RemoveListener(this); } + +#if !defined(_RELEASE) + if (!gEnv->IsDedicated()) + { + UNREGISTER_COMMAND("debugCameraToggle"); + UNREGISTER_COMMAND("debugCameraInvertY"); + UNREGISTER_COMMAND("debugCameraMove"); + + if (s_debugCamera) + { + delete s_debugCamera; + s_debugCamera = nullptr; + } + } +#endif } //------------------------------------------------------------------------ diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp index 7d659ebb7a..91844c9b2f 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp @@ -130,7 +130,8 @@ namespace AZ::Render } AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext(); - if (!m_fontDrawInterface || !viewportContext || !viewportContext->GetRenderScene()) + if (!m_fontDrawInterface || !viewportContext || !viewportContext->GetRenderScene() || + !AZ::Interface::Get()) { return; } From 0807cb7f3e3c5148f17f60ed602fcd7e2e1ec2bd Mon Sep 17 00:00:00 2001 From: galibzon <66021303+galibzon@users.noreply.github.com> Date: Fri, 29 Oct 2021 15:41:17 -0500 Subject: [PATCH 60/77] Added "RemovePassTemplate" method. (#5039) * Added "RemovePassTemplate" method. Signed-off-by: garrieta * RemovePassTemplate only allows to remove PassTemplates created with the Runtime API. It now asserts if there are Passes referencing the PassTemplate that should be removed. Signed-off-by: garrieta --- .../Code/Include/Atom/RPI.Public/Pass/PassLibrary.h | 10 ++++++++++ .../Code/Include/Atom/RPI.Public/Pass/PassSystem.h | 1 + .../Atom/RPI.Public/Pass/PassSystemInterface.h | 3 +++ .../RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp | 13 +++++++++++++ .../RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp | 5 +++++ 5 files changed, 32 insertions(+) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h index 66c3c205ab..f79da54636 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h @@ -77,6 +77,16 @@ namespace AZ const AZStd::shared_ptr GetPassTemplate(const Name& name) const; const AZStd::vector& GetPassesForTemplate(const Name& templateName) const; + //! Removes a PassTemplate by name, only if the following two conditions are met: + //! 1- The template was NOT created from an Asset. This means the template will be erasable + //! only if it was created at runtime with C++. + //! 2- The are no instantiated Passes referencing such template. + //! If the template exists but both conditions are not met then the function will assert. + //! If a template with the given name doesn't exist the function does nothing. + //! This function should be used judiciously, and under rare circumstances. For example, + //! Applications that iteratively create and need to delete templates at runtime. + void RemovePassTemplate(const Name& name); + //! Removes a pass from both it's associated template (if it has one) and from the pass name mapping void RemovePassFromLibrary(Pass* pass); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h index 8390b0f7e2..6412bf6166 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h @@ -94,6 +94,7 @@ namespace AZ bool HasPassesForTemplateName(const Name& templateName) const override; bool AddPassTemplate(const Name& name, const AZStd::shared_ptr& passTemplate) override; const AZStd::shared_ptr GetPassTemplate(const Name& name) const override; + void RemovePassTemplate(const Name& name) override; void RemovePassFromLibrary(Pass* pass) override; void RegisterPass(Pass* pass) override; void UnregisterPass(Pass* pass) override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h index 7f944df88f..b91a31cfd5 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h @@ -199,6 +199,9 @@ namespace AZ //! Retrieves a PassTemplate from the library virtual const AZStd::shared_ptr GetPassTemplate(const Name& name) const = 0; + //! See remarks in PassLibrary.h for the function with this name. + virtual void RemovePassTemplate(const Name& name) = 0; + //! Removes all references to the given pass from the pass library virtual void RemovePassFromLibrary(Pass* pass) = 0; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp index 6a6f5f3ff9..13b2fa391f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp @@ -236,6 +236,19 @@ namespace AZ return true; } + void PassLibrary::RemovePassTemplate(const Name& name) + { + auto itr = m_templateEntries.find(name); + if (itr != m_templateEntries.end()) + { + AZ_Assert(itr->second.m_passes.empty(), "Can not delete PassTemplate '%s' because there are %zu Passes referencing it", + name.GetCStr(), itr->second.m_passes.size()); + AZ_Assert(!itr->second.m_mappingAssetId.IsValid(), "Can not delete PassTemplate '%s' because it was created from an asset", + name.GetCStr()); + m_templateEntries.erase(itr); + } + } + void PassLibrary::RemovePassFromLibrary(Pass* pass) { if (m_isShuttingDown) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index 7f2948c13a..39d0e879e1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -466,6 +466,11 @@ namespace AZ return m_passLibrary.GetPassTemplate(name); } + void PassSystem::RemovePassTemplate(const Name& name) + { + m_passLibrary.RemovePassTemplate(name); + } + void PassSystem::RemovePassFromLibrary(Pass* pass) { m_passLibrary.RemovePassFromLibrary(pass); From de4658b16ccfd285fe7ad3a334a5e4b53166e2f5 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 29 Oct 2021 14:25:13 -0700 Subject: [PATCH 61/77] Corrects mistake naming the override commands (#5140) * corrects mistake naming the override commands Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * fixes PR comments Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Platform/Common/Install_common.cmake | 4 ++-- cmake/Platform/Mac/Install_mac.cmake | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 6d43661b99..df19ad0e78 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -124,9 +124,9 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar cmake_path(RELATIVE_PATH target_library_output_directory BASE_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} OUTPUT_VARIABLE target_library_output_subdirectory) endif() - if(COMMAND ly_install_target_override) + if(COMMAND ly_setup_target_install_targets_override) # Mac needs special handling because of a cmake issue - ly_install_target_override(TARGET ${TARGET_NAME} + ly_setup_target_install_targets_override(TARGET ${TARGET_NAME} ARCHIVE_DIR ${archive_output_directory} LIBRARY_DIR ${library_output_directory} RUNTIME_DIR ${runtime_output_directory} diff --git a/cmake/Platform/Mac/Install_mac.cmake b/cmake/Platform/Mac/Install_mac.cmake index fe0424f86e..76c381138d 100644 --- a/cmake/Platform/Mac/Install_mac.cmake +++ b/cmake/Platform/Mac/Install_mac.cmake @@ -41,8 +41,8 @@ file(GENERATE configure_file(${LY_ROOT_FOLDER}/cmake/Platform/Mac/PreInstallSteps_mac.cmake.in ${CMAKE_BINARY_DIR}/runtime_install/PreInstallSteps_mac.cmake @ONLY) ly_install(SCRIPT ${CMAKE_BINARY_DIR}/runtime_install/PreInstallSteps_mac.cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) -#! ly_setup_runtime_dependencies_copy_function_override: Mac specific target installation -function(ly_setup_runtime_dependencies_copy_function_override) +#! ly_setup_target_install_targets_override: Mac specific target installation +function(ly_setup_target_install_targets_override) set(options) set(oneValueArgs TARGET ARCHIVE_DIR LIBRARY_DIR RUNTIME_DIR LIBRARY_SUBDIR RUNTIME_SUBDIR) @@ -109,8 +109,8 @@ function(ly_setup_runtime_dependencies_copy_function_override) endif() endfunction() -#! ly_install_code_function_override: Mac specific copy function to handle frameworks -function(ly_install_code_function_override) +#! ly_setup_runtime_dependencies_copy_function_override: Mac specific copy function to handle frameworks +function(ly_setup_runtime_dependencies_copy_function_override) configure_file(${LY_ROOT_FOLDER}/cmake/Platform/Mac/InstallUtils_mac.cmake.in ${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake @ONLY) ly_install_run_script(${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake) From e871dff70ecde0576c4b06ec9b85a51ca8a81e93 Mon Sep 17 00:00:00 2001 From: AMZN-AlexOteiza <82234181+AMZN-AlexOteiza@users.noreply.github.com> Date: Fri, 29 Oct 2021 22:32:33 +0100 Subject: [PATCH 62/77] Added two complex prefab tests (#5089) * Added two complex prefab tests * Fix compile error * Added extra methods, fixed test failure * Addressed PR commments * More PR comments * Fix space * Fix ar error --- .../editor_entity_utils.py | 91 ++++++++++++++++--- .../editor_python_test_tools/prefab_utils.py | 8 ++ .../Gem/PythonTests/Prefab/TestSuite_Main.py | 8 ++ ...ComplexWorflow_CreatePrefabInsidePrefab.py | 57 ++++++++++++ ...omplexWorflow_CreatePrefabOfChildEntity.py | 52 +++++++++++ Code/Editor/CryEdit.cpp | 10 +- .../AzCore/AzCore/Component/TransformBus.h | 5 + .../Components/TransformComponent.cpp | 7 ++ .../Components/TransformComponent.h | 1 + 9 files changed, 223 insertions(+), 16 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabInsidePrefab.py create mode 100644 AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabOfChildEntity.py diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py index 844f8de903..9e857ed8bc 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py @@ -107,6 +107,19 @@ class EditorComponent: return type_ids + +def convert_to_azvector3(xyz) -> azlmbr.math.Vector3: + """ + Converts a vector3-like element into a azlmbr.math.Vector3 + """ + if isinstance(xyz, Tuple) or isinstance(xyz, List): + assert len(xyz) == 3, ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3") + return math.Vector3(float(xyz[0]), float(xyz[1]), float(xyz[2])) + elif isinstance(xyz, type(math.Vector3())): + return xyz + else: + raise ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3") + class EditorEntity: """ Entity class is used to create and interact with Editor Entities. @@ -183,15 +196,6 @@ class EditorEntity: :return: EditorEntity class object """ - def convert_to_azvector3(xyz) -> math.Vector3: - if isinstance(xyz, Tuple) or isinstance(xyz, List): - assert len(xyz) == 3, ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3") - return math.Vector3(*xyz) - elif isinstance(xyz, type(math.Vector3())): - return xyz - else: - raise ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3") - if parent_id is None: parent_id = azlmbr.entity.EntityId() @@ -206,7 +210,7 @@ class EditorEntity: return entity # Methods - def set_name(self, entity_name: str): + def set_name(self, entity_name: str) -> None: """ Given entity_name, sets name to Entity :param: entity_name: Name of the entity to set @@ -324,7 +328,7 @@ class EditorEntity: self.start_status = status return status - def set_start_status(self, desired_start_status: str): + def set_start_status(self, desired_start_status: str) -> None: """ Set an entity as active/inactive at beginning of runtime or it is editor-only, given its entity id and the start status then return set success @@ -382,18 +386,75 @@ class EditorEntity: """ return editor.EditorEntityInfoRequestBus(bus.Event, "IsVisible", self.id) + # World Transform Functions + def get_world_translation(self) -> azlmbr.math.Vector3: + """ + Gets the world translation of the entity + """ + return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", self.id) + + def set_world_translation(self, new_translation) -> None: + """ + Sets the new world translation of the current entity + """ + new_translation = convert_to_azvector3(new_translation) + azlmbr.components.TransformBus(azlmbr.bus.Event, "SetWorldTranslation", self.id, new_translation) + + def get_world_rotation(self) -> azlmbr.math.Quaternion: + """ + Gets the world rotation of the entity + """ + return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldRotation", self.id) + + def set_world_rotation(self, new_rotation): + """ + Sets the new world rotation of the current entity + """ + new_rotation = convert_to_azvector3(new_rotation) + azlmbr.components.TransformBus(azlmbr.bus.Event, "SetWorldRotation", self.id, new_rotation) + + # Local Transform Functions + def get_local_uniform_scale(self) -> float: + """ + Gets the local uniform scale of the entity + """ + return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetLocalUniformScale", self.id) + def set_local_uniform_scale(self, scale_float) -> None: """ - Sets the "SetLocalUniformScale" value on the entity. + Sets the local uniform scale value(relative to the parent) on the entity. :param scale_float: value for "SetLocalUniformScale" to set to. :return: None """ azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", self.id, scale_float) - def set_local_rotation(self, vector3_rotation) -> None: + def get_local_rotation(self) -> azlmbr.math.Quaternion: """ - Sets the "SetLocalRotation" value on the entity. + Gets the local rotation of the entity + """ + return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetLocalRotation", self.id) + + def set_local_rotation(self, new_rotation) -> None: + """ + Sets the set the local rotation(relative to the parent) of the current entity. :param vector3_rotation: The math.Vector3 value to use for rotation on the entity (uses radians). :return: None """ - azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", self.id, vector3_rotation) + new_rotation = convert_to_azvector3(new_rotation) + azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", self.id, new_rotation) + + def get_local_translation(self) -> azlmbr.math.Vector3: + """ + Gets the local translation of the current entity. + :return: The math.Vector3 value of the local translation. + """ + return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetLocalTranslation", self.id) + + def set_local_translation(self, new_translation) -> None: + """ + Sets the local translation(relative to the parent) of the current entity. + :param vector3_translation: The math.Vector3 value to use for translation on the entity. + :return: None + """ + new_translation = convert_to_azvector3(new_translation) + azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalTranslation", self.id, new_translation) diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py index 10a6ab1ef4..76c2a42c0a 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py @@ -138,6 +138,14 @@ class PrefabInstance: self.container_entity = reparented_container_entity current_instance_prefab.instances.add(self) + def get_direct_child_entities(self): + """ + Returns the entities only contained in the current prefab instance. + This function does not return entities contained in other child instances + """ + return self.container_entity.get_children() + + # This is a helper class which contains some of the useful information about a prefab template. class Prefab: diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main.py index 5337f0669c..479915752f 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main.py @@ -55,3 +55,11 @@ class TestAutomation(TestAutomationBase): def test_PrefabBasicWorkflow_CreateAndDuplicatePrefab(self, request, workspace, editor, launcher_platform): from .tests import PrefabBasicWorkflow_CreateAndDuplicatePrefab as test_module self._run_prefab_test(request, workspace, editor, test_module) + + def test_PrefabComplexWorflow_CreatePrefabOfChildEntity(self, request, workspace, editor, launcher_platform): + from .tests import PrefabComplexWorflow_CreatePrefabOfChildEntity as test_module + self._run_prefab_test(request, workspace, editor, test_module, autotest_mode=False) + + def test_PrefabComplexWorflow_CreatePrefabInsidePrefab(self, request, workspace, editor, launcher_platform): + from .tests import PrefabComplexWorflow_CreatePrefabInsidePrefab as test_module + self._run_prefab_test(request, workspace, editor, test_module, autotest_mode=False) diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabInsidePrefab.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabInsidePrefab.py new file mode 100644 index 0000000000..e14fc96449 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabInsidePrefab.py @@ -0,0 +1,57 @@ +""" +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 +""" + +def PrefabComplexWorflow_CreatePrefabInsidePrefab(): + """ + Test description: + - Creates an entity with a physx collider + - Creates a prefab "Outer_prefab" and an instance based of that entity + - Creates a prefab "Inner_prefab" inside "Outer_prefab" based the entity contained inside of it + Checks that the entity is correctly handlded by the prefab system checking the name and that it contains the physx collider + """ + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.prefab_utils import Prefab + + import PrefabTestUtils as prefab_test_utils + + prefab_test_utils.open_base_tests_level() + + # Creates a new Entity at the root level + # Asserts if creation didn't succeed + entity = EditorEntity.create_editor_entity_at((100.0, 100.0, 100.0), name = "TestEntity") + assert entity.id.IsValid(), "Couldn't create entity" + entity.add_component("PhysX Collider") + assert entity.has_component("PhysX Collider"), "Attempted to add a PhysX Collider but no physx collider collider was found afterwards" + + # Create a prefab based on that entity + outer_prefab, outer_instance = Prefab.create_prefab([entity], "Outer_prefab") + # The test should be now inside the outer prefab instance. + entity = outer_instance.get_direct_child_entities()[0] + # We track if that is the same entity by checking the name and if it still contains the component that we created before + assert entity.get_name() == "TestEntity", f"Entity name inside outer_prefab doesn't match the original name, original:'TestEntity' current:'{entity.get_name()}'" + assert entity.has_component("PhysX Collider"), "Entity name inside outer_prefab doesn't have the collider component it should" + + # Now, create another prefab, based on the entity that is inside outer_prefab + inner_prefab, inner_instance = Prefab.create_prefab([entity], "Inner_prefab") + # The test entity should now be inside the inner prefab instance + entity = inner_instance.get_direct_child_entities()[0] + # We track if that is the same entity by checking the name and if it still contains the component that we created before + assert entity.get_name() == "TestEntity", f"Entity name inside inner_prefab doesn't match the original name, original:'TestEntity' current:'{entity.get_name()}'" + assert entity.has_component("PhysX Collider"), "Entity name inside inner_prefab doesn't have the collider component it should" + + # Verify hierarchy of entities: + # Outer_prefab + # |- Inner_prefab + # | |- TestEntity + assert entity.get_parent_id() == inner_instance.container_entity.id + assert inner_instance.container_entity.get_parent_id() == outer_instance.container_entity.id + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(PrefabComplexWorflow_CreatePrefabInsidePrefab) diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabOfChildEntity.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabOfChildEntity.py new file mode 100644 index 0000000000..dec44d52be --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabOfChildEntity.py @@ -0,0 +1,52 @@ +""" +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 +""" + +def PrefabComplexWorflow_CreatePrefabOfChildEntity(): + """ + Test description: + - Creates two entities, parent and child. Child entity has Parent entity as its parent. + - Creates a prefab of the child entity. + Test is successful if the new instanced prefab of the child has the parent entity id + """ + + CAR_PREFAB_FILE_NAME = 'car_prefab' + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.prefab_utils import Prefab + + import PrefabTestUtils as prefab_test_utils + + prefab_test_utils.open_base_tests_level() + + # Creates a new Entity at the root level + # Asserts if creation didn't succeed + parent_entity = EditorEntity.create_editor_entity_at((100.0, 100.0, 100.0)) + assert parent_entity.id.IsValid(), "Couldn't create parent entity" + + child_entity = EditorEntity.create_editor_entity(parent_id=parent_entity.id) + assert child_entity.id.IsValid(), "Couldn't create child entity" + assert child_entity.get_world_translation().IsClose(parent_entity.get_world_translation()), f"Child entity position{child_entity.get_world_translation().ToString()}" \ + f" is not located at the same position as the parent{parent_entity.get_world_translation().ToString()}" + + # Asserts if prefab creation doesn't succeed + child_prefab, child_instance = Prefab.create_prefab([child_entity], CAR_PREFAB_FILE_NAME) + child_entity_on_child_instance = child_instance.get_direct_child_entities()[0] + assert child_instance.container_entity.get_parent_id().IsValid(), "Newly instanced entity has no parent" + assert child_instance.container_entity.get_parent_id() == parent_entity.id, "Newly instanced entity parent does not match the expected parent" + assert child_instance.container_entity.get_world_translation().IsClose(parent_entity.get_world_translation()), "Newly instanced entity position is not located at the same position as the parent" + # Move the parent position, it should update the child position + parent_entity.set_world_translation((200.0, 200.0, 200.0)) + child_instance_translation = child_instance.container_entity.get_world_translation() + assert child_instance_translation.IsClose(azlmbr.math.Vector3(200.0, 200.0, 200.0)), f"Instance position position{child_instance_translation.ToString()} didn't get updated" \ + f" to the same position as the parent{parent_entity.get_world_translation().ToString()}" + child_translation = child_entity_on_child_instance.get_world_translation() + assert child_translation.IsClose(azlmbr.math.Vector3(200.0, 200.0, 200.0)), f"Entity position{child_translation.ToString()} of the instance didn't get updated" \ + f" to the same position as the parent{parent_entity.get_world_translation().ToString()}" + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(PrefabComplexWorflow_CreatePrefabOfChildEntity) diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index e4138da932..0277abe60d 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -4137,7 +4137,15 @@ extern "C" int AZ_DLL_EXPORT CryEditMain(int argc, char* argv[]) AzQtComponents::Utilities::HandleDpiAwareness(AzQtComponents::Utilities::SystemDpiAware); Editor::EditorQtApplication* app = Editor::EditorQtApplication::newInstance(argc, argv); - if (app->arguments().contains("-autotest_mode")) + QStringList qArgs = app->arguments(); + const bool is_automated_test = AZStd::any_of(qArgs.begin(), qArgs.end(), + [](const QString& elem) + { + return elem.endsWith("autotest_mode") || elem.endsWith("runpythontest"); + } + ); + + if (is_automated_test) { // Nullroute all stdout to null for automated tests, this way we make sure // that the test result output is not polluted with unrelated output data. diff --git a/Code/Framework/AzCore/AzCore/Component/TransformBus.h b/Code/Framework/AzCore/AzCore/Component/TransformBus.h index 1af77da51b..f8e30147da 100644 --- a/Code/Framework/AzCore/AzCore/Component/TransformBus.h +++ b/Code/Framework/AzCore/AzCore/Component/TransformBus.h @@ -168,6 +168,11 @@ namespace AZ //! Rotation modifiers //! @{ + //! Set the world rotation matrix using the composition of rotations around + //! the principle axes in the order of z-axis first and y-axis and then x-axis. + //! @param eulerRadianAngles A Vector3 denoting radian angles of the rotations around each principle axis. + virtual void SetWorldRotation([[maybe_unused]] const AZ::Vector3& eulerAnglesRadian) {} + //! Sets the entity's rotation in the world in quaternion notation. //! The origin of the axes is the entity's position in world space. //! @param quaternion A quaternion that represents the rotation to use for the entity. diff --git a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp index 68c4b00243..bc109b73c2 100644 --- a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp @@ -323,6 +323,13 @@ namespace AzFramework return localZ; } + void TransformComponent::SetWorldRotation(const AZ::Vector3& eulerAnglesRadian) + { + AZ::Transform newWorldTransform = m_worldTM; + newWorldTransform.SetRotation(AZ::Quaternion::CreateFromEulerAnglesRadians(eulerAnglesRadian)); + SetWorldTM(newWorldTransform); + } + void TransformComponent::SetWorldRotationQuaternion(const AZ::Quaternion& quaternion) { AZ::Transform newWorldTransform = m_worldTM; diff --git a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.h b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.h index ac282b4d49..2375f28ed1 100644 --- a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.h +++ b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.h @@ -108,6 +108,7 @@ namespace AzFramework float GetLocalZ() override; // Rotation modifiers + void SetWorldRotation(const AZ::Vector3& eulerAnglesRadian) override; void SetWorldRotationQuaternion(const AZ::Quaternion& quaternion) override; AZ::Vector3 GetWorldRotation() override; From 22820b6a90ec11063b1308888972698d260b3c59 Mon Sep 17 00:00:00 2001 From: Mike Chang Date: Fri, 29 Oct 2021 15:13:20 -0700 Subject: [PATCH 63/77] Update snapshots list to stablization/2110 Signed-off-by: Mike Chang --- 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 35f6f9a81c..04e249255f 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -16,7 +16,7 @@ EMPTY_JSON = readJSON text: '{}' ENGINE_REPOSITORY_NAME = 'o3de' // Branches with build snapshots -BUILD_SNAPSHOTS = ['development', 'stabilization/2106'] +BUILD_SNAPSHOTS = ['development', 'stabilization/2110'] // Build snapshots with empty snapshot (for use with 'SNAPSHOT' pipeline paramater) BUILD_SNAPSHOTS_WITH_EMPTY = BUILD_SNAPSHOTS + '' From 1ec34f6123e029cd2a27c3c8003e03db0ac52145 Mon Sep 17 00:00:00 2001 From: Shirang Jia Date: Fri, 29 Oct 2021 21:11:53 -0700 Subject: [PATCH 64/77] Fix typo when calling upload_to_s3.py (#5139) Signed-off-by: shiranj --- 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 35f6f9a81c..e00530d0b7 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -450,7 +450,7 @@ def UploadAPLogs(Map options, String branchName, String jobName, String workspac def command = "${pythonPath} -u ${s3UploadScriptPath} --base_dir ${apLogsPath} " + "--file_regex \".*\" --bucket ${env.AP_LOGS_S3_BUCKET} " + "--search_subdirectories True --key_prefix ${env.JENKINS_JOB_NAME}/${branchName}/${env.BUILD_NUMBER}/${jobName} " + - "--extra-args {\"ACL\": \"bucket-owner-full-control\"}" + "--extra_args {\"ACL\": \"bucket-owner-full-control\"}" palSh(command, "Uploading AP logs for job ${jobName} for branch ${branchName}", false) } } From 8c0dbe4b33ed958fad24835fb34c81efaae65335 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Sat, 30 Oct 2021 12:39:40 -0700 Subject: [PATCH 65/77] missed escaping these variables and breaks runtime dependencines in the install layout (#5149) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Platform/Common/Install_common.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index df19ad0e78..803edb7b1d 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -528,7 +528,7 @@ function(ly_setup_runtime_dependencies) ly_install(CODE "function(ly_copy source_file target_directory) cmake_path(GET source_file FILENAME file_name) - if(NOT EXISTS ${target_directory}/${file_name}) + if(NOT EXISTS \${target_directory}/\${file_name}) file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) endif() endfunction()" From db01d8dddae6bc7aebcb9b8a091dbea557f9619d Mon Sep 17 00:00:00 2001 From: Santi Paprika <44426596+santipaprika@users.noreply.github.com> Date: Mon, 1 Nov 2021 14:47:45 +0000 Subject: [PATCH 66/77] Fix bug timestamp view 'Once per Second' option (#5080) Signed-off-by: Santi Paprika --- Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h | 2 +- Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h index 1bed2b5715..7413390357 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h @@ -249,7 +249,7 @@ namespace AZ // Controls how often the timestamp data is refreshed RefreshType m_refreshType = RefreshType::Realtime; - AZStd::sys_time_t m_lastUpdateTimeMicroSecond; + AZStd::sys_time_t m_lastUpdateTimeMicroSecond = 0; }; diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl index 80dcace2df..405848aa35 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl @@ -651,7 +651,7 @@ namespace AZ if (m_refreshType == RefreshType::OncePerSecond) { auto now = AZStd::GetTimeNowMicroSecond(); - if (m_lastUpdateTimeMicroSecond == 0 || now - m_lastUpdateTimeMicroSecond > 1000000) + if (now - m_lastUpdateTimeMicroSecond > 1000000) { needEnable = true; m_lastUpdateTimeMicroSecond = now; From 2dff26ddb56e5073bafebf451cbe2de1be336cd7 Mon Sep 17 00:00:00 2001 From: Artur K <96597+nemerle@users.noreply.github.com> Date: Mon, 1 Nov 2021 15:51:15 +0100 Subject: [PATCH 67/77] Fix asset type retrieval in AssetCatalogModel::GetAssetType (#4995) * Fix asset type retrieval in AssetCatalogModel::GetAssetType Previous logic would visit the next entry in m_extensionToAssetType map, if the previous entry had multiple types was only exiting the inner loop. The main change is that now the first found matching asset type is returned. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Apply reviewer's suggestions + reduce allocations. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> --- .../UI/AssetCatalogModel.cpp | 64 +++++++++---------- .../UI/AssetCatalogModel.h | 2 +- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp index d0091f968e..df8d6db4a8 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp @@ -197,48 +197,46 @@ AssetCatalogModel::~AssetCatalogModel() AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); } -AZ::Data::AssetType AssetCatalogModel::GetAssetType(QString filename) const +AZ::Data::AssetType AssetCatalogModel::GetAssetType(const QString &filename) const { - AZ::Data::AssetType returnType = AZ::Uuid::CreateNull(); // Compare file extensions with the map created from the asset database. int dotIndex = filename.lastIndexOf('.'); - if (dotIndex >= 0) + if (dotIndex < 0) { - QString extension = filename.mid(dotIndex); - for (auto pair : m_extensionToAssetType) - { - QString qExtensions = pair.first.c_str(); - if (qExtensions.indexOf(extension) >= 0) - { - if (pair.second.size() > 1) - { - // There are multiple types with this extension. Check each handler to see if they can handle this data type. - AZStd::string azFilename = filename.toStdString().c_str(); - EBUS_EVENT(AzFramework::ApplicationRequests::Bus, MakePathAssetRootRelative, azFilename); - AZ::Data::AssetId assetId; - EBUS_EVENT_RESULT(assetId, AZ::Data::AssetCatalogRequestBus, GetAssetIdByPath, azFilename.c_str(), AZ::Data::s_invalidAssetType, false); + return AZ::Uuid::CreateNull(); + } - for (AZ::Uuid type : pair.second) - { - const AZ::Data::AssetHandler* handler = AZ::Data::AssetManager::Instance().GetHandler(type); - if (handler && handler->CanHandleAsset(assetId)) - { - returnType = type; - break; - } - } - } - else - { - returnType = pair.second[0]; - break; - } + QStringRef extension = filename.midRef(dotIndex); + for (const auto& pair : m_extensionToAssetType) + { + QString qExtensions = pair.first.c_str(); + if (qExtensions.indexOf(extension) < 0 || pair.second.empty()) + { + continue; + } + if (pair.second.size() == 1) + { + return pair.second[0]; + } + + // There are multiple types with this extension. Search for a handler that can handle this data type. + AZStd::string azFilename = filename.toStdString().c_str(); + EBUS_EVENT(AzFramework::ApplicationRequests::Bus, MakePathAssetRootRelative, azFilename); + AZ::Data::AssetId assetId; + EBUS_EVENT_RESULT(assetId, AZ::Data::AssetCatalogRequestBus, GetAssetIdByPath, azFilename.c_str(), AZ::Data::s_invalidAssetType, false); + + for (const AZ::Uuid& type : pair.second) + { + const AZ::Data::AssetHandler* handler = AZ::Data::AssetManager::Instance().GetHandler(type); + if (handler && handler->CanHandleAsset(assetId)) + { + return type; } } } - return returnType; + return AZ::Uuid::CreateNull(); } QStandardItem* AssetCatalogModel::GetPath(QString& path, bool createIfNeeded, QStandardItem* parent) @@ -419,7 +417,7 @@ AssetCatalogEntry* AssetCatalogModel::AddAsset(QString assetPath, AZ::Data::Asse // icons' memory being reclaimed and crashing the Editor. QSize size = fileIcon.actualSize(QSize(16, 16)); QIcon deepCopy = fileIcon.pixmap(size).copy(0, 0, size.width(), size.height()); - + if (!fileIcon.isNull()) { m_assetTypeToIcon[assetType] = deepCopy; diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.h index c9143bb259..1dffa81d67 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.h +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.h @@ -110,7 +110,7 @@ protected: void SetFilterRegExp(const AZStd::string& filterType, const QRegExp& regExp); void ClearFilterRegExp(const AZStd::string& filterType = AZStd::string()); - AZ::Data::AssetType GetAssetType(QString filename) const; + AZ::Data::AssetType GetAssetType(const QString &filename) const; QStandardItem* GetPath(QString& path, bool createIfNeeded, QStandardItem* parent = nullptr); void ApplyFilter(QStandardItem* parent); From 43563060bc44689f4bee16aad315d276eee1bb95 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 1 Nov 2021 08:44:22 -0700 Subject: [PATCH 68/77] Making trait variable consistent and fixing warning (#5118) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Gems/PhysX/Code/CMakeLists.txt | 4 ++-- Gems/PhysX/Code/Source/Utils.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/PhysX/Code/CMakeLists.txt b/Gems/PhysX/Code/CMakeLists.txt index c59db45aa7..bb3d7c08a2 100644 --- a/Gems/PhysX/Code/CMakeLists.txt +++ b/Gems/PhysX/Code/CMakeLists.txt @@ -11,7 +11,7 @@ add_subdirectory(NumericalMethods) ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # for PAL_TRAIT_PHYSX_SUPPORTED -set(PHYSX_ENABLE_RUNNING_BENCHMARKS OFF CACHE BOOL "Adds a target to allow running of the physx benchmarks.") +set(LY_PHYSX_ENABLE_RUNNING_BENCHMARKS OFF CACHE BOOL "Adds a target to allow running of the physx benchmarks.") if(PAL_TRAIT_PHYSX_SUPPORTED) set(physx_dependency 3rdParty::PhysX) @@ -197,7 +197,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) # Only add the physx benchmarks if this flag is set. The benchmark code is still built, as it is part of the PhysX.Tests project. # Currently jenkins has a 1500sec(25min) timeout, our benchmarks can sometimes take over 1500sec and cause a build failure for timeout. # Jenkins currently doesn't upload the results of the benchmarks, so this is ok. - if(PHYSX_ENABLE_RUNNING_BENCHMARKS) + if(LY_PHYSX_ENABLE_RUNNING_BENCHMARKS) ly_add_googlebenchmark( NAME Gem::PhysX.Benchmarks TARGET Gem::PhysX.Tests diff --git a/Gems/PhysX/Code/Source/Utils.cpp b/Gems/PhysX/Code/Source/Utils.cpp index 3e77ef257a..fecea57d9c 100644 --- a/Gems/PhysX/Code/Source/Utils.cpp +++ b/Gems/PhysX/Code/Source/Utils.cpp @@ -102,7 +102,7 @@ namespace PhysX const float scaleFactor = (maxHeightBounds <= minHeightBounds) ? 1.0f : AZStd::numeric_limits::max() / halfBounds; const float heightScale{ 1.0f / scaleFactor }; - [[maybe_unused]] const uint8_t physxMaximumMaterialIndex = 0x7f; + [[maybe_unused]] constexpr uint8_t physxMaximumMaterialIndex = 0x7f; // Delete the cached heightfield object if it is there, and create a new one and save in the shape configuration heightfieldConfig.SetCachedNativeHeightfield(nullptr); From 8e420dad3d4efdc2c20fe4b893b2a2a3cd357567 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 1 Nov 2021 08:46:26 -0700 Subject: [PATCH 69/77] Removes some usage of DEDICATED_SERVER (#5119) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Legacy/CrySystem/CrySystem_precompiled.h | 7 ------- .../World/UiCanvasAssetRefComponent.cpp | 19 ++++++++++--------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/Code/Legacy/CrySystem/CrySystem_precompiled.h b/Code/Legacy/CrySystem/CrySystem_precompiled.h index faa924931f..3ececa6514 100644 --- a/Code/Legacy/CrySystem/CrySystem_precompiled.h +++ b/Code/Legacy/CrySystem/CrySystem_precompiled.h @@ -60,13 +60,6 @@ #include -#if defined(WIN32) || defined(WIN64) || defined(APPLE) || defined(LINUX) -#if defined(DEDICATED_SERVER) -// enable/disable map load slicing functionality from the build -#define MAP_LOADING_SLICING -#endif -#endif - #ifdef WIN32 #include #include diff --git a/Gems/LyShine/Code/Source/World/UiCanvasAssetRefComponent.cpp b/Gems/LyShine/Code/Source/World/UiCanvasAssetRefComponent.cpp index d2a307ecaf..59d764f297 100644 --- a/Gems/LyShine/Code/Source/World/UiCanvasAssetRefComponent.cpp +++ b/Gems/LyShine/Code/Source/World/UiCanvasAssetRefComponent.cpp @@ -239,15 +239,16 @@ void UiCanvasAssetRefComponent::Activate() //////////////////////////////////////////////////////////////////////////////////////////////////// void UiCanvasAssetRefComponent::Deactivate() { -#if !defined(DEDICATED_SERVER) - if (m_canvasEntityId.IsValid()) + if (!gEnv->IsDedicated()) { - gEnv->pLyShine->ReleaseCanvasDeferred(m_canvasEntityId); - m_canvasEntityId.SetInvalid(); - } + if (m_canvasEntityId.IsValid()) + { + gEnv->pLyShine->ReleaseCanvasDeferred(m_canvasEntityId); + m_canvasEntityId.SetInvalid(); + } - UiCanvasAssetRefBus::Handler::BusDisconnect(); - UiCanvasRefBus::Handler::BusDisconnect(); - UiCanvasManagerNotificationBus::Handler::BusDisconnect(); -#endif + UiCanvasAssetRefBus::Handler::BusDisconnect(); + UiCanvasRefBus::Handler::BusDisconnect(); + UiCanvasManagerNotificationBus::Handler::BusDisconnect(); + } } From 2cc4f322b7313feba612572f5fa3297ef270c711 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 1 Nov 2021 11:06:04 -0700 Subject: [PATCH 70/77] Skips signing when there is no upload URL (#5120) * Skips signing when there is no upload URL so we can run the scripts locally Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * Fixes prebuild command and improves post build command to not depend on psiexec Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Platform/Windows/PackagingPostBuild.cmake | 78 +++++++++++-------- .../Platform/Windows/PackagingPreBuild.cmake | 38 ++++++--- 2 files changed, 74 insertions(+), 42 deletions(-) diff --git a/cmake/Platform/Windows/PackagingPostBuild.cmake b/cmake/Platform/Windows/PackagingPostBuild.cmake index 377a9fb221..ac457bea87 100644 --- a/cmake/Platform/Windows/PackagingPostBuild.cmake +++ b/cmake/Platform/Windows/PackagingPostBuild.cmake @@ -32,9 +32,6 @@ set(_addtional_defines -dCPACK_RESOURCE_PATH=${CPACK_SOURCE_DIR}/Platform/Windows/Packaging ) -file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) -file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) - if(CPACK_LICENSE_URL) list(APPEND _addtional_defines -dCPACK_LICENSE_URL=${CPACK_LICENSE_URL}) endif() @@ -58,28 +55,41 @@ set(_light_command -o "${_bootstrap_output_file}" ) -set(_signing_command - psexec.exe - -accepteula - -nobanner - -s - powershell.exe - -NoLogo - -ExecutionPolicy Bypass - -File ${_sign_script} -) +if(CPACK_UPLOAD_URL) # Skip signing if we are not uploading the package + file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) + file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) -message(STATUS "Signing package files in ${_cpack_wix_out_dir}") -execute_process( - COMMAND ${_signing_command} -packagePath ${_cpack_wix_out_dir} - RESULT_VARIABLE _signing_result - ERROR_VARIABLE _signing_errors - OUTPUT_VARIABLE _signing_output - ECHO_OUTPUT_VARIABLE -) + unset(_signing_command) + find_program(_psiexec_path psexec.exe) + if(_psiexec_path) + list(APPEND _signing_command + ${_psiexec_path} + -accepteula + -nobanner + -s + ) + endif() -if(NOT ${_signing_result} EQUAL 0) - message(FATAL_ERROR "An error occurred during signing package files. ${_signing_errors}") + find_program(_powershell_path powershell.exe REQUIRED) + list(APPEND _signing_command + ${_powershell_path} + -NoLogo + -ExecutionPolicy Bypass + -File ${_sign_script} + ) + + message(STATUS "Signing package files in ${_cpack_wix_out_dir}") + execute_process( + COMMAND ${_signing_command} -packagePath ${_cpack_wix_out_dir} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE + ) + + if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing package files. ${_signing_errors}") + endif() endif() message(STATUS "Creating Bootstrap Installer...") @@ -107,17 +117,19 @@ file(COPY ${_bootstrap_output_file} message(STATUS "Bootstrap installer generated to ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename}") -message(STATUS "Signing bootstrap installer in ${CPACK_PACKAGE_DIRECTORY}") -execute_process( - COMMAND ${_signing_command} -bootstrapPath ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename} - RESULT_VARIABLE _signing_result - ERROR_VARIABLE _signing_errors - OUTPUT_VARIABLE _signing_output - ECHO_OUTPUT_VARIABLE -) +if(CPACK_UPLOAD_URL) # Skip signing if we are not uploading the package + message(STATUS "Signing bootstrap installer in ${CPACK_PACKAGE_DIRECTORY}") + execute_process( + COMMAND ${_signing_command} -bootstrapPath ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE + ) -if(NOT ${_signing_result} EQUAL 0) - message(FATAL_ERROR "An error occurred during signing bootstrap installer. ${_signing_errors}") + if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing bootstrap installer. ${_signing_errors}") + endif() endif() # use the internal default path if somehow not specified from cpack_configure_downloads diff --git a/cmake/Platform/Windows/PackagingPreBuild.cmake b/cmake/Platform/Windows/PackagingPreBuild.cmake index d3924c7a02..7f2eedf352 100644 --- a/cmake/Platform/Windows/PackagingPreBuild.cmake +++ b/cmake/Platform/Windows/PackagingPreBuild.cmake @@ -6,21 +6,41 @@ # # +if(NOT CPACK_UPLOAD_URL) # Skip signing if we are not uploading the package + return() +endif() + file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) set(_cpack_wix_out_dir ${CPACK_TOPLEVEL_DIRECTORY}) file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) -set(_signing_command - psexec.exe - -accepteula - -nobanner - -s - powershell.exe +unset(_signing_command) +find_program(_psiexec_path psexec.exe) +if(_psiexec_path) + list(APPEND _signing_command + ${_psiexec_path} + -accepteula + -nobanner + -s + ) +endif() + +find_program(_powershell_path powershell.exe REQUIRED) +list(APPEND _signing_command + ${_powershell_path} -NoLogo - -ExecutionPolicy Bypass + -ExecutionPolicy Bypass -File ${_sign_script} ) +# This requires to have a valid local certificate. In continuous integration, these certificates are stored +# in the machine directly. +# You can generate a test certificate to be able to run this in a PowerShell elevated promp with: +# New-SelfSignedCertificate -DnsName foo.o3de.com -Type CodeSigning -CertStoreLocation Cert:\CurrentUser\My +# Export-Certificate -Cert (Get-ChildItem Cert:\CurrentUser\My\) -Filepath "c:\selfsigned.crt" +# Import-Certificate -FilePath "c:\selfsigned.crt" -Cert Cert:\CurrentUser\TrustedPublisher +# Import-Certificate -FilePath "c:\selfsigned.crt" -Cert Cert:\CurrentUser\Root + message(STATUS "Signing executable files in ${_cpack_wix_out_dir}") execute_process( COMMAND ${_signing_command} -exePath ${_cpack_wix_out_dir} @@ -32,6 +52,6 @@ execute_process( if(NOT ${_signing_result} EQUAL 0) message(FATAL_ERROR "An error occurred during signing executable files. ${_signing_errors}") +else() + message(STATUS "Signing exes complete!") endif() - -message(STATUS "Signing exes complete!") From edf5e7a242fd2b3b9853f2d24847ab30465c342f Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 1 Nov 2021 11:06:37 -0700 Subject: [PATCH 71/77] Cleanup of validation script exclusions (#5134) * Validation lists cleanup Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * more cleanup Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../commit_validation/commit_validation.py | 12 ++++-------- .../commit_validation/pal_allowedlist.txt | 3 --- .../validator_data_LEGAL_REVIEW_REQUIRED.py | 14 ++------------ 3 files changed, 6 insertions(+), 23 deletions(-) diff --git a/scripts/commit_validation/commit_validation/commit_validation.py b/scripts/commit_validation/commit_validation/commit_validation.py index b9d992fc9c..513244a735 100755 --- a/scripts/commit_validation/commit_validation/commit_validation.py +++ b/scripts/commit_validation/commit_validation/commit_validation.py @@ -173,16 +173,12 @@ EXCLUDED_VALIDATION_PATTERNS = [ '*/3rdParty/*', '*/__pycache__/*', '*/External/*', - 'build', - 'Cache', - '*/Code/Framework/AzCore/azgnmx/azgnmx/*', - 'Code/Tools/CryFXC', - 'Code/Tools/HLSLCrossCompiler', - 'Code/Tools/HLSLCrossCompilerMETAL', - 'Docs', + 'build', # build artifacts + '*/Cache/*', # Asset processing artifacts + 'install', # install layout artifacts 'python/runtime', + 'restricted/*/Code/Framework/AzCore/azgnmx/azgnmx/*', 'restricted/*/Tools/*RemoteControl', - 'Tools/3dsmax', '*/user/Cache/*', '*/user/log/*', ] diff --git a/scripts/commit_validation/commit_validation/pal_allowedlist.txt b/scripts/commit_validation/commit_validation/pal_allowedlist.txt index 4c90bcb6b4..6fd5aab62e 100644 --- a/scripts/commit_validation/commit_validation/pal_allowedlist.txt +++ b/scripts/commit_validation/commit_validation/pal_allowedlist.txt @@ -23,7 +23,6 @@ */Code/Framework/AzCore/AzCore/std/parallel/binary_semaphore.h */Code/Framework/AzCore/AzCore/std/parallel/semaphore.h */Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h -*/Code/Framework/AzCore/Platform/AppleTV/AzCore/AzCore_Traits_AppleTV.h */Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h */Code/Framework/AzCore/Platform/Jasper/AzCore/AzCore_Traits_Jasper.h */Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h @@ -49,7 +48,6 @@ */Code/Tools/* */Gems/*/3rdParty/* */Gems/*/External/* -*/Gems/CryLegacy* */Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLInclude.h */Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp */Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/PluginManager.cpp @@ -61,4 +59,3 @@ */Gems/SaveData/Code/Tests/SaveDataTest.cpp */Gems/WhiteBox/Code/Source/Rendering/Legacy/WhiteBoxLegacyRenderMesh.cpp */restricted/*/Code/Framework/AzCore/AzCore/AzCore_Traits_*.h -*/Tools/CryDeprecation/precompile_check_defines.h diff --git a/scripts/scrubbing/validator_data_LEGAL_REVIEW_REQUIRED.py b/scripts/scrubbing/validator_data_LEGAL_REVIEW_REQUIRED.py index 666e04a2b0..0c008cbe65 100755 --- a/scripts/scrubbing/validator_data_LEGAL_REVIEW_REQUIRED.py +++ b/scripts/scrubbing/validator_data_LEGAL_REVIEW_REQUIRED.py @@ -100,14 +100,10 @@ def get_prohibited_platforms_for_package(package): def get_bypassed_directories(is_all): # Temporarily exempt folders to not fail validation while people is fixing validation errors, they will be removed once the errors are fixed. temp_bypass_directories = [ - 'commit_validation', - 'LauncherTestTools', - 'AutomatedTesting', - 'Atom' + 'commit_validation' ] bypassed_directories = [ - 'python', - 'AWSPythonSDK' + 'python' ] if not is_all: bypassed_directories.extend([ @@ -116,13 +112,7 @@ def get_bypassed_directories(is_all): 'Cache', 'logs', 'AssetProcessorTemp', - 'JenkinsScripts', - 'BuildLambdaFunctions', - 'layouts', - '.idea', 'user/log', - 'DirectXShaderCompiler', - 'v-hacd', 'External' ]) bypassed_directories.extend(temp_bypass_directories) From c87670bbfb1d294ff9856781d9da39d897adce42 Mon Sep 17 00:00:00 2001 From: Tommy Walton Date: Mon, 1 Nov 2021 11:38:45 -0700 Subject: [PATCH 72/77] Fix innocuous release build error in RPIUtils LoadStreamingTexture (#5021) Signed-off-by: Tommy Walton --- Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp index e70885daa1..fda8f967da 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp @@ -119,7 +119,12 @@ namespace AZ AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown; AzFramework::AssetSystemRequestBus::BroadcastResult( status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, path); - AZ_Error("RPIUtils", status == AzFramework::AssetSystem::AssetStatus_Compiled, "Could not compile image at '%s'", path.data()); + + // When running with no Asset Processor (for example in release), CompileAssetSync will return AssetStatus_Unknown. + AZ_Error( + "RPIUtils", + status == AzFramework::AssetSystem::AssetStatus_Compiled || status == AzFramework::AssetSystem::AssetStatus_Unknown, + "Could not compile image at '%s'", path.data()); Data::AssetId streamingImageAssetId; Data::AssetCatalogRequestBus::BroadcastResult( From 916fb413c93f92d3c4aea46dac4d7908b48a10fa Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon, 1 Nov 2021 16:19:27 -0500 Subject: [PATCH 73/77] Fix Assert Absorber being leaked due to one of the tests setting m_errorAbsorber to nullptr without deleting the object (#5176) Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../AssetProcessor/native/tests/AssetProcessorTest.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Code/Tools/AssetProcessor/native/tests/AssetProcessorTest.h b/Code/Tools/AssetProcessor/native/tests/AssetProcessorTest.h index 258268c182..df40683027 100644 --- a/Code/Tools/AssetProcessor/native/tests/AssetProcessorTest.h +++ b/Code/Tools/AssetProcessor/native/tests/AssetProcessorTest.h @@ -25,7 +25,7 @@ namespace AssetProcessor : public ::testing::Test { protected: - UnitTestUtils::AssertAbsorber* m_errorAbsorber; + AZStd::unique_ptr m_errorAbsorber{}; FileStatePassthrough m_fileStateCache; void SetUp() override @@ -40,7 +40,7 @@ namespace AssetProcessor m_ownsSysAllocator = true; AZ::AllocatorInstance::Create(); } - m_errorAbsorber = new UnitTestUtils::AssertAbsorber(); + m_errorAbsorber = AZStd::make_unique(); m_application = AZStd::make_unique(); @@ -60,8 +60,8 @@ namespace AssetProcessor AssetUtilities::ResetAssetRoot(); m_application.reset(); - delete m_errorAbsorber; - m_errorAbsorber = nullptr; + m_errorAbsorber.reset(); + if (m_ownsSysAllocator) { AZ::AllocatorInstance::Destroy(); From 8da6bea0733aa43c19937fc8ba46d5ab3e514968 Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Mon, 1 Nov 2021 14:26:55 -0700 Subject: [PATCH 74/77] =?UTF-8?q?ATOM-16747=20RPISystemInterface::GetDefau?= =?UTF-8?q?ltScene=20returns=20the=20scene=20crea=E2=80=A6=20(#5153)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ATOM-16747 RPISystemInterface::GetDefaultScene returns the scene created by PreviewRenderer but not the Main Scene Deprecate GetDefaultScene() function. Update all the places which use GetDefaultScene to use Scene::GetFeatureProcessorFromEntityId or GetMainScene. Tested with Editor, UI Editor, Material Editor, game launcher. Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> --- .../Code/Source/BootstrapSystemComponent.cpp | 1 + .../Code/Source/LuxCore/LuxCoreTexture.cpp | 10 +++-- .../Code/Include/Atom/RPI.Public/RPISystem.h | 3 +- .../Atom/RPI.Public/RPISystemInterface.h | 12 ++++-- .../RPI/Code/Include/Atom/RPI.Public/Scene.h | 17 +++++--- .../Atom/RPI.Reflect/System/SceneDescriptor.h | 4 ++ .../RPI/Code/Source/RPI.Public/Culling.cpp | 4 +- .../RPI/Code/Source/RPI.Public/RPISystem.cpp | 41 ++++++++++++++----- .../Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 25 +++++++++-- .../PreviewRenderer/PreviewRenderer.cpp | 1 + .../MaterialEditorViewportInputController.cpp | 4 +- .../RotateEnvironmentBehavior.cpp | 3 +- .../Viewport/MaterialViewportRenderer.cpp | 1 + .../Code/Source/AtomBridgeSystemComponent.cpp | 6 +-- .../AtomDebugDisplayViewportInterface.cpp | 3 +- .../AtomDebugDisplayViewportInterface.h | 2 +- .../AtomLyIntegration/AtomFont/FFont.h | 12 ------ ...eGlobalIlluminationComponentController.cpp | 6 +-- .../Source/Grid/GridComponentController.cpp | 2 +- .../DisplayMapperComponentController.cpp | 3 +- .../SkinnedMesh/SkinnedMeshDebugDisplay.h | 2 +- .../Tools/EMStudio/AnimViewportRenderer.cpp | 4 +- .../Components/BlastSystemComponent.cpp | 25 ++++++----- Gems/LyShine/Code/Source/Draw2d.cpp | 12 +++--- Gems/LyShine/Code/Source/LyShine.cpp | 4 +- Gems/LyShine/Code/Source/UiRenderer.cpp | 13 +++--- Gems/LyShine/Code/Source/UiRenderer.h | 4 +- 27 files changed, 133 insertions(+), 91 deletions(-) diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp index 3f5761270a..ed3241b312 100644 --- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp +++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp @@ -259,6 +259,7 @@ namespace AZ // Create and register a scene with all available feature processors RPI::SceneDescriptor sceneDesc; + sceneDesc.m_nameId = AZ::Name("Main"); AZ::RPI::ScenePtr atomScene = RPI::Scene::CreateScene(sceneDesc); atomScene->EnableAllFeatureProcessors(); atomScene->Activate(); diff --git a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexture.cpp b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexture.cpp index aa906a06f7..1fd8f0d91c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexture.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexture.cpp @@ -32,7 +32,7 @@ namespace AZ { if (m_rtPipeline) { - AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->RemoveRenderPipeline(m_rtPipeline->GetId()); + m_rtPipeline->RemoveFromScene(); m_rtPipeline = nullptr; } @@ -111,8 +111,12 @@ namespace AZ parentPass->SetSourceTexture(m_texture, RHI::Format::R8G8B8A8_UNORM); break; } - - AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->AddRenderPipeline(m_rtPipeline); + + const auto mainScene = AZ::RPI::RPISystemInterface::Get()->GetSceneByName(AZ::Name("RPI")); + if (mainScene) + { + mainScene->AddRenderPipeline(m_rtPipeline); + } } bool LuxCoreTexture::IsIBLTexture() diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h index 4914e4b6fe..92370c5a82 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h @@ -70,7 +70,8 @@ namespace AZ void InitializeSystemAssets() override; void RegisterScene(ScenePtr scene) override; void UnregisterScene(ScenePtr scene) override; - ScenePtr GetScene(const SceneId& sceneId) const override; + Scene* GetScene(const SceneId& sceneId) const override; + Scene* GetSceneByName(const AZ::Name& name) const override; ScenePtr GetDefaultScene() const override; RenderPipelinePtr GetRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle) override; Data::Asset GetCommonShaderAssetForSrgs() const override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h index fe81596bd7..3f30d498cf 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h @@ -13,6 +13,7 @@ #include +#include #include namespace AZ @@ -46,11 +47,14 @@ namespace AZ //! Unregister a scene from RPISystem. The scene won't be simulated or rendered. virtual void UnregisterScene(ScenePtr scene) = 0; - // [GFX TODO] to be removed when we have scene setup in AZ Core - virtual ScenePtr GetDefaultScene() const = 0; - + //! Deprecated. Use GetSceneByName(name), GetSceneForEntityContextId(entityContextId) or Scene::GetSceneForEntityId(AZ::EntityId entityId) instead + AZ_DEPRECATED(virtual ScenePtr GetDefaultScene() const = 0;, "This method has been deprecated. Please use GetSceneByName(name), GetSceneForEntityContextId(entityContextId) or Scene::GetSceneForEntityId(AZ::EntityId entityId) instead."); + //! Get scene by using scene id. - virtual ScenePtr GetScene(const SceneId& sceneId) const = 0; + virtual Scene* GetScene(const SceneId& sceneId) const = 0; + + //! Get scene by using scene name. + virtual Scene* GetSceneByName(const AZ::Name& name) const = 0; //! Get the render pipeline created for a window virtual RenderPipelinePtr GetRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle) = 0; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h index fc81368331..f86383101a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h @@ -80,6 +80,9 @@ namespace AZ //! Gets the RPI::Scene for a given entityContextId. //! May return nullptr if there is no RPI::Scene created for that entityContext. static Scene* GetSceneForEntityContextId(AzFramework::EntityContextId entityContextId); + + //! Gets the RPI::Scene for a given entityId. + static Scene* GetSceneForEntityId(AZ::EntityId entityId); ~Scene(); @@ -135,6 +138,8 @@ namespace AZ const SceneId& GetId() const; + AZ::Name GetName() const; + //! Set default pipeline by render pipeline ID. //! It returns true if the default render pipeline was set from the input ID. //! If the specified render pipeline doesn't exist in this scene then it won't do anything and returns false. @@ -245,6 +250,9 @@ namespace AZ // The uuid to identify this scene. SceneId m_id; + // Scene's name which is set at initialization. Can be empty + AZ::Name m_name; + bool m_activated = false; bool m_taskGraphActive = false; // update during tick, to ensure it only changes on frame boundaries @@ -286,13 +294,10 @@ namespace AZ template FeatureProcessorType* Scene::GetFeatureProcessorForEntity(AZ::EntityId entityId) { - // Find the entity context for the entity ID. - AzFramework::EntityContextId entityContextId = AzFramework::EntityContextId::CreateNull(); - AzFramework::EntityIdContextQueryBus::EventResult(entityContextId, entityId, &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId); - - if (!entityContextId.IsNull()) + RPI::Scene* renderScene = GetSceneForEntityId(entityId); + if (renderScene) { - return GetFeatureProcessorForEntityContextId(entityContextId); + return renderScene->GetFeatureProcessor(); } return nullptr; }; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/System/SceneDescriptor.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/System/SceneDescriptor.h index 2072568d59..eb7a2b6cb7 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/System/SceneDescriptor.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/System/SceneDescriptor.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include @@ -25,6 +26,9 @@ namespace AZ //! List of feature processors which the scene will initially enable. AZStd::vector m_featureProcessorNames; + + //! A name used as scene id. It can be used to search a registered scene via RPISystemInterface::GetScene() + AZ::Name m_nameId; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index 348f0aa57a..ac6b10694e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -699,9 +699,7 @@ namespace AZ m_parentScene = parentScene; AZ_Assert(m_visScene == nullptr, "IVisibilityScene already created for this RPI::Scene"); - char sceneIdBuf[40] = ""; - m_parentScene->GetId().ToString(sceneIdBuf); - AZ::Name visSceneName(AZStd::string::format("RenderCullScene[%s]", sceneIdBuf)); + AZ::Name visSceneName(AZStd::string::format("RenderCullScene[%s]", m_parentScene->GetName().GetCStr())); m_visScene = AZ::Interface::Get()->CreateVisibilityScene(visSceneName); #ifdef AZ_CULL_DEBUG_ENABLED diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp index eb74a81e3e..943966c13b 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp @@ -159,6 +159,11 @@ namespace AZ AZ_Assert(false, "Scene was already registered"); return; } + else if (!scene->GetName().IsEmpty() && scene->GetName() == sceneItem->GetName()) + { + // only report a warning if there is a scene with duplicated name + AZ_Warning("RPISystem", false, "There is a registered scene with same name [%s]", scene->GetName().GetCStr()); + } } m_scenes.push_back(scene); @@ -177,11 +182,35 @@ namespace AZ AZ_Assert(false, "Can't unregister scene which wasn't registered"); } - ScenePtr RPISystem::GetScene(const SceneId& sceneId) const + Scene* RPISystem::GetScene(const SceneId& sceneId) const { for (const auto& scene : m_scenes) { if (scene->GetId() == sceneId) + { + return scene.get(); + } + } + return nullptr; + } + + Scene* RPISystem::GetSceneByName(const AZ::Name& name) const + { + for (const auto& scene : m_scenes) + { + if (scene->GetName() == name) + { + return scene.get(); + } + } + return nullptr; + } + + ScenePtr RPISystem::GetDefaultScene() const + { + for (const auto& scene : m_scenes) + { + if (scene->GetName() == AZ::Name("Main")) { return scene; } @@ -189,16 +218,6 @@ namespace AZ return nullptr; } - ScenePtr RPISystem::GetDefaultScene() const - { - if (m_scenes.size() > 0) - { - return m_scenes[0]; - } - return nullptr; - } - - RenderPipelinePtr RPISystem::GetRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle) { RenderPipelinePtr renderPipeline; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index c5d82c6f29..41fefda656 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -45,7 +45,9 @@ namespace AZ auto shaderAsset = RPISystemInterface::Get()->GetCommonShaderAssetForSrgs(); scene->m_srg = ShaderResourceGroup::Create(shaderAsset, sceneSrgLayout->GetName()); } - + + scene->m_name = sceneDescriptor.m_nameId; + return ScenePtr(scene); } @@ -83,10 +85,23 @@ namespace AZ return nullptr; } + Scene* Scene::GetSceneForEntityId(AZ::EntityId entityId) + { + // Find the entity context for the entity ID. + AzFramework::EntityContextId entityContextId = AzFramework::EntityContextId::CreateNull(); + AzFramework::EntityIdContextQueryBus::EventResult(entityContextId, entityId, &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId); + + if (!entityContextId.IsNull()) + { + return GetSceneForEntityContextId(entityContextId); + } + return nullptr; + } + Scene::Scene() { - m_id = Uuid::CreateRandom(); + m_id = AZ::Uuid::CreateRandom(); m_cullingScene = aznew CullingScene(); SceneRequestBus::Handler::BusConnect(m_id); m_drawFilterTagRegistry = RHI::DrawFilterTagRegistry::Create(); @@ -299,7 +314,6 @@ namespace AZ // Force to update the lookup table since adding render pipeline would effect any pipeline states created before pass system tick RebuildPipelineStatesLookup(); - AZ_Assert(!m_id.IsNull(), "RPI::Scene needs to have a valid uuid."); SceneNotificationBus::Event(m_id, &SceneNotification::OnRenderPipelineAdded, pipeline); } @@ -785,6 +799,11 @@ namespace AZ { return m_id; } + + AZ::Name Scene::GetName() const + { + return m_name; + } bool Scene::SetDefaultRenderPipeline(const RenderPipelineId& pipelineId) { diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp index 2b39a87623..27d468e64b 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp @@ -43,6 +43,7 @@ namespace AtomToolsFramework &PreviewerFeatureProcessorProviderBus::Handler::GetRequiredFeatureProcessors, featureProcessors); AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_nameId = AZ::Name("PreviewRenderer"); sceneDesc.m_featureProcessorNames.assign(featureProcessors.begin(), featureProcessors.end()); m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp index 932e2e7436..1784405ffa 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp @@ -279,9 +279,9 @@ namespace MaterialEditor // reset environment AZ::Transform iblTransform = AZ::Transform::CreateIdentity(); AZ::TransformBus::Event(m_iblEntityId, &AZ::TransformBus::Events::SetLocalTM, iblTransform); + const AZ::Matrix4x4 rotationMatrix = AZ::Matrix4x4::CreateIdentity(); - AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); - auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); + auto skyBoxFeatureProcessorInterface = AZ::RPI::Scene::GetFeatureProcessorForEntity(m_iblEntityId); skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix); if (m_behavior) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/RotateEnvironmentBehavior.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/RotateEnvironmentBehavior.cpp index 21d7dee51b..17fb3f3e52 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/RotateEnvironmentBehavior.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/RotateEnvironmentBehavior.cpp @@ -25,8 +25,7 @@ namespace MaterialEditor m_iblEntityId, &MaterialEditorViewportInputControllerRequestBus::Handler::GetIblEntityId); AZ_Assert(m_iblEntityId.IsValid(), "Failed to find m_iblEntityId"); - AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); - m_skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); + m_skyBoxFeatureProcessorInterface = AZ::RPI::Scene::GetFeatureProcessorForEntity(m_iblEntityId); } void RotateEnvironmentBehavior::TickInternal(float x, float y, float z) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp index 6d6fd377e3..4ad87492e3 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp @@ -67,6 +67,7 @@ namespace MaterialEditor // Create and register a scene with all available feature processors AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_nameId = AZ::Name("MaterialViewport"); m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); m_scene->EnableAllFeatureProcessors(); diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomBridgeSystemComponent.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomBridgeSystemComponent.cpp index b439ac475c..d822b16486 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomBridgeSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomBridgeSystemComponent.cpp @@ -108,7 +108,7 @@ namespace AZ { m_dynamicDrawManager.reset(); AZ::RPI::ViewportContextManagerNotificationsBus::Handler::BusDisconnect(); - RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get(); + RPI::Scene* scene = AZ::RPI::Scene::GetSceneForEntityContextId(m_entityContextId); // Check if scene is emptry since scene might be released already when running AtomSampleViewer if (scene) { @@ -157,9 +157,9 @@ namespace AZ void AtomBridgeSystemComponent::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) { - AZ_UNUSED(bootstrapScene); // Make default AtomDebugDisplayViewportInterface - AZStd::shared_ptr mainEntityDebugDisplay = AZStd::make_shared(AzFramework::g_defaultSceneEntityDebugDisplayId); + AZStd::shared_ptr mainEntityDebugDisplay = + AZStd::make_shared(AzFramework::g_defaultSceneEntityDebugDisplayId, bootstrapScene); m_activeViewportsList[AzFramework::g_defaultSceneEntityDebugDisplayId] = mainEntityDebugDisplay; } diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp index 39d8933863..14f1c5aa0d 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp @@ -256,12 +256,11 @@ namespace AZ::AtomBridge viewportContextPtr->ConnectSceneChangedHandler(m_sceneChangeHandler); } - AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress) + AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress, RPI::Scene* scene) { ResetRenderState(); m_viewportId = defaultInstanceAddress; m_defaultInstance = true; - RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get(); InitInternal(scene, nullptr); } diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h index 07f4efdf50..5f902c5884 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h @@ -124,7 +124,7 @@ namespace AZ::AtomBridge AZ_RTTI(AtomDebugDisplayViewportInterface, "{09AF6A46-0100-4FBF-8F94-E6B221322D14}", AzFramework::DebugDisplayRequestBus::Handler); explicit AtomDebugDisplayViewportInterface(AZ::RPI::ViewportContextPtr viewportContextPtr); - explicit AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress); + explicit AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress, RPI::Scene* scene); ~AtomDebugDisplayViewportInterface(); void ResetRenderState(); diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h index 2cc8a67cfa..ff6ad7c151 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h +++ b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h @@ -133,18 +133,6 @@ namespace AZ typedef std::vector FontEffects; typedef FontEffects::iterator FontEffectsIterator; - struct FontPipelineStateMapKey - { - AZ::RPI::SceneId m_sceneId; // which scene pipeline state is attached to (via Render Pipeline) - AZ::RHI::DrawListTag m_drawListTag; // which render pass this pipeline draws in by default - - bool operator<(const FontPipelineStateMapKey& other) const - { - return m_sceneId < other.m_sceneId - || (m_sceneId == other.m_sceneId && m_drawListTag < other.m_drawListTag); - } - }; - struct FontShaderData { AZ::RHI::ShaderInputNameIndex m_imageInputIndex = "m_texture"; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp index ee322c8afd..e844219811 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp @@ -48,11 +48,7 @@ namespace AZ void DiffuseGlobalIlluminationComponentController::Activate(EntityId entityId) { - AZ_UNUSED(entityId); - - const RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get(); - m_featureProcessor = scene->GetFeatureProcessor(); - + m_featureProcessor = AZ::RPI::Scene::GetFeatureProcessorForEntity(entityId); OnConfigChanged(); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp index b4131894f4..2611021359 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp @@ -79,7 +79,7 @@ namespace AZ m_entityId = entityId; m_dirty = true; - RPI::ScenePtr scene = RPI::RPISystemInterface::Get()->GetDefaultScene(); + RPI::Scene* scene = RPI::Scene::GetSceneForEntityId(m_entityId); if (scene) { AZ::RPI::SceneNotificationBus::Handler::BusConnect(scene->GetId()); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp index e86c909121..a0577c6240 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp @@ -357,8 +357,7 @@ namespace AZ void DisplayMapperComponentController::OnConfigChanged() { // Register the configuration with the AcesDisplayMapperFeatureProcessor for this scene. - const AZ::RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get(); - DisplayMapperFeatureProcessorInterface* fp = scene->GetFeatureProcessor(); + DisplayMapperFeatureProcessorInterface* fp = AZ::RPI::Scene::GetFeatureProcessorForEntity(m_entityId); DisplayMapperConfigurationDescriptor desc; desc.m_operationType = m_configuration.m_displayMapperOperation; desc.m_ldrGradingLutEnabled = m_configuration.m_ldrColorGradingLutEnabled; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkinnedMesh/SkinnedMeshDebugDisplay.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkinnedMesh/SkinnedMeshDebugDisplay.h index e789b6dc80..5b060198dc 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkinnedMesh/SkinnedMeshDebugDisplay.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkinnedMesh/SkinnedMeshDebugDisplay.h @@ -48,7 +48,7 @@ namespace AZ // CVar for toggling the display of the scene stats int r_skinnedMeshDisplaySceneStats = 0; // SceneId to query for the stats - RPI::SceneId m_sceneId = RPI::SceneId::CreateNull(); + RPI::SceneId m_sceneId; }; }// namespace Render }// namespace AZ diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index facf7a7b12..1d62e61b0a 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -60,6 +60,7 @@ namespace EMStudio // Create and register a scene with all available feature processors AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_nameId = AZ::Name("AnimViewport"); m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); m_scene->EnableAllFeatureProcessors(); @@ -227,8 +228,7 @@ namespace EMStudio AZ::TransformBus::Event(m_iblEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, iblTransform); const AZ::Matrix4x4 rotationMatrix = AZ::Matrix4x4::CreateIdentity(); - AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); - auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); + auto skyBoxFeatureProcessorInterface = m_scene->GetFeatureProcessor(); skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix); } diff --git a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp index 00629eb65d..4c0f15463a 100644 --- a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp +++ b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp @@ -255,19 +255,22 @@ namespace Blast BlastFamilyComponentRequestBus::Broadcast( &BlastFamilyComponentRequests::FillDebugRenderBuffer, buffer, m_debugRenderMode); - // This is a system component, and thus is not associated with a specific scene, so use the default scene + // This is a system component, and thus is not associated with a specific scene, so use the bootstrap scene // for the debug drawing - const auto defaultScene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); - auto drawQueue = AZ::RPI::AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(defaultScene); - - for (DebugLine& line : buffer.m_lines) + const auto mainScene = AZ::RPI::RPISystemInterface::Get()->GetSceneByName(AZ::Name("Main")); + if (mainScene) { - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArguments; - drawArguments.m_verts = &line.m_p0; - drawArguments.m_vertCount = 2; - drawArguments.m_colors = &line.m_color; - drawArguments.m_colorCount = 1; - drawQueue->DrawLines(drawArguments); + auto drawQueue = AZ::RPI::AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(mainScene); + + for (DebugLine& line : buffer.m_lines) + { + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArguments; + drawArguments.m_verts = &line.m_p0; + drawArguments.m_vertCount = 2; + drawArguments.m_colors = &line.m_color; + drawArguments.m_colorCount = 1; + drawQueue->DrawLines(drawArguments); + } } } } diff --git a/Gems/LyShine/Code/Source/Draw2d.cpp b/Gems/LyShine/Code/Source/Draw2d.cpp index b0539900e2..3476c530b2 100644 --- a/Gems/LyShine/Code/Source/Draw2d.cpp +++ b/Gems/LyShine/Code/Source/Draw2d.cpp @@ -65,7 +65,7 @@ CDraw2d::~CDraw2d() } //////////////////////////////////////////////////////////////////////////////////////////////////// -void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene) +void CDraw2d::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) { // At this point the RPI is ready for use @@ -74,16 +74,16 @@ void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapSc AZ::Data::Instance shader = AZ::RPI::LoadCriticalShader(shaderFilepath); // Set scene to be associated with the dynamic draw context - AZ::RPI::ScenePtr scene; + AZ::RPI::Scene* scene = nullptr; if (m_viewportContext) { // Use scene associated with the specified viewport context - scene = m_viewportContext->GetRenderScene(); + scene = m_viewportContext->GetRenderScene().get(); } else { - // No viewport context specified, use default scene - scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); + // No viewport context specified, use main scene + scene = bootstrapScene; } AZ_Assert(scene != nullptr, "Attempting to create a DynamicDrawContext for a viewport context that has not been associated with a scene yet."); @@ -113,7 +113,7 @@ void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapSc else { // Render target support is disabled - m_dynamicDraw->SetOutputScope(scene.get()); + m_dynamicDraw->SetOutputScope(scene); } m_dynamicDraw->EndInit(); diff --git a/Gems/LyShine/Code/Source/LyShine.cpp b/Gems/LyShine/Code/Source/LyShine.cpp index 2cee4e92eb..19c6e4281e 100644 --- a/Gems/LyShine/Code/Source/LyShine.cpp +++ b/Gems/LyShine/Code/Source/LyShine.cpp @@ -653,12 +653,12 @@ void CLyShine::OnRenderTick() } //////////////////////////////////////////////////////////////////////////////////////////////////// -void CLyShine::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene) +void CLyShine::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) { // Load cursor if its path was set before RPI was initialized LoadUiCursor(); - LyShinePassDataRequestBus::Handler::BusConnect(AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->GetId()); + LyShinePassDataRequestBus::Handler::BusConnect(bootstrapScene->GetId()); } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/LyShine/Code/Source/UiRenderer.cpp b/Gems/LyShine/Code/Source/UiRenderer.cpp index 3111f31615..98b376ec8b 100644 --- a/Gems/LyShine/Code/Source/UiRenderer.cpp +++ b/Gems/LyShine/Code/Source/UiRenderer.cpp @@ -52,7 +52,7 @@ bool UiRenderer::IsReady() return m_isRPIReady; } -void UiRenderer::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene) +void UiRenderer::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) { // At this point the RPI is ready for use @@ -64,16 +64,17 @@ void UiRenderer::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstra if (m_viewportContext) { // Create a new scene based on the user specified viewport context - m_scene = CreateScene(m_viewportContext); + m_ownedScene = CreateScene(m_viewportContext); + m_scene = m_ownedScene.get(); } else { // No viewport context specified, use default scene - m_scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); + m_scene = bootstrapScene; } // Create a dynamic draw context for UI Canvas drawing for the scene - m_dynamicDraw = CreateDynamicDrawContext(m_scene, uiShader); + m_dynamicDraw = CreateDynamicDrawContext(uiShader); if (m_dynamicDraw) { @@ -93,6 +94,7 @@ AZ::RPI::ScenePtr UiRenderer::CreateScene(AZStd::shared_ptrEnableAllFeatureProcessors(); // LYSHINE_ATOM_TODO - have a UI pipeline and enable only needed fps @@ -116,7 +118,6 @@ AZ::RPI::ScenePtr UiRenderer::CreateScene(AZStd::shared_ptr UiRenderer::CreateDynamicDrawContext( - AZ::RPI::ScenePtr scene, AZ::Data::Instance uiShader) { // Find the pass that renders the UI canvases after the rtt passes @@ -144,7 +145,7 @@ AZ::RHI::Ptr UiRenderer::CreateDynamicDrawContext( else { // Render target support is disabled - dynamicDraw->SetOutputScope(m_scene.get()); + dynamicDraw->SetOutputScope(m_scene); } dynamicDraw->EndInit(); diff --git a/Gems/LyShine/Code/Source/UiRenderer.h b/Gems/LyShine/Code/Source/UiRenderer.h index 3be3c832d3..0e15d41907 100644 --- a/Gems/LyShine/Code/Source/UiRenderer.h +++ b/Gems/LyShine/Code/Source/UiRenderer.h @@ -152,7 +152,6 @@ private: // member functions //! Create a dynamic draw context for this renderer AZ::RHI::Ptr CreateDynamicDrawContext( - AZ::RPI::ScenePtr scene, AZ::Data::Instance uiShader); //! Bind the global white texture for all the texture units we use @@ -175,7 +174,8 @@ protected: // attributes // Set by user when viewport context is not the main/default viewport AZStd::shared_ptr m_viewportContext; - AZ::RPI::ScenePtr m_scene; + AZ::RPI::ScenePtr m_ownedScene; + AZ::RPI::Scene* m_scene = nullptr; #ifndef _RELEASE int m_debugTextureDataRecordLevel = 0; From 6862b52069821a6ecfb422d2c9a3fa3d621ead44 Mon Sep 17 00:00:00 2001 From: chiyenteng <82238204+chiyenteng@users.noreply.github.com> Date: Mon, 1 Nov 2021 14:27:22 -0700 Subject: [PATCH 75/77] Convert several physics automated tests with Base test level file converted to prefab file (#5138) * Convert some physics automated tests to use prefab system Signed-off-by: chiyteng * revert changes Signed-off-by: chiyteng * Fix file names Signed-off-by: chiyteng --- .../Physics/TestSuite_Main_Optimized.py | 30 +++++++---- .../PythonTests/Physics/TestSuite_Periodic.py | 21 ++++---- ...ditting.py => Collider_BoxShapeEditing.py} | 6 +-- ...ing.py => Collider_CapsuleShapeEditing.py} | 6 +-- ...ting.py => Collider_SphereShapeEditing.py} | 6 +-- AutomatedTesting/Levels/Base/Base.prefab | 53 +++++++++++++++++++ 6 files changed, 95 insertions(+), 27 deletions(-) rename AutomatedTesting/Gem/PythonTests/Physics/tests/collider/{Collider_BoxShapeEditting.py => Collider_BoxShapeEditing.py} (97%) rename AutomatedTesting/Gem/PythonTests/Physics/tests/collider/{Collider_CapsuleShapeEditting.py => Collider_CapsuleShapeEditing.py} (97%) rename AutomatedTesting/Gem/PythonTests/Physics/tests/collider/{Collider_SphereShapeEditting.py => Collider_SphereShapeEditing.py} (96%) create mode 100644 AutomatedTesting/Levels/Base/Base.prefab diff --git a/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Main_Optimized.py index 63d3b58249..3d668a2085 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Main_Optimized.py @@ -53,6 +53,27 @@ class EditorSingleTest_WithFileOverrides(EditorSingleTest): for f in original_file_list: fm._restore_file(f, file_list[f]) +@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.") +@pytest.mark.SUITE_main +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomationWithPrefabSystemEnabled(EditorTestSuite): + + global_extra_cmdline_args = ['-BatchMode', '-autotest_mode', + 'extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"]'] + + @staticmethod + def get_number_parallel_editors(): + return 16 + + class C4982801_PhysXColliderShape_CanBeSelected(EditorSharedTest): + from .tests.collider import Collider_BoxShapeEditing as test_module + + class C4982800_PhysXColliderShape_CanBeSelected(EditorSharedTest): + from .tests.collider import Collider_SphereShapeEditing as test_module + + class C4982802_PhysXColliderShape_CanBeSelected(EditorSharedTest): + from .tests.collider import Collider_CapsuleShapeEditing as test_module @pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.") @pytest.mark.SUITE_main @@ -286,15 +307,6 @@ class TestAutomation(EditorTestSuite): class C19723164_ShapeCollider_WontCrashEditor(EditorSharedTest): from .tests.shape_collider import ShapeCollider_LargeNumberOfShapeCollidersWontCrashEditor as test_module - class C4982800_PhysXColliderShape_CanBeSelected(EditorSharedTest): - from .tests.collider import Collider_SphereShapeEditting as test_module - - class C4982801_PhysXColliderShape_CanBeSelected(EditorSharedTest): - from .tests.collider import Collider_BoxShapeEditting as test_module - - class C4982802_PhysXColliderShape_CanBeSelected(EditorSharedTest): - from .tests.collider import Collider_CapsuleShapeEditting as test_module - class C12905528_ForceRegion_WithNonTriggerCollider(EditorSharedTest): from .tests.force_region import ForceRegion_WithNonTriggerColliderWarning as test_module # Fixme: expected_lines = ["[Warning] (PhysX Force Region) - Please ensure collider component marked as trigger exists in entity"] diff --git a/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py b/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py index e5dd9adbb9..55e51dd2f8 100755 --- a/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py @@ -401,19 +401,22 @@ class TestAutomation(TestAutomationBase): self._run_test(request, workspace, editor, test_module) @revert_physics_config - def test_Collider_SphereShapeEditting(self, request, workspace, editor, launcher_platform): - from .tests.collider import Collider_SphereShapeEditting as test_module - self._run_test(request, workspace, editor, test_module) + def test_Collider_SphereShapeEditing(self, request, workspace, editor, launcher_platform): + from .tests.collider import Collider_SphereShapeEditing as test_module + self._run_test(request, workspace, editor, test_module, + extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"]) @revert_physics_config - def test_Collider_BoxShapeEditting(self, request, workspace, editor, launcher_platform): - from .tests.collider import Collider_BoxShapeEditting as test_module - self._run_test(request, workspace, editor, test_module) + def test_Collider_BoxShapeEditing(self, request, workspace, editor, launcher_platform): + from .tests.collider import Collider_BoxShapeEditing as test_module + self._run_test(request, workspace, editor, test_module, + extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"]) @revert_physics_config - def test_Collider_CapsuleShapeEditting(self, request, workspace, editor, launcher_platform): - from .tests.collider import Collider_CapsuleShapeEditting as test_module - self._run_test(request, workspace, editor, test_module) + def test_Collider_CapsuleShapeEditing(self, request, workspace, editor, launcher_platform): + from .tests.collider import Collider_CapsuleShapeEditing as test_module + self._run_test(request, workspace, editor, test_module, + extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"]) def test_ForceRegion_WithNonTriggerColliderWarning(self, request, workspace, editor, launcher_platform): from .tests.force_region import ForceRegion_WithNonTriggerColliderWarning as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_BoxShapeEditting.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_BoxShapeEditing.py similarity index 97% rename from AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_BoxShapeEditting.py rename to AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_BoxShapeEditing.py index 68ff0b4edc..a6730c8559 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_BoxShapeEditting.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_BoxShapeEditing.py @@ -19,7 +19,7 @@ class Tests(): # fmt: on -def Collider_BoxShapeEditting(): +def Collider_BoxShapeEditing(): """ Summary: Adding PhysX Collider and Shape components to test entity, then attempting to modify the shape's dimensions @@ -73,7 +73,7 @@ def Collider_BoxShapeEditting(): helper.init_idle() # 1) Load the empty level - helper.open_level("Physics", "Base") + helper.open_level("", "Base") # 2) Create the test entity test_entity = Entity.create_editor_entity("Test Entity") @@ -102,4 +102,4 @@ def Collider_BoxShapeEditting(): if __name__ == "__main__": from editor_python_test_tools.utils import Report - Report.start_test(Collider_BoxShapeEditting) + Report.start_test(Collider_BoxShapeEditing) diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_CapsuleShapeEditting.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_CapsuleShapeEditing.py similarity index 97% rename from AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_CapsuleShapeEditting.py rename to AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_CapsuleShapeEditing.py index 7df12c68f0..12435cc54a 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_CapsuleShapeEditting.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_CapsuleShapeEditing.py @@ -19,7 +19,7 @@ class Tests(): # fmt: on -def Collider_CapsuleShapeEditting(): +def Collider_CapsuleShapeEditing(): """ Summary: Adding PhysX Collider and Shape components to test entity, then attempting to modify the shape's dimensions @@ -74,7 +74,7 @@ def Collider_CapsuleShapeEditting(): helper.init_idle() # 1) Load the empty level - helper.open_level("Physics", "Base") + helper.open_level("", "Base") # 2) Create the test entity test_entity = Entity.create_editor_entity("Test Entity") @@ -102,4 +102,4 @@ def Collider_CapsuleShapeEditting(): if __name__ == "__main__": from editor_python_test_tools.utils import Report - Report.start_test(Collider_CapsuleShapeEditting) + Report.start_test(Collider_CapsuleShapeEditing) diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SphereShapeEditting.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SphereShapeEditing.py similarity index 96% rename from AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SphereShapeEditting.py rename to AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SphereShapeEditing.py index bffd041d92..ef91235411 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SphereShapeEditting.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SphereShapeEditing.py @@ -19,7 +19,7 @@ class Tests(): # fmt: on -def Collider_SphereShapeEditting(): +def Collider_SphereShapeEditing(): """ Summary: Adding PhysX Collider and Shape components to test entity, then attempting to modify the shape's dimensions @@ -57,7 +57,7 @@ def Collider_SphereShapeEditting(): helper.init_idle() # 1) Load the empty level - helper.open_level("Physics", "Base") + helper.open_level("", "Base") # 2) Create the test entity test_entity = Entity.create_editor_entity("Test Entity") @@ -90,4 +90,4 @@ def Collider_SphereShapeEditting(): if __name__ == "__main__": from editor_python_test_tools.utils import Report - Report.start_test(Collider_SphereShapeEditting) + Report.start_test(Collider_SphereShapeEditing) diff --git a/AutomatedTesting/Levels/Base/Base.prefab b/AutomatedTesting/Levels/Base/Base.prefab new file mode 100644 index 0000000000..98495663b7 --- /dev/null +++ b/AutomatedTesting/Levels/Base/Base.prefab @@ -0,0 +1,53 @@ +{ + "ContainerEntity": { + "Id": "ContainerEntity", + "Name": "Base", + "Components": { + "Component_[10182366347512475253]": { + "$type": "EditorPrefabComponent", + "Id": 10182366347512475253 + }, + "Component_[12917798267488243668]": { + "$type": "EditorPendingCompositionComponent", + "Id": 12917798267488243668 + }, + "Component_[3261249813163778338]": { + "$type": "EditorOnlyEntityComponent", + "Id": 3261249813163778338 + }, + "Component_[3837204912784440039]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 3837204912784440039 + }, + "Component_[4272963378099646759]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 4272963378099646759, + "Parent Entity": "" + }, + "Component_[4848458548047175816]": { + "$type": "EditorVisibilityComponent", + "Id": 4848458548047175816 + }, + "Component_[5787060997243919943]": { + "$type": "EditorInspectorComponent", + "Id": 5787060997243919943 + }, + "Component_[7804170251266531779]": { + "$type": "EditorLockComponent", + "Id": 7804170251266531779 + }, + "Component_[7874177159288365422]": { + "$type": "EditorEntitySortComponent", + "Id": 7874177159288365422 + }, + "Component_[8018146290632383969]": { + "$type": "EditorEntityIconComponent", + "Id": 8018146290632383969 + }, + "Component_[8452360690590857075]": { + "$type": "SelectionComponent", + "Id": 8452360690590857075 + } + } + } +} \ No newline at end of file From 96159c1e3a7614b43e512c22477073e2dde71b14 Mon Sep 17 00:00:00 2001 From: Vincent Liu <5900509+onecent1101@users.noreply.github.com> Date: Mon, 1 Nov 2021 14:52:40 -0700 Subject: [PATCH 76/77] Add missing exclamation mark for documentation (#5144) * Add missing exclamation mark for documentation Signed-off-by: onecent1101 * Add more Signed-off-by: onecent1101 --- .../Matchmaking/IMatchmakingRequests.h | 34 ++++++------- .../Matchmaking/MatchmakingNotifications.h | 10 ++-- .../Matchmaking/MatchmakingRequests.h | 10 ++-- .../Session/ISessionHandlingRequests.h | 44 ++++++++--------- .../AzFramework/Session/ISessionRequests.h | 48 +++++++++---------- .../AzFramework/Session/SessionConfig.h | 28 +++++------ .../Session/SessionNotifications.h | 48 +++++++++---------- .../AzFramework/Session/SessionRequests.h | 28 +++++------ .../AWSGameLiftCreateSessionOnQueueRequest.h | 6 +-- .../Request/AWSGameLiftCreateSessionRequest.h | 8 ++-- .../AWSGameLiftSearchSessionsRequest.h | 6 +-- .../AWSGameLiftStartMatchmakingRequest.h | 5 +- 12 files changed, 138 insertions(+), 137 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h b/Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h index c657e0edc7..ccf9acdf8b 100644 --- a/Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h +++ b/Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h @@ -24,17 +24,17 @@ namespace AzFramework IMatchmakingRequests() = default; virtual ~IMatchmakingRequests() = default; - // Registers a player's acceptance or rejection of a proposed matchmaking. - // @param acceptMatchRequest The request of AcceptMatch operation + //! Registers a player's acceptance or rejection of a proposed matchmaking. + //! @param acceptMatchRequest The request of AcceptMatch operation virtual void AcceptMatch(const AcceptMatchRequest& acceptMatchRequest) = 0; - // Create a game match for a group of players. - // @param startMatchmakingRequest The request of StartMatchmaking operation - // @return A unique identifier for a matchmaking ticket + //! Create a game match for a group of players. + //! @param startMatchmakingRequest The request of StartMatchmaking operation + //! @return A unique identifier for a matchmaking ticket virtual AZStd::string StartMatchmaking(const StartMatchmakingRequest& startMatchmakingRequest) = 0; - // Cancels a matchmaking ticket that is currently being processed. - // @param stopMatchmakingRequest The request of StopMatchmaking operation + //! Cancels a matchmaking ticket that is currently being processed. + //! @param stopMatchmakingRequest The request of StopMatchmaking operation virtual void StopMatchmaking(const StopMatchmakingRequest& stopMatchmakingRequest) = 0; }; @@ -48,16 +48,16 @@ namespace AzFramework IMatchmakingAsyncRequests() = default; virtual ~IMatchmakingAsyncRequests() = default; - // AcceptMatch Async - // @param acceptMatchRequest The request of AcceptMatch operation + //! AcceptMatch Async + //! @param acceptMatchRequest The request of AcceptMatch operation virtual void AcceptMatchAsync(const AcceptMatchRequest& acceptMatchRequest) = 0; - // StartMatchmaking Async - // @param startMatchmakingRequest The request of StartMatchmaking operation + //! StartMatchmaking Async + //! @param startMatchmakingRequest The request of StartMatchmaking operation virtual void StartMatchmakingAsync(const StartMatchmakingRequest& startMatchmakingRequest) = 0; - // StopMatchmaking Async - // @param stopMatchmakingRequest The request of StopMatchmaking operation + //! StopMatchmaking Async + //! @param stopMatchmakingRequest The request of StopMatchmaking operation virtual void StopMatchmakingAsync(const StopMatchmakingRequest& stopMatchmakingRequest) = 0; }; @@ -76,14 +76,14 @@ namespace AzFramework static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; ////////////////////////////////////////////////////////////////////////// - // OnAcceptMatchAsyncComplete is fired once AcceptMatchAsync completes + //! OnAcceptMatchAsyncComplete is fired once AcceptMatchAsync completes virtual void OnAcceptMatchAsyncComplete() = 0; - // OnStartMatchmakingAsyncComplete is fired once StartMatchmakingAsync completes - // @param matchmakingTicketId The unique identifier for the matchmaking ticket + //! OnStartMatchmakingAsyncComplete is fired once StartMatchmakingAsync completes + //! @param matchmakingTicketId The unique identifier for the matchmaking ticket virtual void OnStartMatchmakingAsyncComplete(const AZStd::string& matchmakingTicketId) = 0; - // OnStopMatchmakingAsyncComplete is fired once StopMatchmakingAsync completes + //! OnStopMatchmakingAsyncComplete is fired once StopMatchmakingAsync completes virtual void OnStopMatchmakingAsyncComplete() = 0; }; using MatchmakingAsyncRequestNotificationBus = AZ::EBus; diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h index aa19b94b4a..0ec52c7215 100644 --- a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h +++ b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h @@ -29,17 +29,17 @@ namespace AzFramework static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; ////////////////////////////////////////////////////////////////////////// - // OnMatchAcceptance is fired when match is found and pending on acceptance - // Use this notification to accept found match + //! OnMatchAcceptance is fired when match is found and pending on acceptance + //! Use this notification to accept found match virtual void OnMatchAcceptance() = 0; - // OnMatchComplete is fired when match is complete + //! OnMatchComplete is fired when match is complete virtual void OnMatchComplete() = 0; - // OnMatchError is fired when match is processed with error + //! OnMatchError is fired when match is processed with error virtual void OnMatchError() = 0; - // OnMatchFailure is fired when match is failed to complete + //! OnMatchFailure is fired when match is failed to complete virtual void OnMatchFailure() = 0; }; using MatchmakingNotificationBus = AZ::EBus; diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h index 9169a83588..5f5dcc0643 100644 --- a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h +++ b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h @@ -29,11 +29,11 @@ namespace AzFramework AcceptMatchRequest() = default; virtual ~AcceptMatchRequest() = default; - // Player response to accept or reject match + //! Player response to accept or reject match bool m_acceptMatch; - // A list of unique identifiers for players delivering the response + //! A list of unique identifiers for players delivering the response AZStd::vector m_playerIds; - // A unique identifier for a matchmaking ticket + //! A unique identifier for a matchmaking ticket AZStd::string m_ticketId; }; @@ -47,7 +47,7 @@ namespace AzFramework StartMatchmakingRequest() = default; virtual ~StartMatchmakingRequest() = default; - // A unique identifier for a matchmaking ticket + //! A unique identifier for a matchmaking ticket AZStd::string m_ticketId; }; @@ -61,7 +61,7 @@ namespace AzFramework StopMatchmakingRequest() = default; virtual ~StopMatchmakingRequest() = default; - // A unique identifier for a matchmaking ticket + //! A unique identifier for a matchmaking ticket AZStd::string m_ticketId; }; } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Session/ISessionHandlingRequests.h b/Code/Framework/AzFramework/AzFramework/Session/ISessionHandlingRequests.h index 065d6bb9d5..188ea7b994 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/ISessionHandlingRequests.h +++ b/Code/Framework/AzFramework/AzFramework/Session/ISessionHandlingRequests.h @@ -18,16 +18,16 @@ namespace AzFramework //! The properties for handling join session request. struct SessionConnectionConfig { - // A unique identifier for registered player in session. + //! A unique identifier for registered player in session. AZStd::string m_playerSessionId; - // The DNS identifier assigned to the instance that is running the session. + //! The DNS identifier assigned to the instance that is running the session. AZStd::string m_dnsName; - // The IP address of the session. + //! The IP address of the session. AZStd::string m_ipAddress; - // The port number for the session. + //! The port number for the session. uint16_t m_port = 0; }; @@ -35,10 +35,10 @@ namespace AzFramework //! The properties for handling player connect/disconnect struct PlayerConnectionConfig { - // A unique identifier for player connection. + //! A unique identifier for player connection. uint32_t m_playerConnectionId = 0; - // A unique identifier for registered player in session. + //! A unique identifier for registered player in session. AZStd::string m_playerSessionId; }; @@ -51,12 +51,12 @@ namespace AzFramework ISessionHandlingClientRequests() = default; virtual ~ISessionHandlingClientRequests() = default; - // Request the player join session - // @param sessionConnectionConfig The required properties to handle the player join session process - // @return The result of player join session process + //! Request the player join session + //! @param sessionConnectionConfig The required properties to handle the player join session process + //! @return The result of player join session process virtual bool RequestPlayerJoinSession(const SessionConnectionConfig& sessionConnectionConfig) = 0; - // Request the connected player leave session + //! Request the connected player leave session virtual void RequestPlayerLeaveSession() = 0; }; @@ -69,26 +69,26 @@ namespace AzFramework ISessionHandlingProviderRequests() = default; virtual ~ISessionHandlingProviderRequests() = default; - // Handle the destroy session process + //! Handle the destroy session process virtual void HandleDestroySession() = 0; - // Validate the player join session process - // @param playerConnectionConfig The required properties to validate the player join session process - // @return The result of player join session validation + //! Validate the player join session process + //! @param playerConnectionConfig The required properties to validate the player join session process + //! @return The result of player join session validation virtual bool ValidatePlayerJoinSession(const PlayerConnectionConfig& playerConnectionConfig) = 0; - // Handle the player leave session process - // @param playerConnectionConfig The required properties to handle the player leave session process + //! Handle the player leave session process + //! @param playerConnectionConfig The required properties to handle the player leave session process virtual void HandlePlayerLeaveSession(const PlayerConnectionConfig& playerConnectionConfig) = 0; - // Retrieves the file location of a pem-encoded TLS certificate for Client to Server communication - // @return If successful, returns the file location of TLS certificate file; if not successful, returns - // empty string. + //! Retrieves the file location of a pem-encoded TLS certificate for Client to Server communication + //! @return If successful, returns the file location of TLS certificate file; if not successful, returns + //! empty string. virtual AZ::IO::Path GetExternalSessionCertificate() = 0; - // Retrieves the file location of a pem-encoded TLS certificate for Server to Server communication - // @return If successful, returns the file location of TLS certificate file; if not successful, returns - // empty string. + //! Retrieves the file location of a pem-encoded TLS certificate for Server to Server communication + //! @return If successful, returns the file location of TLS certificate file; if not successful, returns + //! empty string. virtual AZ::IO::Path GetInternalSessionCertificate() = 0; }; } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h b/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h index bdc3fe1444..8b985a3187 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h +++ b/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h @@ -25,22 +25,22 @@ namespace AzFramework ISessionRequests() = default; virtual ~ISessionRequests() = default; - // Create a session for players to find and join. - // @param createSessionRequest The request of CreateSession operation - // @return The request id if session creation request succeeds; empty if it fails + //! Create a session for players to find and join. + //! @param createSessionRequest The request of CreateSession operation + //! @return The request id if session creation request succeeds; empty if it fails virtual AZStd::string CreateSession(const CreateSessionRequest& createSessionRequest) = 0; - // Retrieve all active sessions that match the given search criteria and sorted in specific order. - // @param searchSessionsRequest The request of SearchSessions operation - // @return The response of SearchSessions operation + //! Retrieve all active sessions that match the given search criteria and sorted in specific order. + //! @param searchSessionsRequest The request of SearchSessions operation + //! @return The response of SearchSessions operation virtual SearchSessionsResponse SearchSessions(const SearchSessionsRequest& searchSessionsRequest) const = 0; - // Reserve an open player slot in a session, and perform connection from client to server. - // @param joinSessionRequest The request of JoinSession operation - // @return True if joining session succeeds; False otherwise + //! Reserve an open player slot in a session, and perform connection from client to server. + //! @param joinSessionRequest The request of JoinSession operation + //! @return True if joining session succeeds; False otherwise virtual bool JoinSession(const JoinSessionRequest& joinSessionRequest) = 0; - // Disconnect player from session. + //! Disconnect player from session. virtual void LeaveSession() = 0; }; @@ -54,19 +54,19 @@ namespace AzFramework ISessionAsyncRequests() = default; virtual ~ISessionAsyncRequests() = default; - // CreateSession Async - // @param createSessionRequest The request of CreateSession operation + //! CreateSession Async + //! @param createSessionRequest The request of CreateSession operation virtual void CreateSessionAsync(const CreateSessionRequest& createSessionRequest) = 0; - // SearchSessions Async - // @param searchSessionsRequest The request of SearchSessions operation + //! SearchSessions Async + //! @param searchSessionsRequest The request of SearchSessions operation virtual void SearchSessionsAsync(const SearchSessionsRequest& searchSessionsRequest) const = 0; - // JoinSession Async - // @param joinSessionRequest The request of JoinSession operation + //! JoinSession Async + //! @param joinSessionRequest The request of JoinSession operation virtual void JoinSessionAsync(const JoinSessionRequest& joinSessionRequest) = 0; - // LeaveSession Async + //! LeaveSession Async virtual void LeaveSessionAsync() = 0; }; @@ -85,19 +85,19 @@ namespace AzFramework static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; ////////////////////////////////////////////////////////////////////////// - // OnCreateSessionAsyncComplete is fired once CreateSessionAsync completes - // @param createSessionResponse The request id if session creation request succeeds; empty if it fails + //! OnCreateSessionAsyncComplete is fired once CreateSessionAsync completes + //! @param createSessionResponse The request id if session creation request succeeds; empty if it fails virtual void OnCreateSessionAsyncComplete(const AZStd::string& createSessionReponse) = 0; - // OnSearchSessionsAsyncComplete is fired once SearchSessionsAsync completes - // @param searchSessionsResponse The response of SearchSessions call + //! OnSearchSessionsAsyncComplete is fired once SearchSessionsAsync completes + //! @param searchSessionsResponse The response of SearchSessions call virtual void OnSearchSessionsAsyncComplete(const SearchSessionsResponse& searchSessionsResponse) = 0; - // OnJoinSessionAsyncComplete is fired once JoinSessionAsync completes - // @param joinSessionsResponse True if joining session succeeds; False otherwise + //! OnJoinSessionAsyncComplete is fired once JoinSessionAsync completes + //! @param joinSessionsResponse True if joining session succeeds; False otherwise virtual void OnJoinSessionAsyncComplete(bool joinSessionsResponse) = 0; - // OnLeaveSessionAsyncComplete is fired once LeaveSessionAsync completes + //! OnLeaveSessionAsyncComplete is fired once LeaveSessionAsync completes virtual void OnLeaveSessionAsyncComplete() = 0; }; using SessionAsyncRequestNotificationBus = AZ::EBus; diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h b/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h index 45e40c2f29..f951cf58fa 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h +++ b/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h @@ -24,46 +24,46 @@ namespace AzFramework SessionConfig() = default; virtual ~SessionConfig() = default; - // A time stamp indicating when this session was created. Format is a number expressed in Unix time as milliseconds. + //! A time stamp indicating when this session was created. Format is a number expressed in Unix time as milliseconds. uint64_t m_creationTime = 0; - // A time stamp indicating when this data object was terminated. Same format as creation time. + //! A time stamp indicating when this data object was terminated. Same format as creation time. uint64_t m_terminationTime = 0; - // A unique identifier for a player or entity creating the session. + //! A unique identifier for a player or entity creating the session. AZStd::string m_creatorId; - // A collection of custom properties for a session. + //! A collection of custom properties for a session. AZStd::unordered_map m_sessionProperties; - // The matchmaking process information that was used to create the session. + //! The matchmaking process information that was used to create the session. AZStd::string m_matchmakingData; - // A unique identifier for the session. + //! A unique identifier for the session. AZStd::string m_sessionId; - // A descriptive label that is associated with a session. + //! A descriptive label that is associated with a session. AZStd::string m_sessionName; - // The DNS identifier assigned to the instance that is running the session. + //! The DNS identifier assigned to the instance that is running the session. AZStd::string m_dnsName; - // The IP address of the session. + //! The IP address of the session. AZStd::string m_ipAddress; - // The port number for the session. + //! The port number for the session. uint16_t m_port = 0; - // The maximum number of players that can be connected simultaneously to the session. + //! The maximum number of players that can be connected simultaneously to the session. uint64_t m_maxPlayer = 0; - // Number of players currently in the session. + //! Number of players currently in the session. uint64_t m_currentPlayer = 0; - // Current status of the session. + //! Current status of the session. AZStd::string m_status; - // Provides additional information about session status. + //! Provides additional information about session status. AZStd::string m_statusReason; }; } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h b/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h index 2213343aa2..cf1382aeba 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h +++ b/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h @@ -29,42 +29,42 @@ namespace AzFramework static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; ////////////////////////////////////////////////////////////////////////// - // OnSessionHealthCheck is fired in health check process - // Use this notification to perform any custom health check - // @return True if OnSessionHealthCheck succeeds, false otherwise + //! OnSessionHealthCheck is fired in health check process + //! Use this notification to perform any custom health check + //! @return True if OnSessionHealthCheck succeeds, false otherwise virtual bool OnSessionHealthCheck() = 0; - // OnCreateSessionBegin is fired at the beginning of session creation process - // Use this notification to perform any necessary configuration or initialization before - // creating session - // @param sessionConfig The properties to describe a session - // @return True if OnCreateSessionBegin succeeds, false otherwise + //! OnCreateSessionBegin is fired at the beginning of session creation process + //! Use this notification to perform any necessary configuration or initialization before + //! creating session + //! @param sessionConfig The properties to describe a session + //! @return True if OnCreateSessionBegin succeeds, false otherwise virtual bool OnCreateSessionBegin(const SessionConfig& sessionConfig) = 0; - // OnCreateSessionEnd is fired at the end of session creation process - // Use this notification to perform any follow-up operation after session is created and active + //! OnCreateSessionEnd is fired at the end of session creation process + //! Use this notification to perform any follow-up operation after session is created and active virtual void OnCreateSessionEnd() = 0; - // OnDestroySessionBegin is fired at the beginning of session termination process - // Use this notification to perform any cleanup operation before destroying session, - // like gracefully disconnect players, cleanup data, etc. - // @return True if OnDestroySessionBegin succeeds, false otherwise + //! OnDestroySessionBegin is fired at the beginning of session termination process + //! Use this notification to perform any cleanup operation before destroying session, + //! like gracefully disconnect players, cleanup data, etc. + //! @return True if OnDestroySessionBegin succeeds, false otherwise virtual bool OnDestroySessionBegin() = 0; - // OnDestroySessionEnd is fired at the end of session termination process - // Use this notification to perform any follow-up operation after session is destroyed, - // like shutdown application process, etc. + //! OnDestroySessionEnd is fired at the end of session termination process + //! Use this notification to perform any follow-up operation after session is destroyed, + //! like shutdown application process, etc. virtual void OnDestroySessionEnd() = 0; - // OnUpdateSessionBegin is fired at the beginning of session update process - // Use this notification to perform any configuration or initialization to handle - // the session settings changing - // @param sessionConfig The properties to describe a session - // @param updateReason The reason for session update + //! OnUpdateSessionBegin is fired at the beginning of session update process + //! Use this notification to perform any configuration or initialization to handle + //! the session settings changing + //! @param sessionConfig The properties to describe a session + //! @param updateReason The reason for session update virtual void OnUpdateSessionBegin(const SessionConfig& sessionConfig, const AZStd::string& updateReason) = 0; - // OnUpdateSessionBegin is fired at the end of session update process - // Use this notification to perform any follow-up operations after session is updated + //! OnUpdateSessionBegin is fired at the end of session update process + //! Use this notification to perform any follow-up operations after session is updated virtual void OnUpdateSessionEnd() = 0; }; using SessionNotificationBus = AZ::EBus; diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h b/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h index 1ae018e1ef..d806e6fefa 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h +++ b/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h @@ -31,16 +31,16 @@ namespace AzFramework CreateSessionRequest() = default; virtual ~CreateSessionRequest() = default; - // A unique identifier for a player or entity creating the session. + //! A unique identifier for a player or entity creating the session. AZStd::string m_creatorId; - // A collection of custom properties for a session. + //! A collection of custom properties for a session. AZStd::unordered_map m_sessionProperties; - // A descriptive label that is associated with a session. + //! A descriptive label that is associated with a session. AZStd::string m_sessionName; - // The maximum number of players that can be connected simultaneously to the session. + //! The maximum number of players that can be connected simultaneously to the session. uint64_t m_maxPlayer = 0; }; @@ -54,17 +54,17 @@ namespace AzFramework SearchSessionsRequest() = default; virtual ~SearchSessionsRequest() = default; - // String containing the search criteria for the session search. If no filter expression is included, the request returns results - // for all active sessions. + //! String containing the search criteria for the session search. If no filter expression is included, the request returns results + //! for all active sessions. AZStd::string m_filterExpression; - // Instructions on how to sort the search results. If no sort expression is included, the request returns results in random order. + //! Instructions on how to sort the search results. If no sort expression is included, the request returns results in random order. AZStd::string m_sortExpression; - // The maximum number of results to return. + //! The maximum number of results to return. uint8_t m_maxResult = 0; - // A token that indicates the start of the next sequential page of results. + //! A token that indicates the start of the next sequential page of results. AZStd::string m_nextToken; }; @@ -78,10 +78,10 @@ namespace AzFramework SearchSessionsResponse() = default; virtual ~SearchSessionsResponse() = default; - // A collection of sessions that match the search criteria and sorted in specific order. + //! A collection of sessions that match the search criteria and sorted in specific order. AZStd::vector m_sessionConfigs; - // A token that indicates the start of the next sequential page of results. + //! A token that indicates the start of the next sequential page of results. AZStd::string m_nextToken; }; @@ -95,13 +95,13 @@ namespace AzFramework JoinSessionRequest() = default; virtual ~JoinSessionRequest() = default; - // A unique identifier for the session. + //! A unique identifier for the session. AZStd::string m_sessionId; - // A unique identifier for a player. Player IDs are developer-defined. + //! A unique identifier for a player. Player IDs are developer-defined. AZStd::string m_playerId; - // Developer-defined information related to a player. + //! Developer-defined information related to a player. AZStd::string m_playerData; }; } // namespace AzFramework diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h index a9b06c5bc9..24dfce1dfa 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h @@ -25,11 +25,11 @@ namespace AWSGameLift AWSGameLiftCreateSessionOnQueueRequest() = default; virtual ~AWSGameLiftCreateSessionOnQueueRequest() = default; - // Name of the queue to use to place the new game session. You can use either the queue name or ARN value. + //! Name of the queue to use to place the new game session. You can use either the queue name or ARN value. AZStd::string m_queueName; - // A unique identifier to assign to the new game session placement. This value is developer-defined. - // The value must be unique across all Regions and cannot be reused unless you are resubmitting a canceled or timed-out placement request. + //! A unique identifier to assign to the new game session placement. This value is developer-defined. + //! The value must be unique across all Regions and cannot be reused unless you are resubmitting a canceled or timed-out placement request. AZStd::string m_placementId; }; } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h index 4fab16ca70..97ffd0b321 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h @@ -25,14 +25,14 @@ namespace AWSGameLift AWSGameLiftCreateSessionRequest() = default; virtual ~AWSGameLiftCreateSessionRequest() = default; - // A unique identifier for the alias associated with the fleet to create a game session in. + //! A unique identifier for the alias associated with the fleet to create a game session in. AZStd::string m_aliasId; - // A unique identifier for the fleet to create a game session in. + //! A unique identifier for the fleet to create a game session in. AZStd::string m_fleetId; - // Custom string that uniquely identifies the new game session request. - // This is useful for ensuring that game session requests with the same idempotency token are processed only once. + //! Custom string that uniquely identifies the new game session request. + //! This is useful for ensuring that game session requests with the same idempotency token are processed only once. AZStd::string m_idempotencyToken; }; } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h index bfc2dc630e..02f3638998 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h @@ -25,13 +25,13 @@ namespace AWSGameLift AWSGameLiftSearchSessionsRequest() = default; virtual ~AWSGameLiftSearchSessionsRequest() = default; - // A unique identifier for the alias associated with the fleet to search for active game sessions. + //! A unique identifier for the alias associated with the fleet to search for active game sessions. AZStd::string m_aliasId; - // A unique identifier for the fleet to search for active game sessions. + //! A unique identifier for the fleet to search for active game sessions. AZStd::string m_fleetId; - // A fleet location to search for game sessions. + //! A fleet location to search for game sessions. AZStd::string m_location; }; } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h index ec3719c6d3..b2060032e8 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h @@ -30,9 +30,10 @@ namespace AWSGameLift AWSGameLiftStartMatchmakingRequest() = default; virtual ~AWSGameLiftStartMatchmakingRequest() = default; - // Name of the matchmaking configuration to use for this request + //! Name of the matchmaking configuration to use for this request AZStd::string m_configurationName; - // Information on each player to be matched + + //! Information on each player to be matched AZStd::vector m_players; }; } // namespace AWSGameLift From bf0a309a3c302a44c3e37aa52ae595fa90977267 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 1 Nov 2021 15:18:30 -0700 Subject: [PATCH 77/77] copy commands need to be per permutation/per configuraiton (#5183) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Platform/Common/Install_common.cmake | 18 ++++++++++-------- cmake/Platform/Linux/Install_linux.cmake | 9 ++++++--- cmake/Platform/Mac/Install_mac.cmake | 7 ++++++- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 803edb7b1d..2960a99c64 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -525,15 +525,20 @@ function(ly_setup_runtime_dependencies) if(COMMAND ly_setup_runtime_dependencies_copy_function_override) ly_setup_runtime_dependencies_copy_function_override() else() - ly_install(CODE + # despite this copy function being the same, we need to install it per component that uses it + # (which is per-configuration per-permutation component) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + ly_install(CODE "function(ly_copy source_file target_directory) cmake_path(GET source_file FILENAME file_name) if(NOT EXISTS \${target_directory}/\${file_name}) file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) endif() endfunction()" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + ) + endforeach() endif() unset(runtime_commands) @@ -574,11 +579,8 @@ endfunction()" list(JOIN runtime_commands " " runtime_commands_str) # the spaces are just to see the right identation in the cmake_install.cmake file foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) string(TOUPPER ${conf} UCONF) - ly_install(CODE -"if(\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^(${conf})\$\") - ${runtime_commands_str} -endif()" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} + ly_install(CODE "${runtime_commands_str}" + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} ) endforeach() diff --git a/cmake/Platform/Linux/Install_linux.cmake b/cmake/Platform/Linux/Install_linux.cmake index 54d1e18837..02baa6e61e 100644 --- a/cmake/Platform/Linux/Install_linux.cmake +++ b/cmake/Platform/Linux/Install_linux.cmake @@ -22,9 +22,12 @@ endfunction()]]) function(ly_setup_runtime_dependencies_copy_function_override) string(CONFIGURE "${ly_copy_template}" ly_copy_function_linux @ONLY) - ly_install(CODE "${ly_copy_function_linux}" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + ly_install(CODE "${ly_copy_function_linux}" + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + ) + endforeach() endfunction() include(cmake/Platform/Common/Install_common.cmake) diff --git a/cmake/Platform/Mac/Install_mac.cmake b/cmake/Platform/Mac/Install_mac.cmake index 76c381138d..c75d860c3e 100644 --- a/cmake/Platform/Mac/Install_mac.cmake +++ b/cmake/Platform/Mac/Install_mac.cmake @@ -113,7 +113,12 @@ endfunction() function(ly_setup_runtime_dependencies_copy_function_override) configure_file(${LY_ROOT_FOLDER}/cmake/Platform/Mac/InstallUtils_mac.cmake.in ${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake @ONLY) - ly_install_run_script(${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + ly_install(SCRIPT "${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake" + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + ) + endforeach() endfunction()