Browse Source

fixed new merge issues

Signed-off-by: T.J. McGrath-Daly <[email protected]>
T.J. McGrath-Daly 3 years ago
parent
commit
a4f3e6e657
100 changed files with 3598 additions and 1982 deletions
  1. 14 0
      .github/CODEOWNERS
  2. 73 6
      AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Benchmark_GPU.py
  3. 44 1
      AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py
  4. 294 22
      AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py
  5. 313 40
      AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py
  6. 0 6
      AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
  7. 1 1
      AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands_test_case.py
  8. 27 2
      AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Main.py
  9. 8 8
      AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests.py
  10. 0 174
      AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/assets_with_direct_preload_dependency/TestC.slice
  11. 0 174
      AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/assets_with_direct_preload_dependency/TestD.slice
  12. 0 222
      AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/assets_with_nested_preload_dependency/TestA.slice
  13. 0 174
      AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/assets_with_nested_preload_dependency/TestB.slice
  14. 0 174
      AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/assets_with_nested_preload_dependency/TestD.slice
  15. 0 181
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks.py
  16. 0 3
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main.py
  17. 0 21
      AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py
  18. 4 5
      AutomatedTesting/Levels/Physics/ScriptCanvas_PreUpdateEvent/ScriptCanvas_PreUpdateEvent.prefab
  19. 1 115
      Code/Editor/CryEdit.cpp
  20. 0 28
      Code/Editor/CryEdit.h
  21. 143 24
      Code/Editor/MainWindow.cpp
  22. 3 2
      Code/Framework/AzCore/AzCore/DOM/DomValue.h
  23. 3 0
      Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl
  24. 11 3
      Code/Framework/AzCore/AzCore/base.h
  25. 7 4
      Code/Framework/AzCore/AzCore/std/containers/vector.h
  26. 1 1
      Code/Framework/AzCore/AzCore/std/parallel/thread.h
  27. 10 1
      Code/Framework/AzCore/Platform/Linux/AzCore/std/parallel/internal/thread_Linux.cpp
  28. 17 0
      Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/AdapterBuilder.cpp
  29. 19 1
      Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/AdapterBuilder.h
  30. 1 1
      Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/BasicAdapter.h
  31. 198 0
      Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/CvarAdapter.cpp
  32. 31 0
      Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/CvarAdapter.h
  33. 0 4
      Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/DocumentAdapter.h
  34. 101 6
      Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/DocumentSchema.h
  35. 98 1
      Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/PropertyEditorNodes.h
  36. 2 2
      Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp
  37. 3 23
      Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSceneQueries.h
  38. 2 9
      Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsTypes.h
  39. 19 1
      Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h
  40. 1 1
      Code/Framework/AzFramework/AzFramework/Physics/Mocks/MockHeightfieldProviderBus.h
  41. 15 0
      Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp
  42. 1 0
      Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h
  43. 2 0
      Code/Framework/AzFramework/AzFramework/azframework_files.cmake
  44. 3 3
      Code/Framework/AzFramework/Tests/DocumentPropertyEditor/AdapterBuilderTests.cpp
  45. 167 0
      Code/Framework/AzFramework/Tests/DocumentPropertyEditor/CvarAdapterTests.cpp
  46. 57 0
      Code/Framework/AzFramework/Tests/DocumentPropertyEditor/SchemaTests.cpp
  47. 2 0
      Code/Framework/AzFramework/Tests/frameworktests_files.cmake
  48. 36 0
      Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h
  49. 3 0
      Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h
  50. 2 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp
  51. 5 0
      Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp
  52. 5 0
      Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h
  53. 14 0
      Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp
  54. 1 0
      Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.h
  55. 7 1
      Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceComponent.cpp
  56. 14 0
      Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp
  57. 2 0
      Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h
  58. 31 0
      Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp
  59. 12 1
      Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx
  60. 9 0
      Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp
  61. 4 0
      Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.hxx
  62. 6 0
      Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp
  63. 1 0
      Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/Mocks/MockFocusModeInterface.h
  64. 51 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/LocalViewBookmarkComponent.cpp
  65. 31 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/LocalViewBookmarkComponent.h
  66. 514 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/LocalViewBookmarkLoader.cpp
  67. 58 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/LocalViewBookmarkLoader.h
  68. 111 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/SharedViewBookmarkComponent.cpp
  69. 55 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/SharedViewBookmarkComponent.h
  70. 88 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewBookmarkLoaderInterface.h
  71. 36 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewBookmarkSystemComponent.cpp
  72. 38 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewBookmarkSystemComponent.h
  73. 23 7
      Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp
  74. 9 0
      Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake
  75. 109 29
      Code/Framework/AzToolsFramework/Tests/ManipulatorCoreTests.cpp
  76. 4 1
      Code/Legacy/CryCommon/ISystem.h
  77. 4 1
      Code/Legacy/CrySystem/DllMain.cpp
  78. 1 1
      Code/Tools/AssetProcessor/native/tests/AssetProcessorMessagesTests.cpp
  79. 4 0
      Code/Tools/ProjectManager/Source/Application.cpp
  80. 1 0
      Code/Tools/SerializeContextTools/Converter.cpp
  81. 0 24
      Gems/Atom/Asset/Shader/Code/Source/Editor/AtomShaderCapabilitiesConfigFile.cpp
  82. 0 40
      Gems/Atom/Asset/Shader/Code/Source/Editor/AtomShaderCapabilitiesConfigFile.h
  83. 0 136
      Gems/Atom/Asset/Shader/Code/Source/Editor/AtomShaderConfig.cpp
  84. 0 32
      Gems/Atom/Asset/Shader/Code/Source/Editor/AtomShaderConfig.h
  85. 3 2
      Gems/Atom/Asset/Shader/Code/Source/Editor/AzslCompiler.cpp
  86. 2 1
      Gems/Atom/Asset/Shader/Code/Source/Editor/AzslCompiler.h
  87. 3 5
      Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp
  88. 0 81
      Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/GlobalBuildOptions.cpp
  89. 0 37
      Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/GlobalBuildOptions.h
  90. 130 57
      Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/Preprocessor.cpp
  91. 10 20
      Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/Preprocessor.h
  92. 28 42
      Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp
  93. 237 0
      Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuildArgumentsManager.cpp
  94. 146 0
      Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuildArgumentsManager.h
  95. 15 3
      Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.cpp
  96. 2 1
      Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.h
  97. 26 15
      Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp
  98. 1 1
      Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h
  99. 2 0
      Gems/Atom/Asset/Shader/Code/Tests/Common/ShaderBuilderTestFixture.cpp
  100. 8 0
      Gems/Atom/Asset/Shader/Code/Tests/Common/ShaderBuilderTestFixture.h

+ 14 - 0
.github/CODEOWNERS

@@ -0,0 +1,14 @@
+
+/cmake/LYTestWrappers.cmake @o3de/sig-testing-reviewers
+
+/Code/Framework/AzTest @o3de/sig-testing-reviewers
+/Code/Tools/AzTestRunner/ @o3de/sig-testing-reviewers
+
+/o3de/pytest.ini @o3de/sig-testing-reviewers
+/o3de/AutomatedTesting/Gem/PythonTests/editor_test_testing/ @o3de/sig-testing-reviewers
+/o3de/scripts/ctest/ @o3de/sig-testing-reviewers
+
+/Tools/LyTestTools/ @o3de/sig-testing-reviewers
+# This is being deprecated.
+/Tools/RemoteConsole/ @o3de/sig-testing-reviewers
+

+ 73 - 6
AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Benchmark_GPU.py

@@ -6,6 +6,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
 """
 """
 import logging
 import logging
 import os
 import os
+import psutil
 
 
 import pytest
 import pytest
 
 
@@ -15,16 +16,76 @@ from ly_test_tools.benchmark.data_aggregator import BenchmarkDataAggregator
 logger = logging.getLogger(__name__)
 logger = logging.getLogger(__name__)
 
 
 
 
[email protected]('rhi', ['dx12', 'vulkan'])
+def filebeat_service_running():
+    """
+    Checks if the filebeat service is currently running on the OS.
+    :return: True if filebeat service detected and running, False otherwise.
+    """
+    result = False
+    try:
+        filebeat_service = psutil.win_service_get('filebeat')
+        filebeat_service_info = filebeat_service.as_dict()
+        if filebeat_service_info['status'] == 'running':
+            result = True
+    except psutil.NoSuchProcess:
+        return result
+
+    return result
+
+
 @pytest.mark.parametrize("project", ["AutomatedTesting"])
 @pytest.mark.parametrize("project", ["AutomatedTesting"])
 @pytest.mark.parametrize("launcher_platform", ["windows_editor"])
 @pytest.mark.parametrize("launcher_platform", ["windows_editor"])
 @pytest.mark.parametrize("level", ["AtomFeatureIntegrationBenchmark"])
 @pytest.mark.parametrize("level", ["AtomFeatureIntegrationBenchmark"])
 class TestPerformanceBenchmarkSuite(object):
 class TestPerformanceBenchmarkSuite(object):
-    def test_AtomFeatureIntegrationBenchmarkTest_UploadMetrics(
+
+    @pytest.mark.parametrize('rhi', ['-rhi=dx12'])
+    def test_AtomFeatureIntegrationBenchmarkTest_GatherBenchmarkMetrics_DX12(
+            self, request, editor, workspace, rhi, project, launcher_platform, level):
+        """
+        Please review the hydra script run by this test for more specific test info.
+        """
+        expected_lines = [
+            "Benchmark metadata captured.",
+            "Pass timestamps captured.",
+            "CPU frame time captured.",
+            "Captured data successfully.",
+            "Exited game mode"
+        ]
+
+        unexpected_lines = [
+            "Failed to capture data.",
+            "Failed to capture pass timestamps.",
+            "Failed to capture CPU frame time.",
+            "Failed to capture benchmark metadata."
+        ]
+
+        hydra.launch_and_validate_results(
+            request,
+            os.path.join(os.path.dirname(__file__), "tests"),
+            editor,
+            "hydra_GPUTest_AtomFeatureIntegrationBenchmark.py",
+            timeout=600,
+            expected_lines=expected_lines,
+            unexpected_lines=unexpected_lines,
+            halt_on_unexpected=True,
+            cfg_args=[level, rhi],
+            null_renderer=False,
+        )
+
+    @pytest.mark.skipif(not filebeat_service_running(), reason="filebeat service not running")
+    def test_AtomFeatureIntegrationBenchmarkTest_SendBenchmarkMetrics_DX12(
+            self, request, editor, workspace, project, launcher_platform, level):
+        """
+        Gathers the DX12 benchmark metrics and uses filebeat to send the metrics data.
+        """
+        aggregator = BenchmarkDataAggregator(workspace, logger, 'main_gpu')
+        aggregator.upload_metrics('dx12')
+
+    @pytest.mark.parametrize('rhi', ['-rhi=Vulkan'])
+    def test_AtomFeatureIntegrationBenchmarkTest_GatherBenchmarkMetrics_Vulkan(
             self, request, editor, workspace, rhi, project, launcher_platform, level):
             self, request, editor, workspace, rhi, project, launcher_platform, level):
         """
         """
         Please review the hydra script run by this test for more specific test info.
         Please review the hydra script run by this test for more specific test info.
-        Tests the performance of the Simple level.
         """
         """
         expected_lines = [
         expected_lines = [
             "Benchmark metadata captured.",
             "Benchmark metadata captured.",
@@ -50,9 +111,15 @@ class TestPerformanceBenchmarkSuite(object):
             expected_lines=expected_lines,
             expected_lines=expected_lines,
             unexpected_lines=unexpected_lines,
             unexpected_lines=unexpected_lines,
             halt_on_unexpected=True,
             halt_on_unexpected=True,
-            cfg_args=[level],
+            cfg_args=[level, rhi],
             null_renderer=False,
             null_renderer=False,
         )
         )
 
 
-        aggregator = BenchmarkDataAggregator(workspace, logger, 'periodic')
-        aggregator.upload_metrics(rhi)
+    @pytest.mark.skipif(not filebeat_service_running(), reason="filebeat service not running")
+    def test_AtomFeatureIntegrationBenchmarkTest_SendBenchmarkMetrics_Vulkan(
+            self, request, editor, workspace, project, launcher_platform, level):
+        """
+        Gathers the Vulkan benchmark metrics and uses filebeat to send the metrics data.
+        """
+        aggregator = BenchmarkDataAggregator(workspace, logger, 'main_gpu')
+        aggregator.upload_metrics('Vulkan')

+ 44 - 1
AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py

@@ -63,6 +63,23 @@ MESH_LOD_TYPE = {
     'specific lod': 2,
     'specific lod': 2,
 }
 }
 
 
+# Display Mapper type
+DISPLAY_MAPPER_OPERATION_TYPE = {
+    'Aces': 0,
+    'AcesLut': 1,
+    'Passthrough': 2,
+    'GammaSRGB': 3,
+    'Reinhard': 4,
+}
+
+# Display Mapper presets
+DISPLAY_MAPPER_PRESET = {
+    '48Nits': 0,
+    '1000Nits': 1,
+    '2000Nits': 2,
+    '4000Nits': 3,
+}
+
 # Level list used in Editor Level Load Test
 # Level list used in Editor Level Load Test
 # WARNING: "Sponza" level is sandboxed due to an intermittent failure.
 # WARNING: "Sponza" level is sandboxed due to an intermittent failure.
 LEVEL_LIST = ["hermanubis", "hermanubis_high", "macbeth_shaderballs", "PbrMaterialChart", "ShadowTest"]
 LEVEL_LIST = ["hermanubis", "hermanubis_high", "macbeth_shaderballs", "PbrMaterialChart", "ShadowTest"]
@@ -312,16 +329,42 @@ class AtomComponentProperties:
     def display_mapper(property: str = 'name') -> str:
     def display_mapper(property: str = 'name') -> str:
         """
         """
         Display Mapper level component properties.
         Display Mapper level component properties.
+          - 'Type' specifies the Display Mapper type from atom_constants.py DISPLAY_MAPPER_OPERATION_TYPE
           - 'Enable LDR color grading LUT' toggles the use of LDR color grading LUT
           - 'Enable LDR color grading LUT' toggles the use of LDR color grading LUT
           - 'LDR color Grading LUT' is the Low Definition Range (LDR) color grading for Look-up Textures (LUT) which is
           - 'LDR color Grading LUT' is the Low Definition Range (LDR) color grading for Look-up Textures (LUT) which is
-            an Asset.id value corresponding to a lighting asset file.
+            an Asset.id value corresponding to a LUT asset file.
+          - 'Override Defaults' toggle enables parameter overrides for ACES settings (bool)
+          - 'Alter Surround' toggle applies gamma adjustments for dim surround (bool)
+          - 'Alter Desaturation' toggle applies desaturation adjustment for luminance differences (bool)
+          - 'Alter CAT D60 to D65' toggles conversion referencing black luminance level constant (bool)
+          - 'Preset Selection' select from a list of presets from atom_constants.py DISPLAY_MAPPER_PRESET
+          - 'Cinema Limit (black)' reference black
+          - 'Cinema Limit (white)' reference white
+          - 'Min Point (luminance)' linear extension below this value
+          - 'Mid Point (luminance)' middle gray value
+          - 'Max Point (luminance)' linear extension above this value
+          - 'Surround Gamma' applied to compensate for the condition of the viewing environment
+          - 'Gamma' value applied as the basic Gamma curve Opto-Electrical Transfer Function (OETF)
         :param property: From the last element of the property tree path. Default 'name' for component name string.
         :param property: From the last element of the property tree path. Default 'name' for component name string.
         :return: Full property path OR component name if no property specified.
         :return: Full property path OR component name if no property specified.
         """
         """
         properties = {
         properties = {
             'name': 'Display Mapper',
             'name': 'Display Mapper',
+            'Type': 'Controller|Configuration|Type',
             'Enable LDR color grading LUT': 'Controller|Configuration|Enable LDR color grading LUT',
             'Enable LDR color grading LUT': 'Controller|Configuration|Enable LDR color grading LUT',
             'LDR color Grading LUT': 'Controller|Configuration|LDR color Grading LUT',
             'LDR color Grading LUT': 'Controller|Configuration|LDR color Grading LUT',
+            'Override Defaults': 'Controller|Configuration|ACES Parameters|Override Defaults',
+            'Alter Surround': 'Controller|Configuration|ACES Parameters|Alter Surround',
+            'Alter Desaturation': 'Controller|Configuration|ACES Parameters|Alter Desaturation',
+            'Alter CAT D60 to D65': 'Controller|Configuration|ACES Parameters|Alter CAT D60 to D65',
+            'Preset Selection': 'Controller|Configuration|ACES Parameters|Load Preset|Preset Selection',
+            'Cinema Limit (black)': 'Controller|Configuration|ACES Parameters|Cinema Limit (black)',
+            'Cinema Limit (white)': 'Controller|Configuration|ACES Parameters|Cinema Limit (white)',
+            'Min Point (luminance)': 'Controller|Configuration|ACES Parameters|Min Point (luminance)',
+            'Mid Point (luminance)': 'Controller|Configuration|ACES Parameters|Mid Point (luminance)',
+            'Max Point (luminance)': 'Controller|Configuration|ACES Parameters|Max Point (luminance)',
+            'Surround Gamma': 'Controller|Configuration|ACES Parameters|Surround Gamma',
+            'Gamma': 'Controller|Configuration|ACES Parameters|Gamma',
         }
         }
         return properties[property]
         return properties[property]
 
 

+ 294 - 22
AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py

@@ -9,25 +9,71 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
 class Tests:
 class Tests:
     creation_undo = (
     creation_undo = (
         "UNDO level component addition success",
         "UNDO level component addition success",
-        "UNDO level component addition failed")
+        "P0: UNDO level component addition failed")
     creation_redo = (
     creation_redo = (
         "REDO Level component addition success",
         "REDO Level component addition success",
-        "REDO Level component addition failed")
+        "P0: REDO Level component addition failed")
     display_mapper_component = (
     display_mapper_component = (
         "Level has a Display Mapper component",
         "Level has a Display Mapper component",
-        "Level failed to find Display Mapper component")
+        "P0: Level failed to find Display Mapper component")
     ldr_color_grading_lut = (
     ldr_color_grading_lut = (
         "LDR color Grading LUT asset set",
         "LDR color Grading LUT asset set",
-        "LDR color Grading LUT asset could not be set")
+        "P0: LDR color Grading LUT asset could not be set")
     enable_ldr_color_grading_lut = (
     enable_ldr_color_grading_lut = (
         "Enable LDR color grading LUT set",
         "Enable LDR color grading LUT set",
-        "Enable LDR color grading LUT could not be set")
+        "P0: Enable LDR color grading LUT could not be set")
     enter_game_mode = (
     enter_game_mode = (
         "Entered game mode",
         "Entered game mode",
-        "Failed to enter game mode")
+        "P0: Failed to enter game mode")
     exit_game_mode = (
     exit_game_mode = (
         "Exited game mode",
         "Exited game mode",
-        "Couldn't exit game mode")
+        "P0: Couldn't exit game mode")
+    override_defaults = (
+        "Override Defaults property set",
+        "P1: Override Defaults property failed to be set correctly")
+    alter_surround = (
+        "Alter Surround property set",
+        "P1: Alter Surround property failed to be set correctly")
+    alter_desaturation = (
+        "Alter Desaturation property set",
+        "P1: Alter Desaturation property failed to be set correctly")
+    alter_cat = (
+        "Alter CAT D60 to D65 property set",
+        "P1: Alter CAT D60 to D65 property failed to be set correctly")
+    black_level_min = (
+        "Cinema Limit (black) property set to minimum value",
+        "P1: Cinema Limit (black) property failed to take minimum value")
+    black_level_max = (
+        "Cinema Limit (black) property set to maximum value",
+        "P1: Cinema Limit (black) property failed to take maximum value")
+    white_level_min = (
+        "Cinema Limit (white) property set to minimum value",
+        "P1: Cinema Limit (white) property failed to take minimum value")
+    white_level_max = (
+        "Cinema Limit (white) property set to maximum value",
+        "P1: Cinema Limit (white) property failed to take maximum value")
+    luminance_level_min = (
+        "Min Point (luminance) property set",
+        "P1: Min Point (luminance) property failed to set expected value")
+    luminance_level_mid = (
+        "Mid Point (luminance) property set",
+        "P1: Mid Point (luminance) property failed to set expected value")
+    luminance_level_max = (
+        "Max Point (luminance) property set",
+        "P1: Max Point (luminance) property failed to set expected value")
+    surround_gamma = (
+        "Surround Gamma property set",
+        "P1: Surround Gamma property failed to set expected value")
+    gamma = (
+        "Gamma property set",
+        "P1: Gamma property failed to set expected value")
+    display_mapper_type = (
+        "Display Mapper Operation Type is correctly set",
+        "P1: Display Mapper Operation type is not as expected")
+
+
+# IsClose tolerance defaults to , 1e-9, but float values in some tests need a looser tolerance
+TOLERANCE = 1e-6
 
 
 
 
 def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity():
 def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity():
@@ -48,20 +94,36 @@ def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity():
     2) UNDO the level component addition.
     2) UNDO the level component addition.
     3) REDO the level component addition.
     3) REDO the level component addition.
     4) Set LDR color Grading LUT asset.
     4) Set LDR color Grading LUT asset.
-    5) Set Enable LDR color grading LUT property True
-    6) Enter/Exit game mode.
-    7) Look for errors and asserts.
+    5) Set the Display Mapper Operation Type enumerated in DISPLAY_MAPPER_OPERATION_TYPE for each type
+    6) Set Enable LDR color grading LUT property True
+    7) Toggle Override Defaults
+    8) Toggle Alter Surround
+    9) Toggle Alter Desaturation
+    10) Toggle 'Alter CAT D60 to D65'
+    11) Set 'Cinema Limit (black)' max value which is dynamic based on Cinema Limit (white) then min value
+    12) Set 'Cinema Limit (white)' max value then min, and finally back to default
+    13) Set 'Min Point (luminance)' to high and low value
+    14) Set 'Mid Point (luminance)' to high and low value then set default
+    15) Set 'Max Point (luminance)' to high and low value then set default
+    16) Set 'Surround Gamma' to high and low value
+    17) Set 'Gamma' to high and low value
+    18) Enter/Exit game mode.
+    19) Select and load each preset
+    20) Look for errors and asserts.
 
 
     :return: None
     :return: None
     """
     """
     import os
     import os
 
 
+    import azlmbr.bus as bus
     import azlmbr.legacy.general as general
     import azlmbr.legacy.general as general
+    import azlmbr.render as render
 
 
+    from azlmbr.math import Math_IsClose
     from editor_python_test_tools.asset_utils import Asset
     from editor_python_test_tools.asset_utils import Asset
     from editor_python_test_tools.editor_entity_utils import EditorLevelEntity
     from editor_python_test_tools.editor_entity_utils import EditorLevelEntity
     from editor_python_test_tools.utils import Report, Tracer, TestHelper
     from editor_python_test_tools.utils import Report, Tracer, TestHelper
-    from Atom.atom_utils.atom_constants import AtomComponentProperties
+    from Atom.atom_utils.atom_constants import AtomComponentProperties, DISPLAY_MAPPER_PRESET, DISPLAY_MAPPER_OPERATION_TYPE
 
 
     with Tracer() as error_tracer:
     with Tracer() as error_tracer:
         # Test setup begins.
         # Test setup begins.
@@ -89,7 +151,7 @@ def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity():
         Report.result(Tests.creation_redo, EditorLevelEntity.has_component(AtomComponentProperties.display_mapper()))
         Report.result(Tests.creation_redo, EditorLevelEntity.has_component(AtomComponentProperties.display_mapper()))
 
 
         # 4. Set LDR color Grading LUT asset.
         # 4. Set LDR color Grading LUT asset.
-        display_mapper_asset_path = os.path.join("TestData", "test.lightingpreset.azasset")
+        display_mapper_asset_path = os.path.join("LookupTables", "LUT_Sepia.azasset")
         display_mapper_asset = Asset.find_asset_by_path(display_mapper_asset_path, False)
         display_mapper_asset = Asset.find_asset_by_path(display_mapper_asset_path, False)
         display_mapper_component.set_component_property_value(
         display_mapper_component.set_component_property_value(
             AtomComponentProperties.display_mapper('LDR color Grading LUT'), display_mapper_asset.id)
             AtomComponentProperties.display_mapper('LDR color Grading LUT'), display_mapper_asset.id)
@@ -98,20 +160,230 @@ def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity():
             display_mapper_component.get_component_property_value(
             display_mapper_component.get_component_property_value(
                 AtomComponentProperties.display_mapper('LDR color Grading LUT')) == display_mapper_asset.id)
                 AtomComponentProperties.display_mapper('LDR color Grading LUT')) == display_mapper_asset.id)
 
 
-        # 5. Set Enable LDR color grading LUT property True
+        for operation_type in DISPLAY_MAPPER_OPERATION_TYPE.keys():
+            # 5. Set the Display Mapper Operation Type enumerated in DISPLAY_MAPPER_OPERATION_TYPE for each type
+            # Type property cannot be set currently. as a workaround we are calling an ebus to set the operation type
+            # display_mapper_component.set_component_property_value(
+            #     AtomComponentProperties.display_mapper('Type'), DISPLAY_MAPPER_OPERATION_TYPE[operation_type])
+            render.DisplayMapperComponentRequestBus(
+                bus.Broadcast, "SetDisplayMapperOperationType", DISPLAY_MAPPER_OPERATION_TYPE[operation_type])
+            general.idle_wait_frames(3)
+            set_type = render.DisplayMapperComponentRequestBus(bus.Broadcast, "GetDisplayMapperOperationType")
+            Report.info(f"DiplayMapperOperationType: {set_type}")
+            Report.result(Tests.display_mapper_type, set_type == DISPLAY_MAPPER_OPERATION_TYPE[operation_type])
+
+            # 6. Set Enable LDR color grading LUT property True
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True)
+            Report.result(
+                Tests.enable_ldr_color_grading_lut,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True)
+
+            # 7. Toggle Override Defaults
+            # Set Override Defaults to False
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Override Defaults'), False)
+            Report.result(
+                Tests.override_defaults,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Override Defaults')) is False)
+
+            # Set Override Defaults to True
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Override Defaults'), True)
+            Report.result(
+                Tests.override_defaults,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Override Defaults')) is True)
+
+            # 8. Toggle Alter Surround
+            # Set Alter Surround to True
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Alter Surround'), True)
+            Report.result(
+                Tests.alter_surround,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Alter Surround')) is True)
+
+            # Set Alter Surround to False
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Alter Surround'), False)
+            Report.result(
+                Tests.alter_surround,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Alter Surround')) is False)
+
+            # 9. Toggle Alter Desaturation
+            # Set Alter Desaturation to True
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Alter Desaturation'), True)
+            Report.result(
+                Tests.alter_desaturation,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Alter Desaturation')) is True)
+
+            # Set Alter Desaturation to False
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Alter Desaturation'), False)
+            Report.result(
+                Tests.alter_desaturation,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Alter Desaturation')) is False)
+
+            # 10. Toggle 'Alter CAT D60 to D65'
+            # Set 'Alter CAT D60 to D65' to True
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Alter CAT D60 to D65'), True)
+            Report.result(
+                Tests.alter_cat,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Alter CAT D60 to D65')) is True)
+
+            # Set 'Alter CAT D60 to D65' to False
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Alter CAT D60 to D65'), False)
+            Report.result(
+                Tests.alter_cat,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Alter CAT D60 to D65')) is False)
+
+            general.idle_wait_frames(1)
+
+            # 11. Set 'Cinema Limit (black)' max value which is dynamic based on Cinema Limit (white) then min value
+            # set max value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (black)'), value=48.0)
+            Report.result(Tests.black_level_max, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (black)')), 48.0, TOLERANCE))
+
+            # set min value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (black)'), value=0.02)
+            Report.result(Tests.black_level_min, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (black)')), 0.02, TOLERANCE))
+
+            # 12. Set 'Cinema Limit (white)' maximum value then min, and finally back to default
+            # set max value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (white)'), value=4000.0)
+            Report.result(Tests.white_level_max, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (white)')), 4000.0, TOLERANCE))
+
+            # Set min value which is dynamic based on Cinema Limit (black)
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (white)'), value=0.02)
+            Report.result(Tests.white_level_min, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (white)')), 0.02, TOLERANCE))
+
+            # Reset this to the default 48 so following cycles don't impact Cinema Limit (Black)
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (white)'), value=48.0)
+
+            # 13. Set 'Min Point (luminance)' to high and low value
+            # set high value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Min Point (luminance)'), value=4.8)
+            Report.info(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Min Point (luminance)')))
+            Report.result(Tests.luminance_level_min, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Min Point (luminance)')), 4.8, TOLERANCE))
+
+            # set low value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Min Point (luminance)'), value=0.002)
+            Report.result(Tests.luminance_level_min, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Min Point (luminance)')), 0.002, TOLERANCE))
+
+            # 14. Set 'Mid Point (luminance)' to high and low value then set default
+            # set high value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Mid Point (luminance)'), value=1005.0)
+            Report.result(Tests.luminance_level_mid, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Mid Point (luminance)')), 1005.0, TOLERANCE))
+
+            # set low value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Mid Point (luminance)'), value=0.002)
+            Report.result(Tests.luminance_level_mid, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Mid Point (luminance)')), 0.002, TOLERANCE))
+
+            # restore the default since as this impacts the range of 'Min Point (luminance)'
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Mid Point (luminance)'), value=4.8)
+
+            # 15. Set 'Max Point (luminance)' to high and low value then set default
+            # set a high value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Max Point (luminance)'), value=4000.0)
+            Report.result(Tests.luminance_level_max, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Max Point (luminance)')), 4000.0, TOLERANCE))
+
+            # set a low value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Max Point (luminance)'), value=0.002)
+            Report.result(Tests.luminance_level_max, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Max Point (luminance)')), 0.002, TOLERANCE))
+
+            # restore the default since this impacts the range of 'Mid Point (luminance)'
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Max Point (luminance)'), value=1005.7191162)
+
+            # 16. Set 'Surround Gamma' to high and low value
+            # set a high value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Surround Gamma'), value=1.2)
+            Report.result(Tests.surround_gamma, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Surround Gamma')), 1.2, TOLERANCE))
+
+            # set a low value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Surround Gamma'), value=0.6)
+            Report.result(Tests.surround_gamma, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Surround Gamma')), 0.6, TOLERANCE))
+
+            # 17. Set 'Gamma' to high and low value
+            # set a high value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Gamma'), value=4.0)
+            Report.result(Tests.gamma, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Gamma')), 4.0, TOLERANCE))
+
+            # set a low value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Gamma'), value=0.2)
+            Report.result(Tests.gamma, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Gamma')), 0.2, TOLERANCE))
+
+            # 18. Enter/Exit game mode.
+            TestHelper.enter_game_mode(Tests.enter_game_mode)
+            general.idle_wait_frames(1)
+            TestHelper.exit_game_mode(Tests.exit_game_mode)
+
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), False)
+
         display_mapper_component.set_component_property_value(
         display_mapper_component.set_component_property_value(
             AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True)
             AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True)
-        Report.result(
-            Tests.enable_ldr_color_grading_lut,
-            display_mapper_component.get_component_property_value(
-                AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True)
 
 
-        # 6. Enter/Exit game mode.
-        TestHelper.enter_game_mode(Tests.enter_game_mode)
-        general.idle_wait_frames(1)
-        TestHelper.exit_game_mode(Tests.exit_game_mode)
+        cinema_limit_white_presets = [48.0, 184.3200073, 368.6400146, 737.2800293]
+        for preset in DISPLAY_MAPPER_PRESET.keys():
+            # 19. Select and load each preset
+            # Preset Selection cannot be set or loaded currently; as a workaround we are calling an ebus to load preset
+            # A fix is in progress
+            # display_mapper_component.set_component_property_value(
+            #     AtomComponentProperties.display_mapper('Preset Selection'), DISPLAY_MAPPER_PRESET[preset])
+            render.DisplayMapperComponentRequestBus(bus.Broadcast, "LoadPreset", DISPLAY_MAPPER_PRESET[preset])
+            general.idle_wait_frames(1)
+            # check some value to confirm preset loaded
+            test_preset = (f"Preset {preset} loaded expected value",
+                      f"P1: Preset {preset} failed to load values as expected")
+            Report.result(test_preset, Math_IsClose(
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Cinema Limit (white)')),
+                cinema_limit_white_presets[DISPLAY_MAPPER_PRESET[preset]], TOLERANCE))
 
 
-        # 7. Look for errors and asserts.
+        # 20. Look for errors and asserts.
         TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
         TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
         for error_info in error_tracer.errors:
         for error_info in error_tracer.errors:
             Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
             Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")

+ 313 - 40
AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py

@@ -9,43 +9,89 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
 class Tests:
 class Tests:
     creation_undo = (
     creation_undo = (
         "UNDO Entity creation success",
         "UNDO Entity creation success",
-        "UNDO Entity creation failed")
+        "P0: UNDO Entity creation failed")
     creation_redo = (
     creation_redo = (
         "REDO Entity creation success",
         "REDO Entity creation success",
-        "REDO Entity creation failed")
+        "P0: REDO Entity creation failed")
     display_mapper_creation = (
     display_mapper_creation = (
         "Display Mapper Entity successfully created",
         "Display Mapper Entity successfully created",
-        "Display Mapper Entity failed to be created")
+        "P0: Display Mapper Entity failed to be created")
     display_mapper_component = (
     display_mapper_component = (
         "Entity has a Display Mapper component",
         "Entity has a Display Mapper component",
-        "Entity failed to find Display Mapper component")
+        "P0: Entity failed to find Display Mapper component")
     enter_game_mode = (
     enter_game_mode = (
         "Entered game mode",
         "Entered game mode",
-        "Failed to enter game mode")
+        "P0: Failed to enter game mode")
     exit_game_mode = (
     exit_game_mode = (
         "Exited game mode",
         "Exited game mode",
-        "Couldn't exit game mode")
+        "P0: Couldn't exit game mode")
     is_visible = (
     is_visible = (
         "Entity is visible",
         "Entity is visible",
-        "Entity was not visible")
+        "P0: Entity was not visible")
     is_hidden = (
     is_hidden = (
         "Entity is hidden",
         "Entity is hidden",
-        "Entity was not hidden")
+        "P0: Entity was not hidden")
     ldr_color_grading_lut = (
     ldr_color_grading_lut = (
         "LDR color Grading LUT asset set",
         "LDR color Grading LUT asset set",
-        "LDR color Grading LUT asset could not be set")
+        "P0: LDR color Grading LUT asset could not be set")
     enable_ldr_color_grading_lut = (
     enable_ldr_color_grading_lut = (
         "Enable LDR color grading LUT set",
         "Enable LDR color grading LUT set",
-        "Enable LDR color grading LUT could not be set")
+        "P0: Enable LDR color grading LUT could not be set")
     entity_deleted = (
     entity_deleted = (
         "Entity deleted",
         "Entity deleted",
-        "Entity was not deleted")
+        "P0: Entity was not deleted")
     deletion_undo = (
     deletion_undo = (
         "UNDO deletion success",
         "UNDO deletion success",
-        "UNDO deletion failed")
+        "P0: UNDO deletion failed")
     deletion_redo = (
     deletion_redo = (
         "REDO deletion success",
         "REDO deletion success",
-        "REDO deletion failed")
+        "P0: REDO deletion failed")
+    override_defaults = (
+        "Override Defaults property set",
+        "P1: Override Defaults property failed to be set correctly")
+    alter_surround = (
+        "Alter Surround property set",
+        "P1: Alter Surround property failed to be set correctly")
+    alter_desaturation = (
+        "Alter Desaturation property set",
+        "P1: Alter Desaturation property failed to be set correctly")
+    alter_cat = (
+        "Alter CAT D60 to D65 property set",
+        "P1: Alter CAT D60 to D65 property failed to be set correctly")
+    black_level_min = (
+        "Cinema Limit (black) property set to minimum value",
+        "P1: Cinema Limit (black) property failed to take minimum value")
+    black_level_max = (
+        "Cinema Limit (black) property set to maximum value",
+        "P1: Cinema Limit (black) property failed to take maximum value")
+    white_level_min = (
+        "Cinema Limit (white) property set to minimum value",
+        "P1: Cinema Limit (white) property failed to take minimum value")
+    white_level_max = (
+        "Cinema Limit (white) property set to maximum value",
+        "P1: Cinema Limit (white) property failed to take maximum value")
+    luminance_level_min = (
+        "Min Point (luminance) property set",
+        "P1: Min Point (luminance) property failed to set expected value")
+    luminance_level_mid = (
+        "Mid Point (luminance) property set",
+        "P1: Mid Point (luminance) property failed to set expected value")
+    luminance_level_max = (
+        "Max Point (luminance) property set",
+        "P1: Max Point (luminance) property failed to set expected value")
+    surround_gamma = (
+        "Surround Gamma property set",
+        "P1: Surround Gamma property failed to set expected value")
+    gamma = (
+        "Gamma property set",
+        "P1: Gamma property failed to set expected value")
+    display_mapper_type = (
+        "Display Mapper Operation Type is correctly set",
+        "P1: Display Mapper Operation type is not as expected")
+
+
+# IsClose tolerance defaults to , 1e-9, but float values in some tests need a looser tolerance
+TOLERANCE = 1e-6
 
 
 
 
 def AtomEditorComponents_DisplayMapper_AddedToEntity():
 def AtomEditorComponents_DisplayMapper_AddedToEntity():
@@ -67,25 +113,41 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity():
     3) UNDO the entity creation and component addition.
     3) UNDO the entity creation and component addition.
     4) REDO the entity creation and component addition.
     4) REDO the entity creation and component addition.
     5) Set LDR color Grading LUT asset.
     5) Set LDR color Grading LUT asset.
-    6) Set Enable LDR color grading LUT property True
-    7) Enter/Exit game mode.
-    8) Test IsHidden.
-    9) Test IsVisible.
-    10) Delete Display Mapper entity.
-    11) UNDO deletion.
-    12) REDO deletion.
-    13) Look for errors and asserts.
+    6) Set the Display Mapper Operation Type enumerated in DISPLAY_MAPPER_OPERATION_TYPE for each type
+    7) Set Enable LDR color grading LUT property True
+    8) Toggle Override Defaults
+    9) Toggle Alter Surround
+    10) Toggle Alter Desaturation
+    11) Toggle 'Alter CAT D60 to D65'
+    12) Set 'Cinema Limit (black)' max value which is dynamic based on Cinema Limit (white) then min value
+    13) Set 'Cinema Limit (white)' max value then min, and finally back to default
+    14) Set 'Min Point (luminance)' to high and low value
+    15) Set 'Mid Point (luminance)' to high and low value then set default
+    16) Set 'Max Point (luminance)' to high and low value then set default
+    17) Set 'Surround Gamma' to high and low value
+    18) Set 'Gamma' to high and low value
+    19) Enter/Exit game mode.
+    20) Select and load each preset
+    21) Test IsHidden.
+    22) Test IsVisible.
+    23) Delete Display Mapper entity.
+    24) UNDO deletion.
+    25) REDO deletion.
+    26) Look for errors and asserts.
 
 
     :return: None
     :return: None
     """
     """
     import os
     import os
 
 
+    import azlmbr.bus as bus
     import azlmbr.legacy.general as general
     import azlmbr.legacy.general as general
+    import azlmbr.render as render
 
 
+    from azlmbr.math import Math_IsClose
     from editor_python_test_tools.asset_utils import Asset
     from editor_python_test_tools.asset_utils import Asset
     from editor_python_test_tools.editor_entity_utils import EditorEntity
     from editor_python_test_tools.editor_entity_utils import EditorEntity
     from editor_python_test_tools.utils import Report, Tracer, TestHelper
     from editor_python_test_tools.utils import Report, Tracer, TestHelper
-    from Atom.atom_utils.atom_constants import AtomComponentProperties
+    from Atom.atom_utils.atom_constants import AtomComponentProperties, DISPLAY_MAPPER_PRESET, DISPLAY_MAPPER_OPERATION_TYPE
 
 
     with Tracer() as error_tracer:
     with Tracer() as error_tracer:
         # Test setup begins.
         # Test setup begins.
@@ -129,52 +191,263 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity():
         Report.result(Tests.creation_redo, display_mapper_entity.exists())
         Report.result(Tests.creation_redo, display_mapper_entity.exists())
 
 
         # 5. Set LDR color Grading LUT asset.
         # 5. Set LDR color Grading LUT asset.
-        display_mapper_asset_path = os.path.join("TestData", "test.lightingpreset.azasset")
+        display_mapper_asset_path = os.path.join("LookupTables", "LUT_Sepia.azasset")
         display_mapper_asset = Asset.find_asset_by_path(display_mapper_asset_path, False)
         display_mapper_asset = Asset.find_asset_by_path(display_mapper_asset_path, False)
         display_mapper_component.set_component_property_value(
         display_mapper_component.set_component_property_value(
-            AtomComponentProperties.display_mapper("LDR color Grading LUT"), display_mapper_asset.id)
+            AtomComponentProperties.display_mapper('LDR color Grading LUT'), display_mapper_asset.id)
         Report.result(
         Report.result(
             Tests.ldr_color_grading_lut,
             Tests.ldr_color_grading_lut,
             display_mapper_component.get_component_property_value(
             display_mapper_component.get_component_property_value(
-                AtomComponentProperties.display_mapper("LDR color Grading LUT")) == display_mapper_asset.id)
+                AtomComponentProperties.display_mapper('LDR color Grading LUT')) == display_mapper_asset.id)
+
+        for operation_type in DISPLAY_MAPPER_OPERATION_TYPE.keys():
+            # 6. Set the Display Mapper Operation Type enumerated in DISPLAY_MAPPER_OPERATION_TYPE for each type
+            # Type property cannot be set currently. as a workaround we are calling an ebus to set the operation type
+            # A fix is in progress
+            # display_mapper_component.set_component_property_value(
+            #     AtomComponentProperties.display_mapper('Type'), DISPLAY_MAPPER_OPERATION_TYPE[operation_type])
+            render.DisplayMapperComponentRequestBus(
+                bus.Broadcast, "SetDisplayMapperOperationType", DISPLAY_MAPPER_OPERATION_TYPE[operation_type])
+            general.idle_wait_frames(3)
+            set_type = render.DisplayMapperComponentRequestBus(bus.Broadcast, "GetDisplayMapperOperationType")
+            Report.info(f"DiplayMapperOperationType: {set_type}")
+            Report.result(Tests.display_mapper_type, set_type == DISPLAY_MAPPER_OPERATION_TYPE[operation_type])
+
+            # 7. Set Enable LDR color grading LUT property True
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True)
+            Report.result(
+                Tests.enable_ldr_color_grading_lut,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True)
+
+            # 8. Toggle Override Defaults
+            # Set Override Defaults to False
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Override Defaults'), False)
+            Report.result(
+                Tests.override_defaults,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Override Defaults')) is False)
+
+            # Set Override Defaults to True
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Override Defaults'), True)
+            Report.result(
+                Tests.override_defaults,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Override Defaults')) is True)
+
+            # 9. Toggle Alter Surround
+            # Set Alter Surround to True
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Alter Surround'), True)
+            Report.result(
+                Tests.alter_surround,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Alter Surround')) is True)
+
+            # Set Alter Surround to False
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Alter Surround'), False)
+            Report.result(
+                Tests.alter_surround,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Alter Surround')) is False)
+
+            # 10. Toggle Alter Desaturation
+            # Set Alter Desaturation to True
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Alter Desaturation'), True)
+            Report.result(
+                Tests.alter_desaturation,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Alter Desaturation')) is True)
+
+            # Set Alter Desaturation to False
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Alter Desaturation'), False)
+            Report.result(
+                Tests.alter_desaturation,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Alter Desaturation')) is False)
+
+            # 11. Toggle 'Alter CAT D60 to D65'
+            # Set 'Alter CAT D60 to D65' to True
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Alter CAT D60 to D65'), True)
+            Report.result(
+                Tests.alter_cat,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Alter CAT D60 to D65')) is True)
+
+            # Set 'Alter CAT D60 to D65' to False
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Alter CAT D60 to D65'), False)
+            Report.result(
+                Tests.alter_cat,
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Alter CAT D60 to D65')) is False)
+
+            general.idle_wait_frames(1)
+
+            # 12. Set 'Cinema Limit (black)' max value which is dynamic based on Cinema Limit (white) then min value
+            # set max value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (black)'), value=48.0)
+            Report.result(Tests.black_level_max, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (black)')), 48.0, TOLERANCE))
+
+            # set min value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (black)'), value=0.02)
+            Report.result(Tests.black_level_min, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (black)')), 0.02, TOLERANCE))
+
+            # 13. Set 'Cinema Limit (white)' maximum value then min, and finally back to default
+            # set max value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (white)'), value=4000.0)
+            Report.result(Tests.white_level_max, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (white)')), 4000.0, TOLERANCE))
+
+            # Set min value which is dynamic based on Cinema Limit (black)
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (white)'), value=0.02)
+            Report.result(Tests.white_level_min, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (white)')), 0.02, TOLERANCE))
+
+            # Reset this to the default 48 so following cycles don't impact Cinema Limit (Black)
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Cinema Limit (white)'), value=48.0)
+
+            # 14. Set 'Min Point (luminance)' to high and low value
+            # set high value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Min Point (luminance)'), value=4.8)
+            Report.info(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Min Point (luminance)')))
+            Report.result(Tests.luminance_level_min, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Min Point (luminance)')), 4.8, TOLERANCE))
+
+            # set low value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Min Point (luminance)'), value=0.002)
+            Report.result(Tests.luminance_level_min, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Min Point (luminance)')), 0.002, TOLERANCE))
+
+            # 15. Set 'Mid Point (luminance)' to high and low value then set default
+            # set high value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Mid Point (luminance)'), value=1005.0)
+            Report.result(Tests.luminance_level_mid, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Mid Point (luminance)')), 1005.0, TOLERANCE))
+
+            # set low value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Mid Point (luminance)'), value=0.002)
+            Report.result(Tests.luminance_level_mid, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Mid Point (luminance)')), 0.002, TOLERANCE))
+
+            # restore the default since as this impacts the range of 'Min Point (luminance)'
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Mid Point (luminance)'), value=4.8)
+
+            # 16. Set 'Max Point (luminance)' to high and low value then set default
+            # set a high value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Max Point (luminance)'), value=4000.0)
+            Report.result(Tests.luminance_level_max, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Max Point (luminance)')), 4000.0, TOLERANCE))
+
+            # set a low value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Max Point (luminance)'), value=0.002)
+            Report.result(Tests.luminance_level_max, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Max Point (luminance)')), 0.002, TOLERANCE))
+
+            # restore the default since this impacts the range of 'Mid Point (luminance)'
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Max Point (luminance)'), value=1005.7191162)
+
+            # 17. Set 'Surround Gamma' to high and low value
+            # set a high value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Surround Gamma'), value=1.2)
+            Report.result(Tests.surround_gamma, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Surround Gamma')), 1.2, TOLERANCE))
+
+            # set a low value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Surround Gamma'), value=0.6)
+            Report.result(Tests.surround_gamma, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Surround Gamma')), 0.6, TOLERANCE))
+
+            # 18. Set 'Gamma' to high and low value
+            # set a high value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Gamma'), value=4.0)
+            Report.result(Tests.gamma, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Gamma')), 4.0, TOLERANCE))
+
+            # set a low value
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Gamma'), value=0.2)
+            Report.result(Tests.gamma, Math_IsClose(display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Gamma')), 0.2, TOLERANCE))
+
+            # 19. Enter/Exit game mode.
+            TestHelper.enter_game_mode(Tests.enter_game_mode)
+            general.idle_wait_frames(1)
+            TestHelper.exit_game_mode(Tests.exit_game_mode)
+
+            display_mapper_component.set_component_property_value(
+                AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), False)
 
 
-        # 6. Set Enable LDR color grading LUT property True
         display_mapper_component.set_component_property_value(
         display_mapper_component.set_component_property_value(
             AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True)
             AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True)
-        Report.result(
-            Tests.enable_ldr_color_grading_lut,
-            display_mapper_component.get_component_property_value(
-                AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True)
 
 
-        # 7. Enter/Exit game mode.
-        TestHelper.enter_game_mode(Tests.enter_game_mode)
-        general.idle_wait_frames(1)
-        TestHelper.exit_game_mode(Tests.exit_game_mode)
+        cinema_limit_white_presets = [48.0, 184.3200073, 368.6400146, 737.2800293]
+        for preset in DISPLAY_MAPPER_PRESET.keys():
+            # 20. Select and load each preset
+            # Preset Selection cannot be set or loaded currently; as a workaround we are calling an ebus to load preset
+            # A fix is in progress
+            # display_mapper_component.set_component_property_value(
+            #     AtomComponentProperties.display_mapper('Preset Selection'), DISPLAY_MAPPER_PRESET[preset])
+            render.DisplayMapperComponentRequestBus(bus.Broadcast, "LoadPreset", DISPLAY_MAPPER_PRESET[preset])
+            general.idle_wait_frames(1)
+            # check some value to confirm preset loaded
+            test_preset = (f"Preset {preset} loaded expected value",
+                           f"P1: Preset {preset} failed to load values as expected")
+            Report.result(test_preset, Math_IsClose(
+                display_mapper_component.get_component_property_value(
+                    AtomComponentProperties.display_mapper('Cinema Limit (white)')),
+                cinema_limit_white_presets[DISPLAY_MAPPER_PRESET[preset]], TOLERANCE))
 
 
-        # 8. Test IsHidden.
+        # 21. Test IsHidden.
         display_mapper_entity.set_visibility_state(False)
         display_mapper_entity.set_visibility_state(False)
         Report.result(Tests.is_hidden, display_mapper_entity.is_hidden() is True)
         Report.result(Tests.is_hidden, display_mapper_entity.is_hidden() is True)
 
 
-        # 9. Test IsVisible.
+        # 22. Test IsVisible.
         display_mapper_entity.set_visibility_state(True)
         display_mapper_entity.set_visibility_state(True)
         general.idle_wait_frames(1)
         general.idle_wait_frames(1)
         Report.result(Tests.is_visible, display_mapper_entity.is_visible() is True)
         Report.result(Tests.is_visible, display_mapper_entity.is_visible() is True)
 
 
-        # 10. Delete Display Mapper entity.
+        # 23. Delete Display Mapper entity.
         display_mapper_entity.delete()
         display_mapper_entity.delete()
         Report.result(Tests.entity_deleted, not display_mapper_entity.exists())
         Report.result(Tests.entity_deleted, not display_mapper_entity.exists())
 
 
-        # 11. UNDO deletion.
+        # 24. UNDO deletion.
         general.undo()
         general.undo()
         general.idle_wait_frames(1)
         general.idle_wait_frames(1)
         Report.result(Tests.deletion_undo, display_mapper_entity.exists())
         Report.result(Tests.deletion_undo, display_mapper_entity.exists())
 
 
-        # 12. REDO deletion.
+        # 25. REDO deletion.
         general.redo()
         general.redo()
         general.idle_wait_frames(1)
         general.idle_wait_frames(1)
         Report.result(Tests.deletion_redo, not display_mapper_entity.exists())
         Report.result(Tests.deletion_redo, not display_mapper_entity.exists())
 
 
-        # 13. Look for errors and asserts.
+        # 26. Look for errors and asserts.
         TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
         TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
         for error_info in error_tracer.errors:
         for error_info in error_tracer.errors:
             Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
             Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")

+ 0 - 6
AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py

@@ -5,14 +5,8 @@ For complete copyright and license terms please see the LICENSE at the root of t
 SPDX-License-Identifier: Apache-2.0 OR MIT
 SPDX-License-Identifier: Apache-2.0 OR MIT
 """
 """
 
 
-import os
-import sys
-
 import azlmbr.legacy.general as general
 import azlmbr.legacy.general as general
 
 
-sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
-
-import editor_python_test_tools.hydra_editor_utils as hydra
 from editor_python_test_tools.editor_test_helper import EditorTestHelper
 from editor_python_test_tools.editor_test_helper import EditorTestHelper
 from Atom.atom_utils.benchmark_utils import BenchmarkHelper
 from Atom.atom_utils.benchmark_utils import BenchmarkHelper
 
 

+ 1 - 1
AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands_test_case.py

@@ -128,7 +128,7 @@ if len(sys.argv) > 1:
 
 
 # Open a level (any level should work)
 # Open a level (any level should work)
 general.create_level_no_prompt('LevelComponentTest', 128, 1, 512, True)
 general.create_level_no_prompt('LevelComponentTest', 128, 1, 512, True)
-# Make sure the default slices get a chance to initialize.
+# Make sure the default prefabs get a chance to initialize.
 general.idle_wait(1.0)
 general.idle_wait(1.0)
 
 
 # Generate List of Component Types
 # Generate List of Component Types

+ 27 - 2
AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Main.py

@@ -8,10 +8,19 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
 
 
 import pytest
 import pytest
 import os
 import os
-import sys
 from ly_test_tools.o3de.editor_test import EditorTestSuite, EditorSingleTest
 from ly_test_tools.o3de.editor_test import EditorTestSuite, EditorSingleTest
 
 
-sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
+
+# Saves the level cache folder.
+# These artifacts will be saved in the test results so developers can access the level assets
+# to debug should the test ever fail.
+def save_multiplayer_level_cache_folder_artifact(workspace, multiplayer_level):
+    level_cache_folder_path = os.path.join(workspace.paths.platform_cache(), "levels", "multiplayer", multiplayer_level)
+
+    if os.path.exists(level_cache_folder_path):
+        workspace.artifact_manager.save_artifact(level_cache_folder_path)
+    else:
+        pytest.fail(f"Failed to find level asset cache for '{multiplayer_level}', located here: '{level_cache_folder_path}'! Make sure AssetProcessor successfully built the level.")
 
 
 @pytest.mark.SUITE_main
 @pytest.mark.SUITE_main
 @pytest.mark.parametrize("project", ["AutomatedTesting"])
 @pytest.mark.parametrize("project", ["AutomatedTesting"])
@@ -20,12 +29,28 @@ class TestAutomation(EditorTestSuite):
     class test_Multiplayer_AutoComponent_NetworkInput(EditorSingleTest):
     class test_Multiplayer_AutoComponent_NetworkInput(EditorSingleTest):
         from .tests import Multiplayer_AutoComponent_NetworkInput as test_module
         from .tests import Multiplayer_AutoComponent_NetworkInput as test_module
 
 
+        @classmethod
+        def setup(cls, instance, request, workspace, editor, editor_test_results, launcher_platform):
+            save_multiplayer_level_cache_folder_artifact(workspace, "autocomponent_networkinput")
+
     class test_Multiplayer_AutoComponent_RPC(EditorSingleTest):
     class test_Multiplayer_AutoComponent_RPC(EditorSingleTest):
         from .tests import Multiplayer_AutoComponent_RPC as test_module
         from .tests import Multiplayer_AutoComponent_RPC as test_module
 
 
+        @classmethod
+        def setup(cls, instance, request, workspace, editor, editor_test_results, launcher_platform):
+            save_multiplayer_level_cache_folder_artifact(workspace, "autocomponent_rpc")
+
     class test_Multiplayer_BasicConnectivity_Connects(EditorSingleTest):
     class test_Multiplayer_BasicConnectivity_Connects(EditorSingleTest):
         from .tests import Multiplayer_BasicConnectivity_Connects as test_module
         from .tests import Multiplayer_BasicConnectivity_Connects as test_module
 
 
+        @classmethod
+        def setup(cls, instance, request, workspace, editor, editor_test_results, launcher_platform):
+            save_multiplayer_level_cache_folder_artifact(workspace, "basicconnectivity_connects")
+
     class test_Multiplayer_SimpleNetworkLevelEntity(EditorSingleTest):
     class test_Multiplayer_SimpleNetworkLevelEntity(EditorSingleTest):
         from .tests import Multiplayer_SimpleNetworkLevelEntity as test_module
         from .tests import Multiplayer_SimpleNetworkLevelEntity as test_module
 
 
+        @classmethod
+        def setup(cls, instance, request, workspace, editor, editor_test_results, launcher_platform):
+            save_multiplayer_level_cache_folder_artifact(workspace, "simplenetworklevelentity")
+

+ 8 - 8
AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests.py

@@ -674,14 +674,14 @@ class TestsAssetProcessorBatch_AllPlatforms(object):
 
 
     @pytest.mark.BAT
     @pytest.mark.BAT
     @pytest.mark.assetpipeline
     @pytest.mark.assetpipeline
-    @pytest.mark.skip(reason="update assets from .slice to a different type to test preload cyclical dependencies")
+    @pytest.mark.skip(reason="GHI: 8,365 Update assets from .prefab to a different type to test preload cyclical dependencies")
     def test_validateDirectPreloadDependency_Found(self, asset_processor, ap_setup_fixture, workspace):
     def test_validateDirectPreloadDependency_Found(self, asset_processor, ap_setup_fixture, workspace):
         """
         """
         Tests processing an asset with a circular dependency and verifies that Asset Processor will return an error
         Tests processing an asset with a circular dependency and verifies that Asset Processor will return an error
         notifying the user about a circular dependency.
         notifying the user about a circular dependency.
 
 
         Test Steps:
         Test Steps:
-        1. Create test environment with an asset that has a circular dependency
+        1. Create test environment with an asset that has a preload circular dependency
         2. Launch asset processor
         2. Launch asset processor
         3. Verify that error is returned informing the user that the asset has a circular dependency
         3. Verify that error is returned informing the user that the asset has a circular dependency
         """
         """
@@ -692,23 +692,23 @@ class TestsAssetProcessorBatch_AllPlatforms(object):
 
 
         success, output = asset_processor.batch_process(capture_output=True, expect_failure=False)
         success, output = asset_processor.batch_process(capture_output=True, expect_failure=False)
         log = APOutputParser(output)
         log = APOutputParser(output)
-        for _ in log.get_lines(-1, ["Preload circular dependency detected", "testc.dynamicslice"]):
+        for _ in log.get_lines(-1, ["Preload circular dependency detected", "testc.prefab"]):
             error_line_found = True
             error_line_found = True
 
 
         assert error_line_found, "The error could not be found in the newest run of the AP Batch log."
         assert error_line_found, "The error could not be found in the newest run of the AP Batch log."
 
 
     @pytest.mark.BAT
     @pytest.mark.BAT
     @pytest.mark.assetpipeline
     @pytest.mark.assetpipeline
-    @pytest.mark.skip(reason="need to change assets from .slice files to an asset type that can have nested dependencies")
+    @pytest.mark.skip(reason="GHI: 8,365 Update assets from .prefab to an asset type that can have nested preload dependencies")
     def test_validateNestedPreloadDependency_Found(self, asset_processor, ap_setup_fixture, workspace):
     def test_validateNestedPreloadDependency_Found(self, asset_processor, ap_setup_fixture, workspace):
         """
         """
-        Tests processing of a nested circular dependency and verifies that Asset Processor will return an error
+        Tests processing of a nested preload circular dependency and verifies that Asset Processor will return an error
         notifying the user about a circular dependency.
         notifying the user about a circular dependency.
 
 
         Test Steps:
         Test Steps:
-        1. Create test environment with an asset that has a nested circular dependency
+        1. Create test environment with an asset that has a nested preload circular dependency
         2. Launch asset processor
         2. Launch asset processor
-        3. Verify that error is returned informing the user that the asset has a circular dependency
+        3. Verify that error is returned informing the user that the asset has a preload circular dependency
         """
         """
 
 
         env = ap_setup_fixture
         env = ap_setup_fixture
@@ -718,7 +718,7 @@ class TestsAssetProcessorBatch_AllPlatforms(object):
 
 
         success, output = asset_processor.batch_process(capture_output=True, expect_failure=False)
         success, output = asset_processor.batch_process(capture_output=True, expect_failure=False)
         log = APOutputParser(output)
         log = APOutputParser(output)
-        for _ in log.get_lines(-1, ["Preload circular dependency detected", "testa.dynamicslice"]):
+        for _ in log.get_lines(-1, ["Preload circular dependency detected", "testa.prefab"]):
             error_line_found = True
             error_line_found = True
 
 
         assert error_line_found, "The error could not be found in the newest run of the AP Batch log."
         assert error_line_found, "The error could not be found in the newest run of the AP Batch log."

+ 0 - 174
AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/assets_with_direct_preload_dependency/TestC.slice

@@ -1,174 +0,0 @@
-<ObjectStream version="3">
-	<Class name="AZ::Entity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-		<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-			<Class name="AZ::u64" field="id" value="1295506446949" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		</Class>
-		<Class name="AZStd::string" field="Name" value="Slice" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-		<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-			<Class name="SliceComponent" field="element" version="3" type="{AFD304E4-1773-47C8-855A-8B622398934F}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="15843242153155423542" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-				<Class name="AZStd::vector" field="Entities" type="{21786AF0-2606-5B9A-86EB-0892E2820E6C}">
-					<Class name="AZ::Entity" field="element" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-						<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-							<Class name="AZ::u64" field="id" value="1304096381541" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-						</Class>
-						<Class name="AZStd::string" field="Name" value="TestC" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-						<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-							<Class name="EditorOnlyEntityComponent" field="element" type="{22A16F1D-6D49-422D-AAE9-91AE45B5D3E7}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="7006315855742782669" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="bool" field="IsEditorOnly" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="TransformComponent" field="element" version="9" type="{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="3584527199662731007" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="EntityId" field="Parent Entity" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-									<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-								<Class name="EditorTransform" field="Transform Data" version="2" type="{B02B7063-D238-4F40-A724-405F7A6D68CB}">
-									<Class name="Vector3" field="Translate" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
-									<Class name="Vector3" field="Rotate" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
-									<Class name="Vector3" field="Scale" value="1.0000000 1.0000000 1.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
-									<Class name="bool" field="Locked" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								</Class>
-								<Class name="Transform" field="Cached World Transform" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000" type="{5D9958E9-9F1E-4985-B532-FFFDE75FEDFD}"/>
-								<Class name="EntityId" field="Cached World Transform Parent" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-									<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-								<Class name="unsigned int" field="Parent Activation Transform Mode" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-								<Class name="bool" field="IsStatic" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								<Class name="bool" field="Sync Enabled" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								<Class name="unsigned int" field="InterpolatePosition" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-								<Class name="unsigned int" field="InterpolateRotation" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-							</Class>
-							<Class name="EditorInspectorComponent" field="element" version="2" type="{47DE3DDA-50C5-4F50-B1DB-BA4AE66AB056}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="7706925336429309894" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="ComponentOrderEntryArray" type="{B6EFED5B-19B4-5084-9D92-42DECCE83872}">
-									<Class name="ComponentOrderEntry" field="element" version="1" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}">
-										<Class name="AZ::u64" field="ComponentId" value="3584527199662731007" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-										<Class name="AZ::u64" field="SortIndex" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-									<Class name="ComponentOrderEntry" field="element" version="1" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}">
-										<Class name="AZ::u64" field="ComponentId" value="251416810686704101" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-										<Class name="AZ::u64" field="SortIndex" value="1" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-							</Class>
-							<Class name="EditorEntitySortComponent" field="element" version="2" type="{6EA1E03D-68B2-466D-97F7-83998C8C27F0}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="2232445749633468678" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="ChildEntityOrderEntryArray" type="{BE163120-C1ED-5F69-A650-DC2528A8FF94}"/>
-							</Class>
-							<Class name="SelectionComponent" field="element" type="{73B724FC-43D1-4C75-ACF5-79AA8A3BF89D}">
-								<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-									<Class name="AZ::u64" field="Id" value="5414135994254332294" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-							</Class>
-							<Class name="EditorSpawnerComponent" field="element" version="1" type="{77CDE991-EC1A-B7C1-B112-7456ABAC81A1}">
-								<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-									<Class name="AZ::u64" field="Id" value="251416810686704101" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-								<Class name="Asset" field="Slice" value="id={56FC3E9D-3FE4-592F-B6FF-8DF2EBD44B16}:2,type={78802ABF-9595-463A-8D2B-D022F906F9B1},hint={assets_with_direct_preload_dependency/testd.dynamicslice}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
-								<Class name="bool" field="SpawnOnActivate" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								<Class name="bool" field="DestroyOnDeactivate" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="EditorVisibilityComponent" field="element" type="{88E08E78-5C2F-4943-9F73-C115E6FFAB43}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="18139478027057937842" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="bool" field="VisibilityFlag" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="EditorLockComponent" field="element" type="{C3A169C9-7EFB-4D6C-8710-3591680D0936}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="11193408165200254248" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="bool" field="Locked" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="EditorPendingCompositionComponent" field="element" type="{D40FCB35-153D-45B3-AF6D-7BA576D8AFBB}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="7509785945442840634" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="PendingComponents" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}"/>
-							</Class>
-							<Class name="EditorEntityIconComponent" field="element" type="{E15D42C2-912D-466F-9547-E7E948CE2D7D}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="10935675379356727788" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AssetId" field="EntityIconAssetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-									<Class name="AZ::Uuid" field="guid" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-									<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-								</Class>
-							</Class>
-							<Class name="EditorDisabledCompositionComponent" field="element" type="{E77AE6AC-897D-4035-8353-637449B6DCFB}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="17579734367307202992" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="DisabledComponents" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}"/>
-							</Class>
-						</Class>
-						<Class name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-						<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-					</Class>
-				</Class>
-				<Class name="AZStd::list" field="Prefabs" type="{DAD45EB6-5853-5645-B762-3A37F8775E12}"/>
-				<Class name="bool" field="IsDynamic" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-				<Class name="AZ::Entity" field="MetadataEntity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-					<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-						<Class name="AZ::u64" field="id" value="1299801414245" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-					</Class>
-					<Class name="AZStd::string" field="Name" value="No Asset Association" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-					<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-						<Class name="SliceMetadataInfoComponent" field="element" version="2" type="{25EE4D75-8A17-4449-81F4-E561005BAABD}">
-							<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-								<Class name="AZ::u64" field="Id" value="11042881146501432583" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-							</Class>
-							<Class name="AZStd::set" field="AssociatedIds" type="{78E024C3-0143-53FC-B393-0675227839AF}">
-								<Class name="EntityId" field="element" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-									<Class name="AZ::u64" field="id" value="1304096381541" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-							</Class>
-							<Class name="EntityId" field="ParentId" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-								<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-							</Class>
-							<Class name="AZStd::unordered_set" field="ChildrenIds" type="{6C8F8E52-AB4A-5C1F-8E56-9AC390290B94}"/>
-							<Class name="bool" field="PersistenceFlag" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-						</Class>
-					</Class>
-					<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-					<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-				</Class>
-				<Class name="DataFlagsPerEntity" field="DataFlagsForNewEntities" version="1" type="{57FE7B9E-B2AF-4F6F-9F8D-87F671E91C99}">
-					<Class name="AZStd::unordered_map" field="EntityToDataFlags" type="{CAB9E1F5-761E-54B8-916E-E7FB597E5EDE}"/>
-				</Class>
-			</Class>
-		</Class>
-		<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-	</Class>
-</ObjectStream>
-

+ 0 - 174
AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/assets_with_direct_preload_dependency/TestD.slice

@@ -1,174 +0,0 @@
-<ObjectStream version="3">
-	<Class name="AZ::Entity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-		<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-			<Class name="AZ::u64" field="id" value="382257329386" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		</Class>
-		<Class name="AZStd::string" field="Name" value="Slice" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-		<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-			<Class name="SliceComponent" field="element" version="3" type="{AFD304E4-1773-47C8-855A-8B622398934F}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="10124611306244674550" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-				<Class name="AZStd::vector" field="Entities" type="{21786AF0-2606-5B9A-86EB-0892E2820E6C}">
-					<Class name="AZ::Entity" field="element" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-						<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-							<Class name="AZ::u64" field="id" value="390847263978" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-						</Class>
-						<Class name="AZStd::string" field="Name" value="TestB" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-						<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-							<Class name="EditorOnlyEntityComponent" field="element" type="{22A16F1D-6D49-422D-AAE9-91AE45B5D3E7}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="9595291727352692926" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="bool" field="IsEditorOnly" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="TransformComponent" field="element" version="9" type="{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="6918190889556026264" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="EntityId" field="Parent Entity" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-									<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-								<Class name="EditorTransform" field="Transform Data" version="2" type="{B02B7063-D238-4F40-A724-405F7A6D68CB}">
-									<Class name="Vector3" field="Translate" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
-									<Class name="Vector3" field="Rotate" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
-									<Class name="Vector3" field="Scale" value="1.0000000 1.0000000 1.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
-									<Class name="bool" field="Locked" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								</Class>
-								<Class name="Transform" field="Cached World Transform" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000" type="{5D9958E9-9F1E-4985-B532-FFFDE75FEDFD}"/>
-								<Class name="EntityId" field="Cached World Transform Parent" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-									<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-								<Class name="unsigned int" field="Parent Activation Transform Mode" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-								<Class name="bool" field="IsStatic" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								<Class name="bool" field="Sync Enabled" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								<Class name="unsigned int" field="InterpolatePosition" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-								<Class name="unsigned int" field="InterpolateRotation" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-							</Class>
-							<Class name="EditorInspectorComponent" field="element" version="2" type="{47DE3DDA-50C5-4F50-B1DB-BA4AE66AB056}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="16488522651299490860" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="ComponentOrderEntryArray" type="{B6EFED5B-19B4-5084-9D92-42DECCE83872}">
-									<Class name="ComponentOrderEntry" field="element" version="1" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}">
-										<Class name="AZ::u64" field="ComponentId" value="6918190889556026264" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-										<Class name="AZ::u64" field="SortIndex" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-									<Class name="ComponentOrderEntry" field="element" version="1" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}">
-										<Class name="AZ::u64" field="ComponentId" value="1133009518516046488" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-										<Class name="AZ::u64" field="SortIndex" value="1" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-							</Class>
-							<Class name="EditorEntitySortComponent" field="element" version="2" type="{6EA1E03D-68B2-466D-97F7-83998C8C27F0}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="6551321942498556777" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="ChildEntityOrderEntryArray" type="{BE163120-C1ED-5F69-A650-DC2528A8FF94}"/>
-							</Class>
-							<Class name="SelectionComponent" field="element" type="{73B724FC-43D1-4C75-ACF5-79AA8A3BF89D}">
-								<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-									<Class name="AZ::u64" field="Id" value="5168720242367005303" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-							</Class>
-							<Class name="EditorSpawnerComponent" field="element" version="1" type="{77CDE991-EC1A-B7C1-B112-7456ABAC81A1}">
-								<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-									<Class name="AZ::u64" field="Id" value="1133009518516046488" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-								<Class name="Asset" field="Slice" value="id={A4A3A611-18D0-536C-99D9-134A644AAA70}:2,type={78802ABF-9595-463A-8D2B-D022F906F9B1},hint={assets_with_direct_preload_dependency/testc.dynamicslice}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
-								<Class name="bool" field="SpawnOnActivate" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								<Class name="bool" field="DestroyOnDeactivate" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="EditorVisibilityComponent" field="element" type="{88E08E78-5C2F-4943-9F73-C115E6FFAB43}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="17020070072341888679" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="bool" field="VisibilityFlag" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="EditorLockComponent" field="element" type="{C3A169C9-7EFB-4D6C-8710-3591680D0936}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="16300364923199181818" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="bool" field="Locked" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="EditorPendingCompositionComponent" field="element" type="{D40FCB35-153D-45B3-AF6D-7BA576D8AFBB}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="3997039705476816210" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="PendingComponents" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}"/>
-							</Class>
-							<Class name="EditorEntityIconComponent" field="element" type="{E15D42C2-912D-466F-9547-E7E948CE2D7D}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="10323419800905366237" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AssetId" field="EntityIconAssetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-									<Class name="AZ::Uuid" field="guid" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-									<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-								</Class>
-							</Class>
-							<Class name="EditorDisabledCompositionComponent" field="element" type="{E77AE6AC-897D-4035-8353-637449B6DCFB}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="2409852450700585411" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="DisabledComponents" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}"/>
-							</Class>
-						</Class>
-						<Class name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-						<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-					</Class>
-				</Class>
-				<Class name="AZStd::list" field="Prefabs" type="{DAD45EB6-5853-5645-B762-3A37F8775E12}"/>
-				<Class name="bool" field="IsDynamic" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-				<Class name="AZ::Entity" field="MetadataEntity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-					<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-						<Class name="AZ::u64" field="id" value="386552296682" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-					</Class>
-					<Class name="AZStd::string" field="Name" value="No Asset Association" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-					<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-						<Class name="SliceMetadataInfoComponent" field="element" version="2" type="{25EE4D75-8A17-4449-81F4-E561005BAABD}">
-							<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-								<Class name="AZ::u64" field="Id" value="6483308780985076120" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-							</Class>
-							<Class name="AZStd::set" field="AssociatedIds" type="{78E024C3-0143-53FC-B393-0675227839AF}">
-								<Class name="EntityId" field="element" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-									<Class name="AZ::u64" field="id" value="390847263978" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-							</Class>
-							<Class name="EntityId" field="ParentId" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-								<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-							</Class>
-							<Class name="AZStd::unordered_set" field="ChildrenIds" type="{6C8F8E52-AB4A-5C1F-8E56-9AC390290B94}"/>
-							<Class name="bool" field="PersistenceFlag" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-						</Class>
-					</Class>
-					<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-					<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-				</Class>
-				<Class name="DataFlagsPerEntity" field="DataFlagsForNewEntities" version="1" type="{57FE7B9E-B2AF-4F6F-9F8D-87F671E91C99}">
-					<Class name="AZStd::unordered_map" field="EntityToDataFlags" type="{CAB9E1F5-761E-54B8-916E-E7FB597E5EDE}"/>
-				</Class>
-			</Class>
-		</Class>
-		<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-	</Class>
-</ObjectStream>
-

+ 0 - 222
AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/assets_with_nested_preload_dependency/TestA.slice

@@ -1,222 +0,0 @@
-<ObjectStream version="3">
-	<Class name="AZ::Entity" type="{75651658-8663-478D-9090-2432DFCAFA44}" version="2">
-		<Class field="Id" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
-			<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="269594828358" />
-		</Class>
-		<Class field="Name" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="Slice" />
-		<Class field="Components" name="AZStd::vector" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-			<Class field="element" name="SliceComponent" type="{AFD304E4-1773-47C8-855A-8B622398934F}" version="3">
-				<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="13642727600084297375" />
-				</Class>
-				<Class field="Entities" name="AZStd::vector" type="{21786AF0-2606-5B9A-86EB-0892E2820E6C}">
-					<Class field="element" name="AZ::Entity" type="{75651658-8663-478D-9090-2432DFCAFA44}" version="2">
-						<Class field="Id" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
-							<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="278184762950" />
-						</Class>
-						<Class field="Name" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="TestE" />
-						<Class field="Components" name="AZStd::vector" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-							<Class field="element" name="EditorOnlyEntityComponent" type="{22A16F1D-6D49-422D-AAE9-91AE45B5D3E7}">
-								<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
-									<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="16738199190794244171" />
-									</Class>
-								</Class>
-								<Class field="IsEditorOnly" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
-							</Class>
-							<Class field="element" name="TransformComponent" type="{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0}" version="9">
-								<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
-									<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="16210900323787785224" />
-									</Class>
-								</Class>
-								<Class field="Parent Entity" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
-									<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="4294967295" />
-								</Class>
-								<Class field="Transform Data" name="EditorTransform" type="{B02B7063-D238-4F40-A724-405F7A6D68CB}" version="2">
-									<Class field="Translate" name="Vector3" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}" value="0.0000000 0.0000000 0.0000000" />
-									<Class field="Rotate" name="Vector3" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}" value="0.0000000 0.0000000 0.0000000" />
-									<Class field="Scale" name="Vector3" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}" value="1.0000000 1.0000000 1.0000000" />
-									<Class field="Locked" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
-								</Class>
-								<Class field="Cached World Transform" name="Transform" type="{5D9958E9-9F1E-4985-B532-FFFDE75FEDFD}" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000" />
-								<Class field="Cached World Transform Parent" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
-									<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="4294967295" />
-								</Class>
-								<Class field="Parent Activation Transform Mode" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
-								<Class field="IsStatic" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
-								<Class field="Sync Enabled" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
-								<Class field="InterpolatePosition" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
-								<Class field="InterpolateRotation" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
-							</Class>
-							<Class field="element" name="EditorInspectorComponent" type="{47DE3DDA-50C5-4F50-B1DB-BA4AE66AB056}" version="2">
-								<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
-									<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="7735546012552452863" />
-									</Class>
-								</Class>
-								<Class field="ComponentOrderEntryArray" name="AZStd::vector" type="{B6EFED5B-19B4-5084-9D92-42DECCE83872}">
-									<Class field="element" name="ComponentOrderEntry" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}" version="1">
-										<Class field="ComponentId" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="16210900323787785224" />
-										<Class field="SortIndex" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="0" />
-									</Class>
-									<Class field="element" name="ComponentOrderEntry" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}" version="1">
-										<Class field="ComponentId" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="4070968465717414181" />
-										<Class field="SortIndex" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="1" />
-									</Class>
-									<Class field="element" name="ComponentOrderEntry" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}" version="1">
-										<Class field="ComponentId" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="8906495340202656540" />
-										<Class field="SortIndex" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="2" />
-									</Class>
-								</Class>
-							</Class>
-							<Class field="element" name="EditorEntitySortComponent" type="{6EA1E03D-68B2-466D-97F7-83998C8C27F0}" version="2">
-								<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
-									<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="9760814841523354339" />
-									</Class>
-								</Class>
-								<Class field="ChildEntityOrderEntryArray" name="AZStd::vector" type="{BE163120-C1ED-5F69-A650-DC2528A8FF94}" />
-							</Class>
-							<Class field="element" name="SelectionComponent" type="{73B724FC-43D1-4C75-ACF5-79AA8A3BF89D}">
-								<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-									<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="8339376805608654145" />
-								</Class>
-							</Class>
-							<Class field="element" name="EditorSpawnerComponent" type="{77CDE991-EC1A-B7C1-B112-7456ABAC81A1}" version="1">
-								<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-									<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="4070968465717414181" />
-								</Class>
-								<Class field="Slice" name="Asset" type="{77A19D40-8731-4D3C-9041-1B43047366A4}" value="id={F6621671-E624-53B1-BEB8-EB028B777B4C}:2,type={78802ABF-9595-463A-8D2B-D022F906F9B1},hint={assets_with_nested_preload_dependency/testd.dynamicslice}" version="1" />
-								<Class field="SpawnOnActivate" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
-								<Class field="DestroyOnDeactivate" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
-							</Class>
-							<Class field="element" name="EditorVisibilityComponent" type="{88E08E78-5C2F-4943-9F73-C115E6FFAB43}">
-								<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
-									<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="10678724437556014335" />
-									</Class>
-								</Class>
-								<Class field="VisibilityFlag" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
-							</Class>
-							<Class field="element" name="EditorActorComponent" type="{A863EE1B-8CFD-4EDD-BA0D-1CEC2879AD44}" version="4">
-								<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
-									<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="8906495340202656540" />
-									</Class>
-								</Class>
-								<Class field="ActorAsset" name="Asset" type="{77A19D40-8731-4D3C-9041-1B43047366A4}" value="id={58BE9DA5-1F17-53B9-8CEE-EEB10E63454D}:914f19b7,type={F67CC648-EA51-464C-9F5D-4A9CE41A7F86},hint={objects/characters/jack/jack.actor}" version="1" />
-								<Class field="MaterialPerLOD" name="AZStd::vector" type="{BB800BD1-3E2D-5089-8423-F400597960FF}">
-									<Class field="element" name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}" version="1">
-										<Class field="BaseClass1" name="SimpleAssetReferenceBase" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}" version="1">
-											<Class field="AssetPath" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="objects/characters/jack/jack.mtl" />
-										</Class>
-									</Class>
-									<Class field="element" name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}" version="1">
-										<Class field="BaseClass1" name="SimpleAssetReferenceBase" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}" version="1">
-											<Class field="AssetPath" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="objects/characters/jack/jack.mtl" />
-										</Class>
-									</Class>
-									<Class field="element" name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}" version="1">
-										<Class field="BaseClass1" name="SimpleAssetReferenceBase" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}" version="1">
-											<Class field="AssetPath" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="objects/characters/jack/jack.mtl" />
-										</Class>
-									</Class>
-									<Class field="element" name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}" version="1">
-										<Class field="BaseClass1" name="SimpleAssetReferenceBase" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}" version="1">
-											<Class field="AssetPath" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="objects/characters/jack/jack.mtl" />
-										</Class>
-									</Class>
-								</Class>
-								<Class field="MaterialPerActor" name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}" version="1">
-									<Class field="BaseClass1" name="SimpleAssetReferenceBase" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}" version="1">
-										<Class field="AssetPath" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="objects/characters/jack/jack.mtl" />
-									</Class>
-								</Class>
-								<Class field="AttachmentType" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
-								<Class field="AttachmentTarget" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
-									<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="4294967295" />
-								</Class>
-								<Class field="RenderSkeleton" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
-								<Class field="RenderCharacter" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
-								<Class field="RenderBounds" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
-								<Class field="SkinningMethod" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
-								<Class field="UpdateJointTransformsWhenOutOfView" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
-								<Class field="LodLevel" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
-							</Class>
-							<Class field="element" name="EditorLockComponent" type="{C3A169C9-7EFB-4D6C-8710-3591680D0936}">
-								<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
-									<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="2755228366872136502" />
-									</Class>
-								</Class>
-								<Class field="Locked" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
-							</Class>
-							<Class field="element" name="EditorPendingCompositionComponent" type="{D40FCB35-153D-45B3-AF6D-7BA576D8AFBB}">
-								<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
-									<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="2364131805451940550" />
-									</Class>
-								</Class>
-								<Class field="PendingComponents" name="AZStd::vector" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}" />
-							</Class>
-							<Class field="element" name="EditorEntityIconComponent" type="{E15D42C2-912D-466F-9547-E7E948CE2D7D}">
-								<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
-									<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="15019118415351685531" />
-									</Class>
-								</Class>
-								<Class field="EntityIconAssetId" name="AssetId" type="{652ED536-3402-439B-AEBE-4A5DBC554085}" version="1">
-									<Class field="guid" name="AZ::Uuid" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}" value="{00000000-0000-0000-0000-000000000000}" />
-									<Class field="subId" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
-								</Class>
-							</Class>
-							<Class field="element" name="EditorDisabledCompositionComponent" type="{E77AE6AC-897D-4035-8353-637449B6DCFB}">
-								<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
-									<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="12728572968760191789" />
-									</Class>
-								</Class>
-								<Class field="DisabledComponents" name="AZStd::vector" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}" />
-							</Class>
-						</Class>
-						<Class field="IsDependencyReady" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
-						<Class field="IsRuntimeActive" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
-					</Class>
-				</Class>
-				<Class field="Prefabs" name="AZStd::list" type="{DAD45EB6-5853-5645-B762-3A37F8775E12}" />
-				<Class field="IsDynamic" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
-				<Class field="MetadataEntity" name="AZ::Entity" type="{75651658-8663-478D-9090-2432DFCAFA44}" version="2">
-					<Class field="Id" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
-						<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="273889795654" />
-					</Class>
-					<Class field="Name" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="No Asset Association" />
-					<Class field="Components" name="AZStd::vector" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-						<Class field="element" name="SliceMetadataInfoComponent" type="{25EE4D75-8A17-4449-81F4-E561005BAABD}" version="2">
-							<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-								<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="1605466577178627956" />
-							</Class>
-							<Class field="AssociatedIds" name="AZStd::set" type="{78E024C3-0143-53FC-B393-0675227839AF}">
-								<Class field="element" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
-									<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="278184762950" />
-								</Class>
-							</Class>
-							<Class field="ParentId" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
-								<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="4294967295" />
-							</Class>
-							<Class field="ChildrenIds" name="AZStd::unordered_set" type="{6C8F8E52-AB4A-5C1F-8E56-9AC390290B94}" />
-							<Class field="PersistenceFlag" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
-						</Class>
-					</Class>
-					<Class field="IsDependencyReady" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
-					<Class field="IsRuntimeActive" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
-				</Class>
-				<Class field="DataFlagsForNewEntities" name="DataFlagsPerEntity" type="{57FE7B9E-B2AF-4F6F-9F8D-87F671E91C99}" version="1">
-					<Class field="EntityToDataFlags" name="AZStd::unordered_map" type="{CAB9E1F5-761E-54B8-916E-E7FB597E5EDE}" />
-				</Class>
-			</Class>
-		</Class>
-		<Class field="IsDependencyReady" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
-		<Class field="IsRuntimeActive" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
-	</Class>
-</ObjectStream>

+ 0 - 174
AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/assets_with_nested_preload_dependency/TestB.slice

@@ -1,174 +0,0 @@
-<ObjectStream version="3">
-	<Class name="AZ::Entity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-		<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-			<Class name="AZ::u64" field="id" value="268989189527" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		</Class>
-		<Class name="AZStd::string" field="Name" value="Slice" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-		<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-			<Class name="SliceComponent" field="element" version="3" type="{AFD304E4-1773-47C8-855A-8B622398934F}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="13244161893904461810" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-				<Class name="AZStd::vector" field="Entities" type="{21786AF0-2606-5B9A-86EB-0892E2820E6C}">
-					<Class name="AZ::Entity" field="element" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-						<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-							<Class name="AZ::u64" field="id" value="277579124119" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-						</Class>
-						<Class name="AZStd::string" field="Name" value="TestB" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-						<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-							<Class name="EditorOnlyEntityComponent" field="element" type="{22A16F1D-6D49-422D-AAE9-91AE45B5D3E7}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="1413149470528250202" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="bool" field="IsEditorOnly" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="TransformComponent" field="element" version="9" type="{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="10451347479842120634" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="EntityId" field="Parent Entity" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-									<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-								<Class name="EditorTransform" field="Transform Data" version="2" type="{B02B7063-D238-4F40-A724-405F7A6D68CB}">
-									<Class name="Vector3" field="Translate" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
-									<Class name="Vector3" field="Rotate" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
-									<Class name="Vector3" field="Scale" value="1.0000000 1.0000000 1.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
-									<Class name="bool" field="Locked" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								</Class>
-								<Class name="Transform" field="Cached World Transform" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000" type="{5D9958E9-9F1E-4985-B532-FFFDE75FEDFD}"/>
-								<Class name="EntityId" field="Cached World Transform Parent" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-									<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-								<Class name="unsigned int" field="Parent Activation Transform Mode" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-								<Class name="bool" field="IsStatic" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								<Class name="bool" field="Sync Enabled" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								<Class name="unsigned int" field="InterpolatePosition" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-								<Class name="unsigned int" field="InterpolateRotation" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-							</Class>
-							<Class name="EditorInspectorComponent" field="element" version="2" type="{47DE3DDA-50C5-4F50-B1DB-BA4AE66AB056}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="16572464487825802784" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="ComponentOrderEntryArray" type="{B6EFED5B-19B4-5084-9D92-42DECCE83872}">
-									<Class name="ComponentOrderEntry" field="element" version="1" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}">
-										<Class name="AZ::u64" field="ComponentId" value="10451347479842120634" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-										<Class name="AZ::u64" field="SortIndex" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-									<Class name="ComponentOrderEntry" field="element" version="1" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}">
-										<Class name="AZ::u64" field="ComponentId" value="17743482064793827553" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-										<Class name="AZ::u64" field="SortIndex" value="1" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-							</Class>
-							<Class name="EditorEntitySortComponent" field="element" version="2" type="{6EA1E03D-68B2-466D-97F7-83998C8C27F0}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="6677854451525670577" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="ChildEntityOrderEntryArray" type="{BE163120-C1ED-5F69-A650-DC2528A8FF94}"/>
-							</Class>
-							<Class name="SelectionComponent" field="element" type="{73B724FC-43D1-4C75-ACF5-79AA8A3BF89D}">
-								<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-									<Class name="AZ::u64" field="Id" value="10965799152348437728" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-							</Class>
-							<Class name="EditorSpawnerComponent" field="element" version="1" type="{77CDE991-EC1A-B7C1-B112-7456ABAC81A1}">
-								<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-									<Class name="AZ::u64" field="Id" value="17743482064793827553" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-								<Class name="Asset" field="Slice" value="id={0216D84C-4061-5F7E-B6DA-0ABF747BCF1B}:2,type={78802ABF-9595-463A-8D2B-D022F906F9B1},hint={assets_with_nested_preload_dependency/testa.dynamicslice}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
-								<Class name="bool" field="SpawnOnActivate" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								<Class name="bool" field="DestroyOnDeactivate" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="EditorVisibilityComponent" field="element" type="{88E08E78-5C2F-4943-9F73-C115E6FFAB43}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="3307404167904755547" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="bool" field="VisibilityFlag" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="EditorLockComponent" field="element" type="{C3A169C9-7EFB-4D6C-8710-3591680D0936}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="603163492571995613" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="bool" field="Locked" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="EditorPendingCompositionComponent" field="element" type="{D40FCB35-153D-45B3-AF6D-7BA576D8AFBB}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="2776840331440727096" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="PendingComponents" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}"/>
-							</Class>
-							<Class name="EditorEntityIconComponent" field="element" type="{E15D42C2-912D-466F-9547-E7E948CE2D7D}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="12291544534723865655" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AssetId" field="EntityIconAssetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-									<Class name="AZ::Uuid" field="guid" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-									<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-								</Class>
-							</Class>
-							<Class name="EditorDisabledCompositionComponent" field="element" type="{E77AE6AC-897D-4035-8353-637449B6DCFB}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="12816958447570956345" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="DisabledComponents" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}"/>
-							</Class>
-						</Class>
-						<Class name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-						<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-					</Class>
-				</Class>
-				<Class name="AZStd::list" field="Prefabs" type="{DAD45EB6-5853-5645-B762-3A37F8775E12}"/>
-				<Class name="bool" field="IsDynamic" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-				<Class name="AZ::Entity" field="MetadataEntity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-					<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-						<Class name="AZ::u64" field="id" value="273284156823" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-					</Class>
-					<Class name="AZStd::string" field="Name" value="No Asset Association" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-					<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-						<Class name="SliceMetadataInfoComponent" field="element" version="2" type="{25EE4D75-8A17-4449-81F4-E561005BAABD}">
-							<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-								<Class name="AZ::u64" field="Id" value="7886784016988102927" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-							</Class>
-							<Class name="AZStd::set" field="AssociatedIds" type="{78E024C3-0143-53FC-B393-0675227839AF}">
-								<Class name="EntityId" field="element" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-									<Class name="AZ::u64" field="id" value="277579124119" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-							</Class>
-							<Class name="EntityId" field="ParentId" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-								<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-							</Class>
-							<Class name="AZStd::unordered_set" field="ChildrenIds" type="{6C8F8E52-AB4A-5C1F-8E56-9AC390290B94}"/>
-							<Class name="bool" field="PersistenceFlag" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-						</Class>
-					</Class>
-					<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-					<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-				</Class>
-				<Class name="DataFlagsPerEntity" field="DataFlagsForNewEntities" version="1" type="{57FE7B9E-B2AF-4F6F-9F8D-87F671E91C99}">
-					<Class name="AZStd::unordered_map" field="EntityToDataFlags" type="{CAB9E1F5-761E-54B8-916E-E7FB597E5EDE}"/>
-				</Class>
-			</Class>
-		</Class>
-		<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-	</Class>
-</ObjectStream>
-

+ 0 - 174
AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/assets_with_nested_preload_dependency/TestD.slice

@@ -1,174 +0,0 @@
-<ObjectStream version="3">
-	<Class name="AZ::Entity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-		<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-			<Class name="AZ::u64" field="id" value="382257329386" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		</Class>
-		<Class name="AZStd::string" field="Name" value="Slice" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-		<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-			<Class name="SliceComponent" field="element" version="3" type="{AFD304E4-1773-47C8-855A-8B622398934F}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="10124611306244674550" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-				<Class name="AZStd::vector" field="Entities" type="{21786AF0-2606-5B9A-86EB-0892E2820E6C}">
-					<Class name="AZ::Entity" field="element" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-						<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-							<Class name="AZ::u64" field="id" value="390847263978" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-						</Class>
-						<Class name="AZStd::string" field="Name" value="TestB" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-						<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-							<Class name="EditorOnlyEntityComponent" field="element" type="{22A16F1D-6D49-422D-AAE9-91AE45B5D3E7}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="9595291727352692926" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="bool" field="IsEditorOnly" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="TransformComponent" field="element" version="9" type="{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="6918190889556026264" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="EntityId" field="Parent Entity" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-									<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-								<Class name="EditorTransform" field="Transform Data" version="2" type="{B02B7063-D238-4F40-A724-405F7A6D68CB}">
-									<Class name="Vector3" field="Translate" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
-									<Class name="Vector3" field="Rotate" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
-									<Class name="Vector3" field="Scale" value="1.0000000 1.0000000 1.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
-									<Class name="bool" field="Locked" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								</Class>
-								<Class name="Transform" field="Cached World Transform" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000" type="{5D9958E9-9F1E-4985-B532-FFFDE75FEDFD}"/>
-								<Class name="EntityId" field="Cached World Transform Parent" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-									<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-								<Class name="unsigned int" field="Parent Activation Transform Mode" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-								<Class name="bool" field="IsStatic" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								<Class name="bool" field="Sync Enabled" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								<Class name="unsigned int" field="InterpolatePosition" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-								<Class name="unsigned int" field="InterpolateRotation" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-							</Class>
-							<Class name="EditorInspectorComponent" field="element" version="2" type="{47DE3DDA-50C5-4F50-B1DB-BA4AE66AB056}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="16488522651299490860" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="ComponentOrderEntryArray" type="{B6EFED5B-19B4-5084-9D92-42DECCE83872}">
-									<Class name="ComponentOrderEntry" field="element" version="1" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}">
-										<Class name="AZ::u64" field="ComponentId" value="6918190889556026264" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-										<Class name="AZ::u64" field="SortIndex" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-									<Class name="ComponentOrderEntry" field="element" version="1" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}">
-										<Class name="AZ::u64" field="ComponentId" value="1133009518516046488" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-										<Class name="AZ::u64" field="SortIndex" value="1" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-							</Class>
-							<Class name="EditorEntitySortComponent" field="element" version="2" type="{6EA1E03D-68B2-466D-97F7-83998C8C27F0}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="6551321942498556777" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="ChildEntityOrderEntryArray" type="{BE163120-C1ED-5F69-A650-DC2528A8FF94}"/>
-							</Class>
-							<Class name="SelectionComponent" field="element" type="{73B724FC-43D1-4C75-ACF5-79AA8A3BF89D}">
-								<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-									<Class name="AZ::u64" field="Id" value="5168720242367005303" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-							</Class>
-							<Class name="EditorSpawnerComponent" field="element" version="1" type="{77CDE991-EC1A-B7C1-B112-7456ABAC81A1}">
-								<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-									<Class name="AZ::u64" field="Id" value="1133009518516046488" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-								<Class name="Asset" field="Slice" value="id={F47140D7-4A19-5BAA-B0A5-117E6575647A}:2,type={78802ABF-9595-463A-8D2B-D022F906F9B1},hint={assets_with_nested_preload_dependency/testb.dynamicslice}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
-								<Class name="bool" field="SpawnOnActivate" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-								<Class name="bool" field="DestroyOnDeactivate" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="EditorVisibilityComponent" field="element" type="{88E08E78-5C2F-4943-9F73-C115E6FFAB43}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="17020070072341888679" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="bool" field="VisibilityFlag" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="EditorLockComponent" field="element" type="{C3A169C9-7EFB-4D6C-8710-3591680D0936}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="16300364923199181818" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="bool" field="Locked" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-							</Class>
-							<Class name="EditorPendingCompositionComponent" field="element" type="{D40FCB35-153D-45B3-AF6D-7BA576D8AFBB}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="3997039705476816210" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="PendingComponents" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}"/>
-							</Class>
-							<Class name="EditorEntityIconComponent" field="element" type="{E15D42C2-912D-466F-9547-E7E948CE2D7D}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="10323419800905366237" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AssetId" field="EntityIconAssetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-									<Class name="AZ::Uuid" field="guid" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-									<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-								</Class>
-							</Class>
-							<Class name="EditorDisabledCompositionComponent" field="element" type="{E77AE6AC-897D-4035-8353-637449B6DCFB}">
-								<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
-									<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-										<Class name="AZ::u64" field="Id" value="2409852450700585411" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-									</Class>
-								</Class>
-								<Class name="AZStd::vector" field="DisabledComponents" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}"/>
-							</Class>
-						</Class>
-						<Class name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-						<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-					</Class>
-				</Class>
-				<Class name="AZStd::list" field="Prefabs" type="{DAD45EB6-5853-5645-B762-3A37F8775E12}"/>
-				<Class name="bool" field="IsDynamic" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-				<Class name="AZ::Entity" field="MetadataEntity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-					<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-						<Class name="AZ::u64" field="id" value="386552296682" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-					</Class>
-					<Class name="AZStd::string" field="Name" value="No Asset Association" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-					<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
-						<Class name="SliceMetadataInfoComponent" field="element" version="2" type="{25EE4D75-8A17-4449-81F4-E561005BAABD}">
-							<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-								<Class name="AZ::u64" field="Id" value="6483308780985076120" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-							</Class>
-							<Class name="AZStd::set" field="AssociatedIds" type="{78E024C3-0143-53FC-B393-0675227839AF}">
-								<Class name="EntityId" field="element" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-									<Class name="AZ::u64" field="id" value="390847263978" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-								</Class>
-							</Class>
-							<Class name="EntityId" field="ParentId" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-								<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-							</Class>
-							<Class name="AZStd::unordered_set" field="ChildrenIds" type="{6C8F8E52-AB4A-5C1F-8E56-9AC390290B94}"/>
-							<Class name="bool" field="PersistenceFlag" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-						</Class>
-					</Class>
-					<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-					<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-				</Class>
-				<Class name="DataFlagsPerEntity" field="DataFlagsForNewEntities" version="1" type="{57FE7B9E-B2AF-4F6F-9F8D-87F671E91C99}">
-					<Class name="AZStd::unordered_map" field="EntityToDataFlags" type="{CAB9E1F5-761E-54B8-916E-E7FB597E5EDE}"/>
-				</Class>
-			</Class>
-		</Class>
-		<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-	</Class>
-</ObjectStream>
-

+ 0 - 181
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks.py

@@ -1,181 +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
-"""
-
-
-class BehaviorContextTests:
-    spawner_initialized = (
-        "Successfully initialized a Dynamic Slice Instance Spawner",
-        "Failed to initialize a Dynamic Slice Instance Spawner"
-    )
-    spawner_slice_asset_path_set = (
-        "Successfully set a Dynamic Slice asset path",
-        "Failed to set a Dynamic Slice asset path"
-    )
-    spawner_empty_slice_asset_path_set = (
-        "Successfully set an empty Dynamic Slice asset path",
-        "Failed to set an empty Dynamic Slice asset path"
-    )
-    desc_spawnertype_sets_spawner = (
-        "Setting spawnerType sets spawner too",
-        "Setting spawnerType failed to set spawner to expected value"
-    )
-    desc_spawner_sets_spawnertype = (
-        "Setting spawner sets spawnerType too",
-        "Setting spawner failed to set spawnerType to expected value"
-    )
-
-
-class PropertyTreeTests:
-    entity_created = (
-        "Spawner entity created successfully",
-        "Failed to create spawner entity"
-    )
-    spawner_type_set = (
-        "Successfully set spawner type",
-        "Failed to set spawner type"
-    )
-    empty_instance_count_validation = (
-        "Expected number of empty instances planted",
-        "Unexpected number of empty instances planted"
-    )
-    no_instances_when_empty_disallowed = (
-        "No empty instances found when Empty Assets are not allowed",
-        "Unexpectedly found empty instances when Empty Assets are not allowed"
-    )
-    nonempty_asset_instance_count_validation = (
-        "Expected number of instances planted",
-        "Unexpected number of instances planted"
-    )
-
-
-def DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks():
-    """
-    Summary:
-    Test aspects of the DynamicSliceInstanceSpawner through the BehaviorContext and the Property Tree.
-
-    :return: None
-    """
-
-    import os
-
-    import azlmbr.legacy.general as general
-    import azlmbr.math as math
-
-    import editor_python_test_tools.hydra_editor_utils as hydra
-    from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
-    from editor_python_test_tools.utils import Report
-    from editor_python_test_tools.utils import TestHelper as helper
-
-    # 1) Open an existing simple level
-    hydra.open_base_level()
-    general.set_current_view_position(512.0, 480.0, 38.0)
-
-    # Grab the UUID that we need for creating an Dynamic Slice Instance Spawner
-    dynamic_slice_spawner_uuid = azlmbr.math.Uuid_CreateString('{BBA5CC1E-B4CA-4792-89F7-93711E98FBD1}', 0)
-
-    # Grab a path to a test dynamic slice asset
-    test_slice_asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-
-    # 2) Test DynamicSliceInstanceSpawner BehaviorContext
-    behavior_context_test_success = True
-    dynamic_slice_spawner = azlmbr.vegetation.DynamicSliceInstanceSpawner()
-    behavior_context_test_success = behavior_context_test_success and (dynamic_slice_spawner is not None)
-    behavior_context_test_success = behavior_context_test_success and (dynamic_slice_spawner.typename == 'DynamicSliceInstanceSpawner')
-    Report.critical_result(BehaviorContextTests.spawner_initialized, behavior_context_test_success)
-    # Try to get/set the slice asset path with a valid asset
-    dynamic_slice_spawner.SetSliceAssetPath(test_slice_asset_path)
-    validate_path = dynamic_slice_spawner.GetSliceAssetPath()
-    # We expect the path to get lowercased and normalized with a forward slash, so we compare our result
-    # vs that instead of directly against test_slice_asset_path.
-    behavior_context_test_success = behavior_context_test_success and hydra.compare_values('slices/pinkflower.dynamicslice', validate_path, 'GetSliceAssetPath - valid')
-    Report.result(BehaviorContextTests.spawner_slice_asset_path_set, behavior_context_test_success)
-    # Try to get/set the slice asset path with an empty path
-    dynamic_slice_spawner.SetSliceAssetPath('')
-    validate_path = dynamic_slice_spawner.GetSliceAssetPath()
-    behavior_context_test_success = behavior_context_test_success and hydra.compare_values('', validate_path, 'GetSliceAssetPath - empty')
-    Report.result(BehaviorContextTests.spawner_empty_slice_asset_path_set, behavior_context_test_success)
-    Report.info(f'DynamicSliceInstanceSpawner() BehaviorContext test: {behavior_context_test_success}')
-
-    # 3) Test Descriptor BehaviorContext - setting spawnerType sets spawner too
-    spawner_type_test_success = True
-    descriptor = azlmbr.vegetation.Descriptor()
-    spawner_type_test_success = spawner_type_test_success and hydra.get_set_property_test(descriptor, 'spawnerType', dynamic_slice_spawner_uuid)
-    spawner_type_test_success = spawner_type_test_success and (descriptor.spawner.typename == 'DynamicSliceInstanceSpawner')
-    Report.result(BehaviorContextTests.desc_spawnertype_sets_spawner, spawner_type_test_success)
-    Report.info(f'Descriptor() BehaviorContext spawnerType test: {spawner_type_test_success}')
-
-    # 4) Test Descriptor BehaviorContext - setting spawner sets spawnerType too
-    spawner_test_success = True
-    descriptor = azlmbr.vegetation.Descriptor()
-    descriptor.spawner = dynamic_slice_spawner
-    spawner_test_success = spawner_test_success and (descriptor.spawnerType.Equal(dynamic_slice_spawner_uuid))
-    spawner_test_success = spawner_test_success and (descriptor.spawner.typename == 'DynamicSliceInstanceSpawner')
-    Report.result(BehaviorContextTests.desc_spawner_sets_spawnertype, spawner_test_success)
-    Report.info(f'Descriptor() BehaviorContext spawner test: {spawner_test_success}')
-
-    ### Setup for Property Tree set of tests
-
-    # Create a new entity with required vegetation area components
-    spawner_entity = hydra.Entity("Veg Area")
-    spawner_entity.create_entity(
-        math.Vector3(512.0, 512.0, 32.0),
-        ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]
-        )
-    Report.critical_result(PropertyTreeTests.entity_created, spawner_entity.id.IsValid())
-
-    # Resize the Box Shape component
-    new_box_dimensions = math.Vector3(16.0, 16.0, 16.0)
-    box_dimensions_path = "Box Shape|Box Configuration|Dimensions"
-    spawner_entity.get_set_test(1, box_dimensions_path, new_box_dimensions)
-
-    # Create a surface to plant on
-    dynveg.create_surface_entity("Surface Entity", math.Vector3(512.0, 512.0, 32.0), 1024.0, 1024.0, 1.0)
-
-    # 5) Descriptor Property Tree test: spawner type can be set
-
-    # - Validate the dynamic slice spawner type can be set correctly.
-    property_tree_success = True
-    property_tree_success = property_tree_success and spawner_entity.get_set_test(2, 'Configuration|Embedded Assets|[0]|Instance Spawner', dynamic_slice_spawner_uuid)
-    Report.result(PropertyTreeTests.spawner_type_set, property_tree_success)
-
-    # This should result in 400 instances, since our box is 16 m x 16 m and by default the veg system plants
-    # 20 instances per 16 meters
-    spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', True)
-    num_expected_instances = 20 * 20
-    property_tree_success = property_tree_success and helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
-    Report.result(PropertyTreeTests.empty_instance_count_validation, property_tree_success)
-    Report.info(f'Property Tree spawner type test: {property_tree_success}')
-
-    # 6) Validate that the "Allow Empty Assets" setting affects the DynamicSliceInstanceSpawner
-    allow_empty_assets_success = True
-    # Since we have an empty slice path, we should have 0 instances once we disable 'Allow Empty Assets'
-    num_expected_instances = 0
-    allow_empty_assets_success = allow_empty_assets_success and spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
-    Report.info('Allow Empty Assets test:')
-    allow_empty_assets_success = allow_empty_assets_success and helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
-    Report.result(PropertyTreeTests.no_instances_when_empty_disallowed, allow_empty_assets_success)
-    Report.info(f'Allow Empty Assets test: {allow_empty_assets_success}')
-
-    # 7) Validate that with 'Allow Empty Assets' set to False, a non-empty slice asset gives us the number
-    # of instances we expect.
-    spawns_slices_success = True
-    num_expected_instances = 20 * 20
-    dynamic_slice_spawner.SetSliceAssetPath(test_slice_asset_path)
-    spawns_slices_success = spawns_slices_success and spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
-    descriptor = hydra.get_component_property_value(spawner_entity.components[2], 'Configuration|Embedded Assets|[0]')
-    descriptor.spawner = dynamic_slice_spawner
-    spawns_slices_success = spawns_slices_success and spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
-    Report.info('Spawn dynamic slices test:')
-    spawns_slices_success = spawns_slices_success and helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
-    Report.result(PropertyTreeTests.nonempty_asset_instance_count_validation, spawns_slices_success)
-    Report.info(f'Spawn dynamic slices test: {spawns_slices_success}')
-
-
-if __name__ == "__main__":
-
-    from editor_python_test_tools.utils import Report
-    Report.start_test(DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks)

+ 0 - 3
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main.py

@@ -45,9 +45,6 @@ class TestAutomation(EditorTestSuite):
     class test_DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius(EditorSharedTest):
     class test_DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius(EditorSharedTest):
         from .EditorScripts import DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius as test_module
         from .EditorScripts import DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius as test_module
 
 
-    class test_DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(EditorSharedTest):
-        from .EditorScripts import DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks as test_module
-
     class test_EmptyInstanceSpawner_EmptySpawnerWorks(EditorSharedTest):
     class test_EmptyInstanceSpawner_EmptySpawnerWorks(EditorSharedTest):
         from .EditorScripts import EmptyInstanceSpawner_EmptySpawnerWorks as test_module
         from .EditorScripts import EmptyInstanceSpawner_EmptySpawnerWorks as test_module
 
 

+ 0 - 21
AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py

@@ -93,27 +93,6 @@ def create_mesh_surface_entity_with_slopes(name, center_point, uniform_scale):
     return surface_entity
     return surface_entity
 
 
 
 
-def create_dynamic_slice_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_z, dynamic_slice_asset_path):
-    # Create a vegetation area entity to use as our test vegetation spawner
-    spawner_entity = hydra.Entity(name)
-    spawner_entity.create_entity(
-        center_point,
-        ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]
-        )
-    if spawner_entity.id.IsValid():
-        print(f"'{spawner_entity.name}' created")
-    spawner_entity.get_set_test(1, "Box Shape|Box Configuration|Dimensions", math.Vector3(box_size_x, box_size_y,
-                                                                                          box_size_z))
-
-    # Set the vegetation area to a Dynamic Slice spawner with a specific slice asset selected
-    descriptor = hydra.get_component_property_value(spawner_entity.components[2], 'Configuration|Embedded Assets|[0]')
-    dynamic_slice_spawner = vegetation.DynamicSliceInstanceSpawner()
-    dynamic_slice_spawner.SetSliceAssetPath(dynamic_slice_asset_path)
-    descriptor.spawner = dynamic_slice_spawner
-    spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
-    return spawner_entity
-
-
 def create_temp_prefab_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_z, target_prefab):
 def create_temp_prefab_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_z, target_prefab):
     """Creates a vegetation area using in-memory prefabs. Use when test is solely contained to Editor"""
     """Creates a vegetation area using in-memory prefabs. Use when test is solely contained to Editor"""
     # Create a vegetation area entity to use as our test vegetation spawner
     # Create a vegetation area entity to use as our test vegetation spawner

+ 4 - 5
AutomatedTesting/Levels/Physics/ScriptCanvas_PreUpdateEvent/ScriptCanvas_PreUpdateEvent.prefab

@@ -20,7 +20,6 @@
                 "Id": 14126657869720434043,
                 "Id": 14126657869720434043,
                 "Child Entity Order": [
                 "Child Entity Order": [
                     "Entity_[3471072164802]",
                     "Entity_[3471072164802]",
-                    "Entity_[3475367132098]",
                     "Entity_[3475367132098]"
                     "Entity_[3475367132098]"
                 ]
                 ]
             },
             },
@@ -88,7 +87,7 @@
                     "Parent Entity": "Entity_[1146574390643]",
                     "Parent Entity": "Entity_[1146574390643]",
                     "Transform Data": {
                     "Transform Data": {
                         "Translate": [
                         "Translate": [
-                            506.0,
+                            510.0,
                             530.0,
                             530.0,
                             39.0
                             39.0
                         ]
                         ]
@@ -139,9 +138,9 @@
                     "Parent Entity": "Entity_[1146574390643]",
                     "Parent Entity": "Entity_[1146574390643]",
                     "Transform Data": {
                     "Transform Data": {
                         "Translate": [
                         "Translate": [
-                            0.0,
-                            0.09999752044677734,
-                            4.010498523712158
+                            509.0,
+                            530.0,
+                            39.0
                         ]
                         ]
                     }
                     }
                 },
                 },

+ 1 - 115
Code/Editor/CryEdit.cpp

@@ -384,32 +384,7 @@ void CCryEditApp::RegisterActionHandlers()
     ON_COMMAND(ID_VIEW_CONFIGURELAYOUT, OnViewConfigureLayout)
     ON_COMMAND(ID_VIEW_CONFIGURELAYOUT, OnViewConfigureLayout)
 
 
     ON_COMMAND(IDC_SELECTION, OnDummyCommand)
     ON_COMMAND(IDC_SELECTION, OnDummyCommand)
-    //////////////////////////////////////////////////////////////////////////
-    ON_COMMAND(ID_TAG_LOC1, OnTagLocation1)
-    ON_COMMAND(ID_TAG_LOC2, OnTagLocation2)
-    ON_COMMAND(ID_TAG_LOC3, OnTagLocation3)
-    ON_COMMAND(ID_TAG_LOC4, OnTagLocation4)
-    ON_COMMAND(ID_TAG_LOC5, OnTagLocation5)
-    ON_COMMAND(ID_TAG_LOC6, OnTagLocation6)
-    ON_COMMAND(ID_TAG_LOC7, OnTagLocation7)
-    ON_COMMAND(ID_TAG_LOC8, OnTagLocation8)
-    ON_COMMAND(ID_TAG_LOC9, OnTagLocation9)
-    ON_COMMAND(ID_TAG_LOC10, OnTagLocation10)
-    ON_COMMAND(ID_TAG_LOC11, OnTagLocation11)
-    ON_COMMAND(ID_TAG_LOC12, OnTagLocation12)
-    //////////////////////////////////////////////////////////////////////////
-    ON_COMMAND(ID_GOTO_LOC1, OnGotoLocation1)
-    ON_COMMAND(ID_GOTO_LOC2, OnGotoLocation2)
-    ON_COMMAND(ID_GOTO_LOC3, OnGotoLocation3)
-    ON_COMMAND(ID_GOTO_LOC4, OnGotoLocation4)
-    ON_COMMAND(ID_GOTO_LOC5, OnGotoLocation5)
-    ON_COMMAND(ID_GOTO_LOC6, OnGotoLocation6)
-    ON_COMMAND(ID_GOTO_LOC7, OnGotoLocation7)
-    ON_COMMAND(ID_GOTO_LOC8, OnGotoLocation8)
-    ON_COMMAND(ID_GOTO_LOC9, OnGotoLocation9)
-    ON_COMMAND(ID_GOTO_LOC10, OnGotoLocation10)
-    ON_COMMAND(ID_GOTO_LOC11, OnGotoLocation11)
-    ON_COMMAND(ID_GOTO_LOC12, OnGotoLocation12)
+
     //////////////////////////////////////////////////////////////////////////
     //////////////////////////////////////////////////////////////////////////
 
 
     ON_COMMAND(ID_TOOLS_LOGMEMORYUSAGE, OnToolsLogMemoryUsage)
     ON_COMMAND(ID_TOOLS_LOGMEMORYUSAGE, OnToolsLogMemoryUsage)
@@ -3420,31 +3395,6 @@ void CCryEditApp::OnViewConfigureLayout()
     }
     }
 }
 }
 
 
-//////////////////////////////////////////////////////////////////////////
-void CCryEditApp::TagLocation(int index)
-{
-    CViewport* pRenderViewport = GetIEditor()->GetViewManager()->GetGameViewport();
-    if (!pRenderViewport)
-    {
-        return;
-    }
-
-    Vec3 vPosVec = pRenderViewport->GetViewTM().GetTranslation();
-
-    m_tagLocations[index - 1] = vPosVec;
-    m_tagAngles[index - 1] = Ang3::GetAnglesXYZ(Matrix33(pRenderViewport->GetViewTM()));
-
-    QString sTagConsoleText("");
-    sTagConsoleText = tr("Camera Tag Point %1 set to the position: x=%2, y=%3, z=%4 ").arg(index).arg(vPosVec.x, 0, 'f', 2).arg(vPosVec.y, 0, 'f', 2).arg(vPosVec.z, 0, 'f', 2);
-
-    GetIEditor()->WriteToConsole(sTagConsoleText.toUtf8().data());
-
-    if (gSettings.bAutoSaveTagPoints)
-    {
-        SaveTagLocations();
-    }
-}
-
 void CCryEditApp::SaveTagLocations()
 void CCryEditApp::SaveTagLocations()
 {
 {
     // Save to file.
     // Save to file.
@@ -3462,41 +3412,6 @@ void CCryEditApp::SaveTagLocations()
     }
     }
 }
 }
 
 
-
-//////////////////////////////////////////////////////////////////////////
-void CCryEditApp::GotoTagLocation(int index)
-{
-    QString sTagConsoleText("");
-    Vec3 pos = m_tagLocations[index - 1];
-
-    if (!IsVectorsEqual(m_tagLocations[index - 1], Vec3(0, 0, 0)))
-    {
-        // Change render viewport view TM to the stored one.
-        CViewport* pRenderViewport = GetIEditor()->GetViewManager()->GetGameViewport();
-        if (pRenderViewport)
-        {
-            Matrix34 tm = Matrix34::CreateRotationXYZ(m_tagAngles[index - 1]);
-            tm.SetTranslation(pos);
-            pRenderViewport->SetViewTM(tm);
-            Vec3 vPosVec(tm.GetTranslation());
-
-            GetISystem()->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_BEAM_PLAYER_TO_CAMERA_POS, (UINT_PTR)&tm, 0);
-
-            sTagConsoleText = tr("Moved Camera To Tag Point %1 (x=%2, y=%3, z=%4)").arg(index).arg(vPosVec.x, 0, 'f', 2).arg(vPosVec.y, 0, 'f', 2).arg(vPosVec.z, 0, 'f', 2);
-        }
-    }
-    else
-    {
-        sTagConsoleText = tr("Camera Tag Point %1 not set").arg(index);
-    }
-
-    if (!sTagConsoleText.isEmpty())
-    {
-        GetIEditor()->WriteToConsole(sTagConsoleText.toUtf8().data());
-    }
-}
-
-
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 void CCryEditApp::LoadTagLocations()
 void CCryEditApp::LoadTagLocations()
 {
 {
@@ -3535,35 +3450,6 @@ void CCryEditApp::OnToolsLogMemoryUsage()
     gEnv->pConsole->ExecuteString("SaveLevelStats");
     gEnv->pConsole->ExecuteString("SaveLevelStats");
 }
 }
 
 
-//////////////////////////////////////////////////////////////////////////
-void CCryEditApp::OnTagLocation1() { TagLocation(1); }
-void CCryEditApp::OnTagLocation2() { TagLocation(2); }
-void CCryEditApp::OnTagLocation3() { TagLocation(3); }
-void CCryEditApp::OnTagLocation4() { TagLocation(4); }
-void CCryEditApp::OnTagLocation5() { TagLocation(5); }
-void CCryEditApp::OnTagLocation6() { TagLocation(6); }
-void CCryEditApp::OnTagLocation7() { TagLocation(7); }
-void CCryEditApp::OnTagLocation8() { TagLocation(8); }
-void CCryEditApp::OnTagLocation9() { TagLocation(9); }
-void CCryEditApp::OnTagLocation10() { TagLocation(10); }
-void CCryEditApp::OnTagLocation11() { TagLocation(11); }
-void CCryEditApp::OnTagLocation12() { TagLocation(12); }
-
-
-//////////////////////////////////////////////////////////////////////////
-void CCryEditApp::OnGotoLocation1() { GotoTagLocation(1); }
-void CCryEditApp::OnGotoLocation2() { GotoTagLocation(2); }
-void CCryEditApp::OnGotoLocation3() { GotoTagLocation(3); }
-void CCryEditApp::OnGotoLocation4() { GotoTagLocation(4); }
-void CCryEditApp::OnGotoLocation5() { GotoTagLocation(5); }
-void CCryEditApp::OnGotoLocation6() { GotoTagLocation(6); }
-void CCryEditApp::OnGotoLocation7() { GotoTagLocation(7); }
-void CCryEditApp::OnGotoLocation8() { GotoTagLocation(8); }
-void CCryEditApp::OnGotoLocation9() { GotoTagLocation(9); }
-void CCryEditApp::OnGotoLocation10() { GotoTagLocation(10); }
-void CCryEditApp::OnGotoLocation11() { GotoTagLocation(11); }
-void CCryEditApp::OnGotoLocation12() { GotoTagLocation(12); }
-
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 void CCryEditApp::OnCustomizeKeyboard()
 void CCryEditApp::OnCustomizeKeyboard()
 {
 {

+ 0 - 28
Code/Editor/CryEdit.h

@@ -247,8 +247,6 @@ private:
 
 
     CMainFrame* GetMainFrame() const;
     CMainFrame* GetMainFrame() const;
     void WriteConfig();
     void WriteConfig();
-    void TagLocation(int index);
-    void GotoTagLocation(int index);
     void LoadTagLocations();
     void LoadTagLocations();
     bool UserExportToGame(bool bNoMsgBox = true);
     bool UserExportToGame(bool bNoMsgBox = true);
     static void ShowSplashScreen(CCryEditApp* app);
     static void ShowSplashScreen(CCryEditApp* app);
@@ -359,32 +357,6 @@ private:
     void OnUpdateWireframe(QAction* action);
     void OnUpdateWireframe(QAction* action);
     void OnViewConfigureLayout();
     void OnViewConfigureLayout();
 
 
-    // Tag Locations.
-    void OnTagLocation1();
-    void OnTagLocation2();
-    void OnTagLocation3();
-    void OnTagLocation4();
-    void OnTagLocation5();
-    void OnTagLocation6();
-    void OnTagLocation7();
-    void OnTagLocation8();
-    void OnTagLocation9();
-    void OnTagLocation10();
-    void OnTagLocation11();
-    void OnTagLocation12();
-
-    void OnGotoLocation1();
-    void OnGotoLocation2();
-    void OnGotoLocation3();
-    void OnGotoLocation4();
-    void OnGotoLocation5();
-    void OnGotoLocation6();
-    void OnGotoLocation7();
-    void OnGotoLocation8();
-    void OnGotoLocation9();
-    void OnGotoLocation10();
-    void OnGotoLocation11();
-    void OnGotoLocation12();
     void OnToolsLogMemoryUsage();
     void OnToolsLogMemoryUsage();
     void OnCustomizeKeyboard();
     void OnCustomizeKeyboard();
     void OnToolsConfiguretools();
     void OnToolsConfiguretools();

+ 143 - 24
Code/Editor/MainWindow.cpp

@@ -21,6 +21,10 @@
 #include <QAbstractEventDispatcher>
 #include <QAbstractEventDispatcher>
 #endif
 #endif
 
 
+// Atom
+#include <Atom/RPI.Public/ViewportContext.h>
+#include <Atom/RPI.Public/ViewportContextBus.h>
+
 // AzCore
 // AzCore
 #include <AzCore/Component/ComponentApplication.h>
 #include <AzCore/Component/ComponentApplication.h>
 #include <AzCore/Interface/Interface.h>
 #include <AzCore/Interface/Interface.h>
@@ -35,6 +39,7 @@
 #include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
 #include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
 #include <AzFramework/Network/SocketConnection.h>
 #include <AzFramework/Network/SocketConnection.h>
 #include <AzFramework/Asset/AssetSystemComponent.h>
 #include <AzFramework/Asset/AssetSystemComponent.h>
+#include <AzFramework/Viewport/CameraInput.h>
 
 
 // AzToolsFramework
 // AzToolsFramework
 #include <AzToolsFramework/Application/Ticker.h>
 #include <AzToolsFramework/Application/Ticker.h>
@@ -44,6 +49,8 @@
 #include <AzToolsFramework/PythonTerminal/ScriptTermDialog.h>
 #include <AzToolsFramework/PythonTerminal/ScriptTermDialog.h>
 #include <AzToolsFramework/Viewport/ViewportSettings.h>
 #include <AzToolsFramework/Viewport/ViewportSettings.h>
 #include <AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h>
 #include <AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h>
+#include <AzToolsFramework/API/EditorCameraBus.h>
+#include <AzToolsFramework/Viewport/ViewBookmarkLoaderInterface.h>
 
 
 // AzQtComponents
 // AzQtComponents
 #include <AzQtComponents/Buses/ShortcutDispatch.h>
 #include <AzQtComponents/Buses/ShortcutDispatch.h>
@@ -95,6 +102,7 @@
 #include <ImGuiBus.h>
 #include <ImGuiBus.h>
 #include <AzToolsFramework/Viewport/ViewportMessages.h>
 #include <AzToolsFramework/Viewport/ViewportMessages.h>
 #include <LmbrCentral/Audio/AudioSystemComponentBus.h>
 #include <LmbrCentral/Audio/AudioSystemComponentBus.h>
+#include <Editor/EditorViewportCamera.h>
 
 
 using namespace AZ;
 using namespace AZ;
 using namespace AzQtComponents;
 using namespace AzQtComponents;
@@ -845,78 +853,189 @@ void MainWindow::InitActions()
         .SetShortcut(tr("Z"))
         .SetShortcut(tr("Z"))
         .SetToolTip(tr("Center on Selection (Z)"))
         .SetToolTip(tr("Center on Selection (Z)"))
         .Connect(&QAction::triggered, this, &MainWindow::OnGotoSelected);
         .Connect(&QAction::triggered, this, &MainWindow::OnGotoSelected);
+
+    const auto goToViewBookmarkFn = [](int index)
+    {
+        AzToolsFramework::ViewBookmarkLoaderInterface* bookmarkLoader = AZ::Interface<ViewBookmarkLoaderInterface>::Get();
+        if (!bookmarkLoader)
+        {
+            AZ_Warning("Main Window", false, "Couldn't find View Bookmark Loader");
+            return false;
+        }
+
+        const AZStd::optional<AzToolsFramework::ViewBookmark> bookmark =
+            bookmarkLoader->LoadBookmarkAtIndex(index);
+
+        if (!bookmark.has_value())
+        {
+            return false;
+        }
+
+        // Check the bookmark we want to load is not exactly 0 
+        if (bookmark.value().IsZero())
+        {
+            QString tagConsoleText = tr("View Bookmark %1 has not been set yet").arg(index + 1);
+            AZ_Warning("Main Window", false, tagConsoleText.toUtf8().data());
+            return false;
+        }
+
+        auto viewportContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
+        if (!viewportContextManager)
+        {
+            return false;
+        }
+
+        auto viewportContext = viewportContextManager->GetDefaultViewportContext();
+        if (!viewportContext)
+        {
+            return false;
+        }
+
+        SandboxEditor::InterpolateDefaultViewportCameraToTransform(
+            bookmark->m_position, bookmark->m_rotation.GetX(), bookmark->m_rotation.GetZ());
+
+        QString tagConsoleText = tr("View Bookmark %1 loaded position: x=%2, y=%3, z=%4")
+                                     .arg(index + 1)
+                                     .arg(bookmark->m_position.GetX(), 0, 'f', 2)
+                                     .arg(bookmark->m_position.GetY(), 0, 'f', 2)
+                                     .arg(bookmark->m_position.GetZ(), 0, 'f', 2);
+        AZ_Printf("MainWindow", tagConsoleText.toUtf8().data());
+        return true;
+    };
+
     am->AddAction(ID_GOTO_LOC1, tr("Location 1"))
     am->AddAction(ID_GOTO_LOC1, tr("Location 1"))
         .SetShortcut(tr("Shift+F1"))
         .SetShortcut(tr("Shift+F1"))
-        .SetToolTip(tr("Location 1 (Shift+F1)"));
+        .SetToolTip(tr("Go to Location 1 (Shift+F1)"))
+        .Connect(&QAction::triggered, [goToViewBookmarkFn](){ goToViewBookmarkFn(0);});
     am->AddAction(ID_GOTO_LOC2, tr("Location 2"))
     am->AddAction(ID_GOTO_LOC2, tr("Location 2"))
         .SetShortcut(tr("Shift+F2"))
         .SetShortcut(tr("Shift+F2"))
-        .SetToolTip(tr("Location 2 (Shift+F2)"));
+        .SetToolTip(tr("Go to Location 2 (Shift+F2)"))
+        .Connect(&QAction::triggered, [goToViewBookmarkFn](){ goToViewBookmarkFn(1);});
     am->AddAction(ID_GOTO_LOC3, tr("Location 3"))
     am->AddAction(ID_GOTO_LOC3, tr("Location 3"))
         .SetShortcut(tr("Shift+F3"))
         .SetShortcut(tr("Shift+F3"))
-        .SetToolTip(tr("Location 3 (Shift+F3)"));
+        .SetToolTip(tr("Go to Location 3 (Shift+F3)"))
+        .Connect(&QAction::triggered, [goToViewBookmarkFn](){ goToViewBookmarkFn(2);});
     am->AddAction(ID_GOTO_LOC4, tr("Location 4"))
     am->AddAction(ID_GOTO_LOC4, tr("Location 4"))
         .SetShortcut(tr("Shift+F4"))
         .SetShortcut(tr("Shift+F4"))
-        .SetToolTip(tr("Location 4 (Shift+F4)"));
+        .SetToolTip(tr("Go to Location 4 (Shift+F4)"))
+        .Connect(&QAction::triggered, [goToViewBookmarkFn](){ goToViewBookmarkFn(3);});
     am->AddAction(ID_GOTO_LOC5, tr("Location 5"))
     am->AddAction(ID_GOTO_LOC5, tr("Location 5"))
         .SetShortcut(tr("Shift+F5"))
         .SetShortcut(tr("Shift+F5"))
-        .SetToolTip(tr("Location 5 (Shift+F5)"));
+        .SetToolTip(tr("Go to Location 5 (Shift+F5)"))
+        .Connect(&QAction::triggered, [goToViewBookmarkFn](){ goToViewBookmarkFn(4);});
     am->AddAction(ID_GOTO_LOC6, tr("Location 6"))
     am->AddAction(ID_GOTO_LOC6, tr("Location 6"))
         .SetShortcut(tr("Shift+F6"))
         .SetShortcut(tr("Shift+F6"))
-        .SetToolTip(tr("Location 6 (Shift+F6)"));
+        .SetToolTip(tr("Go to Location 6 (Shift+F6)"))
+        .Connect(&QAction::triggered, [goToViewBookmarkFn](){ goToViewBookmarkFn(5);});
     am->AddAction(ID_GOTO_LOC7, tr("Location 7"))
     am->AddAction(ID_GOTO_LOC7, tr("Location 7"))
         .SetShortcut(tr("Shift+F7"))
         .SetShortcut(tr("Shift+F7"))
-        .SetToolTip(tr("Location 7 (Shift+F7)"));
+        .SetToolTip(tr("Go to Location 7 (Shift+F7)"))
+        .Connect(&QAction::triggered, [goToViewBookmarkFn](){ goToViewBookmarkFn(6);});
     am->AddAction(ID_GOTO_LOC8, tr("Location 8"))
     am->AddAction(ID_GOTO_LOC8, tr("Location 8"))
         .SetShortcut(tr("Shift+F8"))
         .SetShortcut(tr("Shift+F8"))
-        .SetToolTip(tr("Location 8 (Shift+F8)"));
+        .SetToolTip(tr("Go to Location 8 (Shift+F8)"))
+        .Connect(&QAction::triggered, [goToViewBookmarkFn](){ goToViewBookmarkFn(7);});
     am->AddAction(ID_GOTO_LOC9, tr("Location 9"))
     am->AddAction(ID_GOTO_LOC9, tr("Location 9"))
         .SetShortcut(tr("Shift+F9"))
         .SetShortcut(tr("Shift+F9"))
-        .SetToolTip(tr("Location 9 (Shift+F9)"));
+        .SetToolTip(tr("Go to Location 9 (Shift+F9)"))
+        .Connect(&QAction::triggered, [goToViewBookmarkFn](){ goToViewBookmarkFn(8);});
     am->AddAction(ID_GOTO_LOC10, tr("Location 10"))
     am->AddAction(ID_GOTO_LOC10, tr("Location 10"))
         .SetShortcut(tr("Shift+F10"))
         .SetShortcut(tr("Shift+F10"))
-        .SetToolTip(tr("Location 10 (Shift+F10)"));
+        .SetToolTip(tr("Go to Location 10 (Shift+F10)"))
+        .Connect(&QAction::triggered, [goToViewBookmarkFn](){ goToViewBookmarkFn(9);});
     am->AddAction(ID_GOTO_LOC11, tr("Location 11"))
     am->AddAction(ID_GOTO_LOC11, tr("Location 11"))
         .SetShortcut(tr("Shift+F11"))
         .SetShortcut(tr("Shift+F11"))
-        .SetToolTip(tr("Location 11 (Shift+F11)"));
+        .SetToolTip(tr("Go to Location 11 (Shift+F11)"))
+        .Connect(&QAction::triggered, [goToViewBookmarkFn](){ goToViewBookmarkFn(10);});
     am->AddAction(ID_GOTO_LOC12, tr("Location 12"))
     am->AddAction(ID_GOTO_LOC12, tr("Location 12"))
         .SetShortcut(tr("Shift+F12"))
         .SetShortcut(tr("Shift+F12"))
-        .SetToolTip(tr("Location 12 (Shift+F12)"));
+        .SetToolTip(tr("Go to Location 12 (Shift+F12)"))
+        .Connect(&QAction::triggered, [goToViewBookmarkFn](){ goToViewBookmarkFn(11);});
+
+    const auto tagViewBookmarkFn = [](int index)
+    {
+        AzToolsFramework::ViewBookmarkLoaderInterface* bookmarkLoader = AZ::Interface<ViewBookmarkLoaderInterface>::Get();
+        if (!bookmarkLoader)
+        {
+            QString tagConsoleText = tr("Failed to tag View Bookmark %1").arg(index + 1);
+            AZ_Warning("Main Window", false, tagConsoleText.toUtf8().data());
+            return false;
+        }
+
+        bool found = false;
+        AzFramework::CameraState cameraState;
+        Camera::EditorCameraRequestBus::BroadcastResult(
+            found, &Camera::EditorCameraRequestBus::Events::GetActiveCameraState, cameraState);
+
+        if (!found)
+        {
+            AZ_Warning("Main Window", false, "tagLocation: Couldn't find Active Camera State.");
+            return false;
+        }
+
+        ViewBookmark bookmark;
+        bookmark.m_position = cameraState.m_position;
+        bookmark.m_rotation =
+            AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromColumns(cameraState.m_side, cameraState.m_forward, cameraState.m_up));
+
+        bookmarkLoader->ModifyBookmarkAtIndex(bookmark, index);
+        QString tagConsoleText = tr("View Bookmark %1 set to the position: x=%2, y=%3, z=%4")
+                                     .arg(index + 1)
+                                     .arg(bookmark.m_position.GetX(), 0, 'f', 2)
+                                     .arg(bookmark.m_position.GetY(), 0, 'f', 2)
+                                     .arg(bookmark.m_position.GetZ(), 0, 'f', 2);
+        AZ_Printf("MainWindow", tagConsoleText.toUtf8().data());
+        return true;
+    };
+
     am->AddAction(ID_TAG_LOC1, tr("Location 1"))
     am->AddAction(ID_TAG_LOC1, tr("Location 1"))
         .SetShortcut(tr("Ctrl+F1"))
         .SetShortcut(tr("Ctrl+F1"))
-        .SetToolTip(tr("Location 1 (Ctrl+F1)"));
+        .SetToolTip(tr("Save Location 1 (Ctrl+F1)"))
+        .Connect(&QAction::triggered, [tagViewBookmarkFn](){ tagViewBookmarkFn(0); });
     am->AddAction(ID_TAG_LOC2, tr("Location 2"))
     am->AddAction(ID_TAG_LOC2, tr("Location 2"))
         .SetShortcut(tr("Ctrl+F2"))
         .SetShortcut(tr("Ctrl+F2"))
-        .SetToolTip(tr("Location 2 (Ctrl+F2)"));
+        .SetToolTip(tr("Save Location 2 (Ctrl+F2)"))
+        .Connect(&QAction::triggered, [tagViewBookmarkFn](){ tagViewBookmarkFn(1); });
     am->AddAction(ID_TAG_LOC3, tr("Location 3"))
     am->AddAction(ID_TAG_LOC3, tr("Location 3"))
         .SetShortcut(tr("Ctrl+F3"))
         .SetShortcut(tr("Ctrl+F3"))
-        .SetToolTip(tr("Location 3 (Ctrl+F3)"));
+        .SetToolTip(tr("Save Location 3 (Ctrl+F3)"))
+        .Connect(&QAction::triggered, [tagViewBookmarkFn](){ tagViewBookmarkFn(2); });
     am->AddAction(ID_TAG_LOC4, tr("Location 4"))
     am->AddAction(ID_TAG_LOC4, tr("Location 4"))
         .SetShortcut(tr("Ctrl+F4"))
         .SetShortcut(tr("Ctrl+F4"))
-        .SetToolTip(tr("Location 4 (Ctrl+F4)"));
+        .SetToolTip(tr("Save Location 4 (Ctrl+F4)"))
+        .Connect(&QAction::triggered, [tagViewBookmarkFn](){ tagViewBookmarkFn(3); });
     am->AddAction(ID_TAG_LOC5, tr("Location 5"))
     am->AddAction(ID_TAG_LOC5, tr("Location 5"))
         .SetShortcut(tr("Ctrl+F5"))
         .SetShortcut(tr("Ctrl+F5"))
-        .SetToolTip(tr("Location 5 (Ctrl+F5)"));
+        .SetToolTip(tr("Save Location 5 (Ctrl+F5)"))
+        .Connect(&QAction::triggered, [tagViewBookmarkFn](){ tagViewBookmarkFn(4); });
     am->AddAction(ID_TAG_LOC6, tr("Location 6"))
     am->AddAction(ID_TAG_LOC6, tr("Location 6"))
         .SetShortcut(tr("Ctrl+F6"))
         .SetShortcut(tr("Ctrl+F6"))
-        .SetToolTip(tr("Location 6 (Ctrl+F6)"));
+        .SetToolTip(tr("Save Location 6 (Ctrl+F6)"))
+        .Connect(&QAction::triggered, [tagViewBookmarkFn](){ tagViewBookmarkFn(5); });
     am->AddAction(ID_TAG_LOC7, tr("Location 7"))
     am->AddAction(ID_TAG_LOC7, tr("Location 7"))
         .SetShortcut(tr("Ctrl+F7"))
         .SetShortcut(tr("Ctrl+F7"))
-        .SetToolTip(tr("Location 7 (Ctrl+F7)"));
+        .SetToolTip(tr("Save Location 7 (Ctrl+F7)"))
+        .Connect(&QAction::triggered, [tagViewBookmarkFn](){ tagViewBookmarkFn(6); });
     am->AddAction(ID_TAG_LOC8, tr("Location 8"))
     am->AddAction(ID_TAG_LOC8, tr("Location 8"))
         .SetShortcut(tr("Ctrl+F8"))
         .SetShortcut(tr("Ctrl+F8"))
-        .SetToolTip(tr("Location 8 (Ctrl+F8)"));
+        .SetToolTip(tr("Save Location 8 (Ctrl+F8)"))
+        .Connect(&QAction::triggered, [tagViewBookmarkFn](){ tagViewBookmarkFn(7); });
     am->AddAction(ID_TAG_LOC9, tr("Location 9"))
     am->AddAction(ID_TAG_LOC9, tr("Location 9"))
         .SetShortcut(tr("Ctrl+F9"))
         .SetShortcut(tr("Ctrl+F9"))
-        .SetToolTip(tr("Location 9 (Ctrl+F9)"));
+        .SetToolTip(tr("Save Location 9 (Ctrl+F9)"))
+        .Connect(&QAction::triggered, [tagViewBookmarkFn](){ tagViewBookmarkFn(8); });
     am->AddAction(ID_TAG_LOC10, tr("Location 10"))
     am->AddAction(ID_TAG_LOC10, tr("Location 10"))
         .SetShortcut(tr("Ctrl+F10"))
         .SetShortcut(tr("Ctrl+F10"))
-        .SetToolTip(tr("Location 10 (Ctrl+F10)"));
+        .SetToolTip(tr("Save Location 10 (Ctrl+F10)"))
+        .Connect(&QAction::triggered, [tagViewBookmarkFn](){ tagViewBookmarkFn(9); });
     am->AddAction(ID_TAG_LOC11, tr("Location 11"))
     am->AddAction(ID_TAG_LOC11, tr("Location 11"))
         .SetShortcut(tr("Ctrl+F11"))
         .SetShortcut(tr("Ctrl+F11"))
-        .SetToolTip(tr("Location 11 (Ctrl+F11)"));
+        .SetToolTip(tr("Save Location 11 (Ctrl+F11)"))
+        .Connect(&QAction::triggered, [tagViewBookmarkFn](){ tagViewBookmarkFn(10); });
     am->AddAction(ID_TAG_LOC12, tr("Location 12"))
     am->AddAction(ID_TAG_LOC12, tr("Location 12"))
         .SetShortcut(tr("Ctrl+F12"))
         .SetShortcut(tr("Ctrl+F12"))
-        .SetToolTip(tr("Location 12 (Ctrl+F12)"));
+        .SetToolTip(tr("Save Location 12 (Ctrl+F12)"))
+        .Connect(&QAction::triggered, [tagViewBookmarkFn](){ tagViewBookmarkFn(11); });
 
 
     if (CViewManager::IsMultiViewportEnabled())
     if (CViewManager::IsMultiViewportEnabled())
     {
     {

+ 3 - 2
Code/Framework/AzCore/AzCore/DOM/DomValue.h

@@ -159,6 +159,9 @@ namespace AZ::Dom
     class Value final
     class Value final
     {
     {
     public:
     public:
+        AZ_TYPE_INFO(Value, "{3E20677F-3B8E-4F89-B665-ED41D74F4799}");
+        AZ_CLASS_ALLOCATOR(Value, ValueAllocator, 0);
+
         // Determine the short string buffer size based on the size of our largest internal type (string_view)
         // Determine the short string buffer size based on the size of our largest internal type (string_view)
         // minus the size of the short string size field.
         // minus the size of the short string size field.
         static constexpr const size_t ShortStringSize = sizeof(AZStd::string_view) - 2;
         static constexpr const size_t ShortStringSize = sizeof(AZStd::string_view) - 2;
@@ -199,8 +202,6 @@ namespace AZ::Dom
         Value(const Value&);
         Value(const Value&);
         Value(Value&&) noexcept;
         Value(Value&&) noexcept;
         Value(AZStd::string_view stringView, bool copy);
         Value(AZStd::string_view stringView, bool copy);
-        explicit Value(const ValueType&);
-        explicit Value(ValueType&&);
         explicit Value(SharedStringType sharedString);
         explicit Value(SharedStringType sharedString);
 
 
         explicit Value(int8_t value);
         explicit Value(int8_t value);

+ 3 - 0
Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl

@@ -194,6 +194,9 @@ namespace AZ
             //! For use with slice creation tools. See SliceCreationFlags below for details.
             //! For use with slice creation tools. See SliceCreationFlags below for details.
             const static AZ::Crc32 SliceFlags = AZ_CRC("SliceFlags", 0xa447e1fb);
             const static AZ::Crc32 SliceFlags = AZ_CRC("SliceFlags", 0xa447e1fb);
 
 
+            //! Does the clear button in the LineEdit need to have a test for visibility.
+            const static AZ::Crc32 ShowClearButtonHandler = AZ_CRC_CE("ShowClearButtonHandler");
+
             //! For optional use on Getter Events used for Virtual Properties
             //! For optional use on Getter Events used for Virtual Properties
             const static AZ::Crc32 PropertyPosition = AZ_CRC("Position", 0x462ce4f5);
             const static AZ::Crc32 PropertyPosition = AZ_CRC("Position", 0x462ce4f5);
             const static AZ::Crc32 PropertyRotation = AZ_CRC("Rotation", 0x297c98f1);
             const static AZ::Crc32 PropertyRotation = AZ_CRC("Rotation", 0x297c98f1);

+ 11 - 3
Code/Framework/AzCore/AzCore/base.h

@@ -13,10 +13,18 @@
 
 
 #include <AzCore/AzCore_Traits_Platform.h>
 #include <AzCore/AzCore_Traits_Platform.h>
 
 
-#ifndef AZ_ARRAY_SIZE
 /// Return an array size for static arrays.
 /// Return an array size for static arrays.
-#   define  AZ_ARRAY_SIZE(__a)  (sizeof(__a)/sizeof(__a[0]))
-#endif
+namespace AZ::Internal
+{
+    template<class T>
+    struct StaticArraySize
+    {
+        static_assert(std::is_array_v<T>, "AZ_ARRAY_SIZE can only be used with a C-style array");
+        static constexpr size_t value = sizeof(T) / sizeof(std::remove_extent_t<T>);
+    };
+}
+#define AZ_ARRAY_SIZE(__a)  AZ::Internal::StaticArraySize<std::remove_reference_t<decltype(__a)>>::value
+
 
 
 #ifndef AZ_SIZE_ALIGN_UP
 #ifndef AZ_SIZE_ALIGN_UP
 /// Aign to the next bigger/up size
 /// Aign to the next bigger/up size

+ 7 - 4
Code/Framework/AzCore/AzCore/std/containers/vector.h

@@ -849,10 +849,13 @@ namespace AZStd
 #endif
 #endif
 
 
             size_type offset = firstPtr - m_start;
             size_type offset = firstPtr - m_start;
-            // unless we have 1 elements we have memory overlapping, so we need to use move.
-            pointer newLast = AZStd::move(lastPtr, m_last, firstPtr);
-            Internal::destroy<pointer>::range(newLast, m_last);
-            m_last = newLast;
+            if (firstPtr != lastPtr)
+            {
+                // unless we have 1 elements we have memory overlapping, so we need to use move.
+                pointer newLast = AZStd::move(lastPtr, m_last, firstPtr);
+                Internal::destroy<pointer>::range(newLast, m_last);
+                m_last = newLast;
+            }
             return iterator(AZSTD_POINTER_ITERATOR_PARAMS(m_start)) + offset;
             return iterator(AZSTD_POINTER_ITERATOR_PARAMS(m_start)) + offset;
         }
         }
 
 

+ 1 - 1
Code/Framework/AzCore/AzCore/std/parallel/thread.h

@@ -50,7 +50,7 @@ namespace AZStd
 
 
     struct thread_desc
     struct thread_desc
     {
     {
-        //! Debug thread name.
+        //! Debug thread name. Limited to 16 characters on Linux.
         const char*     m_name{ "AZStd::thread" };
         const char*     m_name{ "AZStd::thread" };
 
 
         //! Thread stack size. Default is -1, which means we will use the default stack size for each platform.
         //! Thread stack size. Default is -1, which means we will use the default stack size for each platform.

+ 10 - 1
Code/Framework/AzCore/Platform/Linux/AzCore/std/parallel/internal/thread_Linux.cpp

@@ -6,6 +6,7 @@
  *
  *
  */
  */
 
 
+#include <AzCore/std/string/fixed_string.h>
 #include <AzCore/std/parallel/thread.h>
 #include <AzCore/std/parallel/thread.h>
 
 
 #include <sched.h>
 #include <sched.h>
@@ -53,7 +54,15 @@ namespace AZStd
 
 
         void PostCreateThread(pthread_t tId, const char* name, int)
         void PostCreateThread(pthread_t tId, const char* name, int)
         {
         {
-            pthread_setname_np(tId, name);
+            if (const int result = pthread_setname_np(tId, name); result == ERANGE)
+            {
+                // The name was too long. pthread limits the name to 16
+                // characters (including the null terminator). Let's elide the
+                // middle.
+                const auto len = strlen(name);
+                const auto elidedName = AZStd::fixed_string<15>{name, 7} + "." + AZStd::fixed_string<15>{name + len - 7, 7};
+                pthread_setname_np(tId, elidedName.c_str());
+            }
         }
         }
 
 
         uint8_t GetDefaultThreadPriority()
         uint8_t GetDefaultThreadPriority()

+ 17 - 0
Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/AdapterBuilder.cpp

@@ -21,6 +21,23 @@ namespace AZ::DocumentPropertyEditor
         CurrentNode()[attribute] = AZStd::move(value);
         CurrentNode()[attribute] = AZStd::move(value);
     }
     }
 
 
+    void AdapterBuilder::OnEditorChanged(AZStd::function<void(const Dom::Path&, const Dom::Value&)> onChangedCallback)
+    {
+        // The value path is the first child of the PropertyEditor node
+        Dom::Path changedPath = GetCurrentPath() / 0;
+        CallbackAttribute(
+            Nodes::PropertyEditor::OnChanged,
+            [changedPath, onChangedCallback](const Dom::Value& value)
+            {
+                onChangedCallback(changedPath, value);
+            });
+    }
+
+    Dom::Path AdapterBuilder::GetCurrentPath() const
+    {
+        return m_currentPath;
+    }
+
     bool AdapterBuilder::IsError() const
     bool AdapterBuilder::IsError() const
     {
     {
         return !m_error.empty();
         return !m_error.empty();

+ 19 - 1
Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/AdapterBuilder.h

@@ -59,6 +59,13 @@ namespace AZ::DocumentPropertyEditor
         //! Sets an attribute of the last node. Rows, labels, and property editors all support different attributes.
         //! Sets an attribute of the last node. Rows, labels, and property editors all support different attributes.
         //! \see DocumentPropertyEditor::Nodes
         //! \see DocumentPropertyEditor::Nodes
         void Attribute(Name attribute, Dom::Value value);
         void Attribute(Name attribute, Dom::Value value);
+        //! Adds a Nodes::PropertyEditor::OnChanged attribute that will get called with
+        //! the path of the property value and its new value. This path can be used to generate a
+        //! correct Replace patch for submitting NotifyContentsChanged.
+        void OnEditorChanged(AZStd::function<void(const Dom::Path&, const Dom::Value&)> onChangedCallback);
+
+        //! Gets the path to the DOM node currently being built within this builder's DOM.
+        Dom::Path GetCurrentPath() const;
 
 
         //! Returns true if an error has been encountered during the build process, 
         //! Returns true if an error has been encountered during the build process, 
         bool IsError() const;
         bool IsError() const;
@@ -68,6 +75,12 @@ namespace AZ::DocumentPropertyEditor
         //! Operations are no longer valid on this builder once this is called.
         //! Operations are no longer valid on this builder once this is called.
         Dom::Value&& FinishAndTakeResult();
         Dom::Value&& FinishAndTakeResult();
 
 
+        template <class PropertyEditorDefinition>
+        void BeginPropertyEditor(Dom::Value value = {})
+        {
+            BeginPropertyEditor(PropertyEditorDefinition::Name, value);
+        }
+
         template <class NodeDefinition>
         template <class NodeDefinition>
         void BeginNode()
         void BeginNode()
         {
         {
@@ -92,12 +105,17 @@ namespace AZ::DocumentPropertyEditor
             Attribute(definition.GetName(), definition.ValueToDom(AZStd::move(value)));
             Attribute(definition.GetName(), definition.ValueToDom(AZStd::move(value)));
         }
         }
 
 
+        template <class CallbackType, class Functor>
+        void CallbackAttribute(const CallbackAttributeDefinition<CallbackType>& definition, Functor value)
+        {
+            Attribute(definition.GetName(), definition.ValueToDom(AZStd::function<CallbackType>(value)));
+        }
+
         void Attribute(const AttributeDefinition<AZStd::string_view>& definition, AZStd::string_view value)
         void Attribute(const AttributeDefinition<AZStd::string_view>& definition, AZStd::string_view value)
         {
         {
             Attribute(definition.GetName(), Dom::Value(value, true));
             Attribute(definition.GetName(), Dom::Value(value, true));
         }
         }
 
 
-
     private:
     private:
         void Error(AZStd::string_view message);
         void Error(AZStd::string_view message);
         Dom::Value& CurrentNode();
         Dom::Value& CurrentNode();

+ 1 - 1
Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/BasicAdapter.h

@@ -21,7 +21,7 @@ namespace AZ::DocumentPropertyEditor
         //! Resets the contents of this adapter with a new DOM.
         //! Resets the contents of this adapter with a new DOM.
         void SetContents(Dom::Value contents);
         void SetContents(Dom::Value contents);
         Dom::Value GetContents() const override;
         Dom::Value GetContents() const override;
-        Dom::PatchOutcome RequestContentChange(const Dom::Patch& patch) override;
+        Dom::PatchOutcome RequestContentChange(const Dom::Patch& patch);
 
 
     private:
     private:
         Dom::Value m_value;
         Dom::Value m_value;

+ 198 - 0
Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/CvarAdapter.cpp

@@ -0,0 +1,198 @@
+/*
+ * 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 <AzCore/Console/ConsoleFunctor.h>
+#include <AzCore/Console/IConsole.h>
+#include <AzCore/Interface/Interface.h>
+#include <AzFramework/DocumentPropertyEditor/AdapterBuilder.h>
+#include <AzFramework/DocumentPropertyEditor/CvarAdapter.h>
+
+namespace AZ::DocumentPropertyEditor
+{
+    struct CvarAdapter::Impl
+    {
+        Impl(CvarAdapter* adapter)
+            : m_adapter(adapter)
+        {
+        }
+
+        template<typename T>
+        bool TryBuildNumericEditor(AdapterBuilder& builder, ConsoleFunctorBase* functor)
+        {
+            if (functor->GetTypeId() == azrtti_typeid<T>())
+            {
+                T buffer;
+                functor->GetValue(buffer);
+                builder.BeginPropertyEditor<Nodes::SpinBox<T>>(Dom::Value(buffer));
+                builder.OnEditorChanged(
+                    [this, functor](const Dom::Path& path, const Dom::Value& value)
+                    {
+                        T buffer;
+                        if constexpr (AZStd::is_integral_v<T> && AZStd::is_signed_v<T>)
+                        {
+                            buffer = aznumeric_cast<T>(value.GetInt64());
+                        }
+                        else if constexpr (AZStd::is_integral_v<T> && AZStd::is_unsigned_v<T>)
+                        {
+                            buffer = aznumeric_cast<T>(value.GetUint64());
+                        }
+                        else
+                        {
+                            buffer = aznumeric_cast<T>(value.GetDouble());
+                        }
+                        (*functor)({ ConsoleTypeHelpers::ValueToString(buffer) });
+                        m_adapter->OnContentsChanged(path, value);
+                    });
+                builder.Attribute(Nodes::SpinBox<T>::Min, AZStd::numeric_limits<T>::min());
+                builder.Attribute(Nodes::SpinBox<T>::Max, AZStd::numeric_limits<T>::max());
+                builder.EndPropertyEditor();
+                return true;
+            }
+            return false;
+        }
+
+        template<typename First, typename Second, typename... Rest>
+        bool TryBuildNumericEditor(AdapterBuilder& builder, ConsoleFunctorBase* functor)
+        {
+            if (TryBuildNumericEditor<First>(builder, functor))
+            {
+                return true;
+            }
+            return TryBuildNumericEditor<Second, Rest...>(builder, functor);
+        }
+
+        bool TryBuildStringEditor(AdapterBuilder& builder, ConsoleFunctorBase* functor)
+        {
+            if (functor->GetTypeId() == azrtti_typeid<CVarFixedString>())
+            {
+                CVarFixedString buffer;
+                functor->GetValue(buffer);
+                builder.BeginPropertyEditor<Nodes::LineEdit>(Dom::Value(buffer, true));
+                builder.OnEditorChanged(
+                    [this, functor](const Dom::Path& path, const Dom::Value& value)
+                    {
+                        (*functor)({ value.GetString() });
+                        m_adapter->OnContentsChanged(path, value);
+                    });
+                builder.EndPropertyEditor();
+                return true;
+            }
+            return false;
+        }
+
+        template<typename VectorType, size_t ElementCount, typename NodeType>
+        bool TryBuildMathVectorEditor(AdapterBuilder& builder, ConsoleFunctorBase* functor)
+        {
+            if (functor->GetTypeId() == azrtti_typeid<VectorType>())
+            {
+                VectorType container;
+                functor->GetValue(container);
+                Dom::Value contents(Dom::Type::Array);
+                for (int i = 0; i < ElementCount; ++i)
+                {
+                    contents.ArrayPushBack(Dom::Value(container.GetElement(i)));
+                }
+                builder.BeginPropertyEditor<NodeType>(AZStd::move(contents));
+                builder.OnEditorChanged(
+                    [this, functor](const Dom::Path& path, const Dom::Value& value)
+                    {
+                        // ConsoleCommandContainer holds string_views, so ensure we allocate our parameters here
+                        AZStd::fixed_vector<CVarFixedString, ElementCount> newValue;
+                        for (int i = 0; i < ElementCount; ++i)
+                        {
+                            newValue.push_back(ConsoleTypeHelpers::ValueToString(value[i].GetDouble()));
+                        }
+                        (*functor)(ConsoleCommandContainer(newValue));
+                        m_adapter->OnContentsChanged(path, value);
+                    });
+                builder.EndPropertyEditor();
+                return true;
+            }
+            return false;
+        }
+
+        bool TryBuildCheckBoxEditor(AdapterBuilder& builder, ConsoleFunctorBase* functor)
+        {
+            if (functor->GetTypeId() == azrtti_typeid<bool>())
+            {
+                bool value;
+                functor->GetValue(value);
+                builder.BeginPropertyEditor<Nodes::CheckBox>(Dom::Value(value));
+                builder.OnEditorChanged(
+                    [this, functor](const Dom::Path& path, const Dom::Value& value)
+                    {
+                        (*functor)({ ConsoleTypeHelpers::ValueToString(value.GetBool()) });
+                        m_adapter->OnContentsChanged(path, value);
+                    });
+                builder.EndPropertyEditor();
+                return true;
+            }
+            return false;
+        }
+
+        bool BuildEditorForCvar(AdapterBuilder& builder, ConsoleFunctorBase* functor)
+        {
+            // Check all possible type IDs for our supported types and try to create a property editor
+            return TryBuildNumericEditor<int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t, float, double>(
+                       builder, functor) ||
+                TryBuildStringEditor(builder, functor) || TryBuildMathVectorEditor<AZ::Vector2, 2, Nodes::Vector2>(builder, functor) ||
+                TryBuildMathVectorEditor<AZ::Vector3, 3, Nodes::Vector3>(builder, functor) ||
+                TryBuildMathVectorEditor<AZ::Vector4, 4, Nodes::Vector4>(builder, functor) ||
+                TryBuildMathVectorEditor<AZ::Quaternion, 4, Nodes::Quaternion>(builder, functor) ||
+                TryBuildMathVectorEditor<AZ::Color, 4, Nodes::Color>(builder, functor) || TryBuildCheckBoxEditor(builder, functor);
+        }
+
+        CvarAdapter* m_adapter;
+    };
+
+    CvarAdapter::CvarAdapter()
+        : m_impl(AZStd::make_unique<Impl>(this))
+    {
+    }
+
+    CvarAdapter::~CvarAdapter()
+    {
+    }
+
+    Dom::Value CvarAdapter::GetContents() const
+    {
+        AdapterBuilder builder;
+        builder.BeginAdapter();
+
+        auto consoleInterface = AZ::Interface<AZ::IConsole>::Get();
+        if (consoleInterface != nullptr)
+        {
+            // Enumerate all functors, try to wire up a proper editor for each CVar
+            consoleInterface->VisitRegisteredFunctors(
+                [&](ConsoleFunctorBase* functor)
+                {
+                    // Skip console functors with no registered type ID - CVars all have a type ID set
+                    if (functor->GetTypeId().IsNull())
+                    {
+                        return;
+                    }
+                    builder.BeginRow();
+                    builder.Label(functor->GetName());
+                    if (!m_impl->BuildEditorForCvar(builder, functor))
+                    {
+                        builder.Label("Unknown CVAR type");
+                    }
+                    builder.EndRow();
+                });
+        }
+
+        builder.EndAdapter();
+        return builder.FinishAndTakeResult();
+    }
+
+    void CvarAdapter::OnContentsChanged(const Dom::Path& path, const Dom::Value& value)
+    {
+        // If one of our values has changed, forward a replace patch to the view
+        NotifyContentsChanged({ Dom::PatchOperation::ReplaceOperation(path, value) });
+    }
+} // namespace AZ::DocumentPropertyEditor

+ 31 - 0
Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/CvarAdapter.h

@@ -0,0 +1,31 @@
+/*
+ * 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 <AzFramework/DocumentPropertyEditor/DocumentAdapter.h>
+
+namespace AZ::DocumentPropertyEditor
+{
+    //! An adapter for displaying an editable list of CVars registered to the console instance.
+    //! Supports editing CVars with primitive types, string types, and numeric vector types
+    //! (VectorX, Quaternion, and Color).
+    class CvarAdapter : public DocumentAdapter
+    {
+    public:
+        CvarAdapter();
+        ~CvarAdapter();
+
+        Dom::Value GetContents() const override;
+        void OnContentsChanged(const Dom::Path& path, const Dom::Value& value);
+
+    private:
+        struct Impl;
+        AZStd::unique_ptr<Impl> m_impl;
+    };
+}

+ 0 - 4
Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/DocumentAdapter.h

@@ -47,10 +47,6 @@ namespace AZ::DocumentPropertyEditor
         //! Retrieves the contents of this adapter. This must be an Adapter DOM node.
         //! Retrieves the contents of this adapter. This must be an Adapter DOM node.
         //! \see AdapterBuilder for building out this DOM structure.
         //! \see AdapterBuilder for building out this DOM structure.
         virtual Dom::Value GetContents() const = 0;
         virtual Dom::Value GetContents() const = 0;
-        //! Called when the view would like to change the current contents - for example, by changing the value of
-        //! a property within a Property Editor. If this patch is accepted and triggers a mutation to the contents of this
-        //! adapter, NotifyContentsChanged should be called to trigger a change event with the accepted patches.
-        virtual Dom::PatchOutcome RequestContentChange(const Dom::Patch& patch) = 0;
 
 
         //! Connects a listener for the reset event, fired when the contents of this adapter have completely changed.
         //! Connects a listener for the reset event, fired when the contents of this adapter have completely changed.
         //! Any views listening to this adapter will need to call GetContents to retrieve the new contents of the adapter.
         //! Any views listening to this adapter will need to call GetContents to retrieve the new contents of the adapter.

+ 101 - 6
Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/DocumentSchema.h

@@ -9,8 +9,9 @@
 #pragma once
 #pragma once
 
 
 #include <AzCore/DOM/DomValue.h>
 #include <AzCore/DOM/DomValue.h>
-#include <AzCore/std/string/fixed_string.h>
 #include <AzCore/Name/Name.h>
 #include <AzCore/Name/Name.h>
+#include <AzCore/Outcome/Outcome.h>
+#include <AzCore/std/string/fixed_string.h>
 
 
 namespace AZ::DocumentPropertyEditor
 namespace AZ::DocumentPropertyEditor
 {
 {
@@ -45,12 +46,18 @@ namespace AZ::DocumentPropertyEditor
 
 
     //! Retrieves a node's name from a node definition.
     //! Retrieves a node's name from a node definition.
     //! \see NodeDefinition
     //! \see NodeDefinition
-    template <typename NodeDefinition>
+    template<typename NodeDefinition>
     Name GetNodeName()
     Name GetNodeName()
     {
     {
         return AZ::Name(NodeDefinition::Name);
         return AZ::Name(NodeDefinition::Name);
     }
     }
 
 
+    //! Defines a definition for a PropertyEditor, specified as the type of a PropertyEditor node
+    struct PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "<undefined editor name>";
+    };
+
     //! Defines an attribute applicable to a Node.
     //! Defines an attribute applicable to a Node.
     //! Attributes may be defined inline inside of a NodeDefinition.
     //! Attributes may be defined inline inside of a NodeDefinition.
     //! AttributeDefinitions may be used to marshal types to and from a DOM representation.
     //! AttributeDefinitions may be used to marshal types to and from a DOM representation.
@@ -74,17 +81,105 @@ namespace AZ::DocumentPropertyEditor
         //! Converts a value of this attribute's type to a DOM value.
         //! Converts a value of this attribute's type to a DOM value.
         Dom::Value ValueToDom(const AttributeType& attribute) const
         Dom::Value ValueToDom(const AttributeType& attribute) const
         {
         {
-            return Dom::Value(attribute);
+            if constexpr (AZStd::is_same_v<AZStd::string_view, AttributeType>)
+            {
+                return Dom::Value(attribute, true);
+            }
+            else if constexpr (AZStd::is_constructible_v<Dom::Value, const AttributeType&>)
+            {
+                return Dom::Value(attribute);
+            }
+            else
+            {
+                return Dom::Value::FromOpaqueValue(AZStd::any(attribute));
+            }
         }
         }
 
 
         //! Converts a DOM value to an instance of AttributeType.
         //! Converts a DOM value to an instance of AttributeType.
-        AttributeType&& DomToValue(const Dom::Value& value)
+        AttributeType&& DomToValue(const Dom::Value& value) const
         {
         {
             AZ_Assert(false, "DomToValue is not yet implemented");
             AZ_Assert(false, "DomToValue is not yet implemented");
             return {};
             return {};
         }
         }
 
 
-    private:
+    protected:
         AZStd::fixed_string<128> m_name;
         AZStd::fixed_string<128> m_name;
     };
     };
-}
+
+    //! Defines a callback applicable to a Node.
+    //! Callbacks are stored as attributes and accept an AZStd::function<CallbackSignature> stored as an
+    //! opaque value. Callbacks can be validated and invokved from DOM values using InvokeOnDomValue
+    //! and InvokeOnDomNode.
+    template<typename CallbackSignature>
+    class CallbackAttributeDefinition : public AttributeDefinition<AZStd::function<CallbackSignature>>
+    {
+    public:
+        using ErrorType = AZStd::fixed_string<128>;
+        using FunctionType = AZStd::function<CallbackSignature>;
+
+        constexpr CallbackAttributeDefinition(AZStd::string_view name)
+            : AttributeDefinition<FunctionType>(name)
+        {
+        }
+
+        template<typename T>
+        struct Traits;
+
+        template<typename Result, typename... Args>
+        struct Traits<Result(Args...)>
+        {
+            using ResultType = AZ::Outcome<Result, ErrorType>;
+
+            static ResultType Invoke(const AZStd::function<Result(Args...)>& fn, Args... args)
+            {
+                return AZ::Success(fn(args...));
+            }
+        };
+
+        template <typename... Args>
+        struct Traits<void(Args...)>
+        {
+            using ResultType = AZ::Outcome<void, ErrorType>;
+
+            static ResultType Invoke(const AZStd::function<void(Args...)>& fn, Args... args)
+            {
+                fn(args...);
+                return AZ::Success();
+            }
+        };
+
+        using CallbackTraits = Traits<CallbackSignature>;
+
+        //! Attempts to call a function with this attribute's callback signature stored in a DOM value as an opaque type.
+        //! Invokes the method with the specified args if our callback signature is found in the value, otherwise returns an error message.
+        template<typename... Args>
+        typename CallbackTraits::ResultType InvokeOnDomValue(const AZ::Dom::Value& value, Args... args) const
+        {
+            if (!value.IsOpaqueValue())
+            {
+                return AZ::Failure<ErrorType>("This property is holding a value and not a callback");
+            }
+
+            const AZStd::any& wrapper = value.GetOpaqueValue();
+            if (!wrapper.is<FunctionType>())
+            {
+                return AZ::Failure<ErrorType>("This property does not contain a callback with the correct signature");
+            }
+
+            return CallbackTraits::Invoke(AZStd::any_cast<FunctionType>(wrapper), args...);
+        }
+
+        //! Attemps to read this attribute from the specified DOM value, which must be a Node.
+        //! Invokes the method with the specified args if this attribute is specified, otherwise returns an error message.
+        template<typename... Args>
+        typename CallbackTraits::ResultType InvokeOnDomNode(const AZ::Dom::Value& value, Args... args) const
+        {
+            auto attributeIt = value.FindMember(this->GetName());
+            if (attributeIt == value.MemberEnd())
+            {
+                return AZ::Failure<ErrorType>(ErrorType::format("No \"%s\" attribute found", this->m_name.data()));
+            }
+            return this->InvokeOnDomValue(attributeIt->second, args...);
+        }
+    };
+} // namespace AZ::DocumentPropertyEditor

+ 98 - 1
Code/Framework/AzFramework/AzFramework/DocumentPropertyEditor/PropertyEditorNodes.h

@@ -39,6 +39,103 @@ namespace AZ::DocumentPropertyEditor::Nodes
     struct PropertyEditor : NodeDefinition
     struct PropertyEditor : NodeDefinition
     {
     {
         static constexpr AZStd::string_view Name = "PropertyEditor";
         static constexpr AZStd::string_view Name = "PropertyEditor";
-        static constexpr auto Type = AttributeDefinition<AZStd::string_view>("type");
+        static constexpr auto Type = AttributeDefinition<AZStd::string_view>("Type");
+        static constexpr auto OnChanged = CallbackAttributeDefinition<void(const Dom::Value&)>("OnChanged");
+    };
+
+    template<typename T>
+    struct NumericEditor
+    {
+        static_assert(AZStd::is_floating_point_v<T> || AZStd::is_integral_v<T>, "Numeric editors must have a numeric type");
+        static constexpr auto Min = AttributeDefinition<T>("Min");
+        static constexpr auto Max = AttributeDefinition<T>("Max");
+        static constexpr auto Step = AttributeDefinition<T>("Step");
+        static constexpr auto Suffix = AttributeDefinition<AZStd::string_view>("Suffix");
+        static constexpr auto SoftMin = AttributeDefinition<T>("SoftMin");
+        static constexpr auto SoftMax = AttributeDefinition<T>("SoftMax");
+        static constexpr auto Decimals = AttributeDefinition<int>("Decimals");
+        static constexpr auto DisplayDecimals = AttributeDefinition<int>("DisplayDecimals");
+    };
+
+    struct Button : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "Button";
+    };
+
+    struct CheckBox : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "CheckBox";
+    };
+
+    struct Color : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "Color";
+    };
+
+    struct ComboBox : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "ComboBox";
+    };
+
+    struct RadioButton : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "RadioButton";
+    };
+
+    struct EntityId : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "EntityId";
+    };
+
+    struct LayoutPadding : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "LayoutPadding";
+    };
+
+    struct LineEdit : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "LineEdit";
+    };
+
+    struct MultiLineEdit : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "MultiLineEdit";
+    };
+
+    struct Quaternion : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "Quaternion";
+    };
+
+    template<typename T>
+    struct Slider : NumericEditor<T>
+    {
+        static constexpr AZStd::string_view Name = "Slider";
+    };
+
+    template<typename T>
+    struct SpinBox : NumericEditor<T>
+    {
+        static constexpr AZStd::string_view Name = "SpinBox";
+    };
+
+    struct Crc : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "Crc";
+    };
+
+    struct Vector2 : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "Vector2";
+    };
+
+    struct Vector3 : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "Vector3";
+    };
+
+    struct Vector4 : PropertyEditorDefinition
+    {
+        static constexpr AZStd::string_view Name = "Vector4";
     };
     };
 } // namespace AZ::DocumentPropertyEditor::Nodes
 } // namespace AZ::DocumentPropertyEditor::Nodes

+ 2 - 2
Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp

@@ -73,10 +73,10 @@ namespace AzFramework
             m_retryAfterDisconnect = false;
             m_retryAfterDisconnect = false;
             m_isBusyDisconnecting = false;
             m_isBusyDisconnecting = false;
 
 
-            m_sendThread.m_desc.m_name = "APConnection::SendThread";
+            m_sendThread.m_desc.m_name = "APConnectSend";
             m_sendThread.m_main = AZStd::bind(&AssetProcessorConnection::SendThread, this);
             m_sendThread.m_main = AZStd::bind(&AssetProcessorConnection::SendThread, this);
 
 
-            m_recvThread.m_desc.m_name = "APConnection::RecvThread";
+            m_recvThread.m_desc.m_name = "APConnectRecv";
             m_recvThread.m_main = AZStd::bind(&AssetProcessorConnection::RecvThread, this);
             m_recvThread.m_main = AZStd::bind(&AssetProcessorConnection::RecvThread, this);
             
             
             // Put the AP send and receive threads on a core not shared by the main thread or render thread.
             // Put the AP send and receive threads on a core not shared by the main thread or render thread.

+ 3 - 23
Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSceneQueries.h

@@ -84,15 +84,7 @@ namespace AzPhysics
         };
         };
 
 
         //! Bitwise operators for HitFlags
         //! Bitwise operators for HitFlags
-        inline HitFlags operator|(HitFlags lhs, HitFlags rhs)
-        {
-            return static_cast<HitFlags>(static_cast<AZ::u16>(lhs) | static_cast<AZ::u16>(rhs));
-        }
-
-        inline HitFlags operator&(HitFlags lhs, HitFlags rhs)
-        {
-            return static_cast<HitFlags>(static_cast<AZ::u16>(lhs) & static_cast<AZ::u16>(rhs));
-        }
+        AZ_DEFINE_ENUM_BITWISE_OPERATORS(HitFlags)
 
 
         //! Flag used to mark which members are valid in a SceneQueryHit object.
         //! Flag used to mark which members are valid in a SceneQueryHit object.
         //! Example: if SceneQueryHit::m_resultFlags & ResultFlags::Distance is true,
         //! Example: if SceneQueryHit::m_resultFlags & ResultFlags::Distance is true,
@@ -109,21 +101,9 @@ namespace AzPhysics
             Position = (1 << 5),
             Position = (1 << 5),
             Normal = (1 << 6)
             Normal = (1 << 6)
         };
         };
-        //! Bitwise operators for ResultFlags
-        inline ResultFlags operator|(ResultFlags lhs, ResultFlags rhs)
-        {
-            return static_cast<ResultFlags>(static_cast<AZ::u8>(lhs) | static_cast<AZ::u8>(rhs));
-        }
 
 
-        inline ResultFlags operator|=(ResultFlags& lhs, ResultFlags rhs)
-        {
-            return (lhs = (lhs | rhs));
-        }
-
-        inline ResultFlags operator&(ResultFlags lhs, ResultFlags rhs)
-        {
-            return static_cast<ResultFlags>(static_cast<AZ::u8>(lhs) & static_cast<AZ::u8>(rhs));
-        }
+        //! Bitwise operators for ResultFlags
+        AZ_DEFINE_ENUM_BITWISE_OPERATORS(ResultFlags)
 
 
         //! Callback used for directed scene queries: RayCasts and ShapeCasts
         //! Callback used for directed scene queries: RayCasts and ShapeCasts
         using FilterCallback = AZStd::function<QueryHitType(const SimulatedBody* body, const Physics::Shape* shape)>;
         using FilterCallback = AZStd::function<QueryHitType(const SimulatedBody* body, const Physics::Shape* shape)>;

+ 2 - 9
Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsTypes.h

@@ -104,17 +104,10 @@ namespace AzPhysics
 
 
         DEFAULT = COMPUTE_COM | COMPUTE_INERTIA | COMPUTE_MASS
         DEFAULT = COMPUTE_COM | COMPUTE_INERTIA | COMPUTE_MASS
     };
     };
+
     //! Bitwise operators for MassComputeFlags
     //! Bitwise operators for MassComputeFlags
-    inline MassComputeFlags operator|(MassComputeFlags lhs, MassComputeFlags rhs)
-    {
-        return aznumeric_cast<MassComputeFlags>(aznumeric_cast<AZ::u8>(lhs) | aznumeric_cast<AZ::u8>(rhs));
-    }
+    AZ_DEFINE_ENUM_BITWISE_OPERATORS(MassComputeFlags)
 
 
-    inline MassComputeFlags operator&(MassComputeFlags lhs, MassComputeFlags rhs)
-    {
-        return aznumeric_cast<MassComputeFlags>(aznumeric_cast<AZ::u8>(lhs) & aznumeric_cast<AZ::u8>(rhs));
-    }
-    
     //! Variant to allow support for the system to either create the Shape(s) or use the provide Shape(s) that have been created externally.
     //! Variant to allow support for the system to either create the Shape(s) or use the provide Shape(s) that have been created externally.
     //! Can be one of the following.
     //! Can be one of the following.
     //! @code{ .cpp }
     //! @code{ .cpp }

+ 19 - 1
Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h

@@ -46,6 +46,8 @@ namespace Physics
         uint16_t m_padding{ 0 }; //!< available for future use.
         uint16_t m_padding{ 0 }; //!< available for future use.
     };
     };
 
 
+    using UpdateHeightfieldSampleFunction = AZStd::function<void(int32_t, int32_t, const Physics::HeightMaterialPoint&)>;
+
     //! An interface to provide heightfield values.
     //! An interface to provide heightfield values.
     class HeightfieldProviderRequests
     class HeightfieldProviderRequests
         : public AZ::ComponentBus
         : public AZ::ComponentBus
@@ -104,6 +106,9 @@ namespace Physics
         //! Returns the list of heights and materials used by the height field.
         //! Returns the list of heights and materials used by the height field.
         //! @return the rows*columns vector of the heights and materials.
         //! @return the rows*columns vector of the heights and materials.
         virtual AZStd::vector<Physics::HeightMaterialPoint> GetHeightsAndMaterials() const = 0;
         virtual AZStd::vector<Physics::HeightMaterialPoint> GetHeightsAndMaterials() const = 0;
+
+        //! Updates the list of heights and materials within the region. Pass Null region to update the entire list.
+        virtual void UpdateHeightsAndMaterials(const UpdateHeightfieldSampleFunction& updateHeightsMaterialsCallback, const AZ::Aabb& region) const = 0;
     };
     };
 
 
     using HeightfieldProviderRequestsBus = AZ::EBus<HeightfieldProviderRequests>;
     using HeightfieldProviderRequestsBus = AZ::EBus<HeightfieldProviderRequests>;
@@ -115,9 +120,20 @@ namespace Physics
     public:
     public:
         static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
         static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
 
 
+        enum class HeightfieldChangeMask : AZ::u8
+        {
+            None = 0,
+            Settings = (1 << 0),
+            HeightData = (1 << 1),
+            MaterialData = (1 << 2),
+            SurfaceData = (1 << 3),
+            Unspecified = 0xff
+        };
+
         //! Called whenever the heightfield data changes.
         //! Called whenever the heightfield data changes.
         //! @param the AABB of the area of data that changed.
         //! @param the AABB of the area of data that changed.
-        virtual void OnHeightfieldDataChanged([[maybe_unused]] const AZ::Aabb& dirtyRegion)
+        virtual void OnHeightfieldDataChanged([[maybe_unused]] const AZ::Aabb& dirtyRegion, 
+            [[maybe_unused]] Physics::HeightfieldProviderNotifications::HeightfieldChangeMask changeMask)
         {
         {
         }
         }
 
 
@@ -125,5 +141,7 @@ namespace Physics
         ~HeightfieldProviderNotifications() = default;
         ~HeightfieldProviderNotifications() = default;
     };
     };
 
 
+    AZ_DEFINE_ENUM_BITWISE_OPERATORS(HeightfieldProviderNotifications::HeightfieldChangeMask)
+
     using HeightfieldProviderNotificationBus = AZ::EBus<HeightfieldProviderNotifications>;
     using HeightfieldProviderNotificationBus = AZ::EBus<HeightfieldProviderNotifications>;
 } // namespace Physics
 } // namespace Physics

+ 1 - 1
Code/Framework/AzFramework/AzFramework/Physics/Mocks/MockHeightfieldProviderBus.h

@@ -28,6 +28,6 @@ namespace UnitTest
             Physics::HeightfieldProviderNotificationBus::Handler::BusDisconnect();
             Physics::HeightfieldProviderNotificationBus::Handler::BusDisconnect();
         }
         }
 
 
-        MOCK_METHOD1(OnHeightfieldDataChanged, void(const AZ::Aabb&));
+        MOCK_METHOD2(OnHeightfieldDataChanged, void(const AZ::Aabb&, Physics::HeightfieldProviderNotifications::HeightfieldChangeMask));
     };
     };
 } // namespace UnitTest
 } // namespace UnitTest

+ 15 - 0
Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp

@@ -413,6 +413,21 @@ namespace Physics
         return m_samples;
         return m_samples;
     }
     }
 
 
+    void HeightfieldShapeConfiguration::ModifySample(int32_t row, int32_t column, const Physics::HeightMaterialPoint& point)
+    {
+        const int32_t index = row * m_numColumns + column;
+        if (row < m_numRows && column < m_numColumns && index < m_samples.size())
+        {
+            m_samples[index] = point;
+        }
+        else
+        {
+            AZ_Error("HeightfieldShapeConfiguration", false,
+                "Trying to modify a sample out of range. Row: %d, Col: %d, NumColumns: %d, NumRows: %d",
+                row, column, m_numColumns, m_numRows);
+        }
+    }
+
     void HeightfieldShapeConfiguration::SetSamples(const AZStd::vector<Physics::HeightMaterialPoint>& samples)
     void HeightfieldShapeConfiguration::SetSamples(const AZStd::vector<Physics::HeightMaterialPoint>& samples)
     {
     {
         m_samples = samples;
         m_samples = samples;

+ 1 - 0
Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h

@@ -228,6 +228,7 @@ namespace Physics
         int32_t GetNumRows() const;
         int32_t GetNumRows() const;
         void SetNumRows(int32_t numRows);
         void SetNumRows(int32_t numRows);
         const AZStd::vector<Physics::HeightMaterialPoint>& GetSamples() const;
         const AZStd::vector<Physics::HeightMaterialPoint>& GetSamples() const;
+        void ModifySample(int32_t row, int32_t column, const Physics::HeightMaterialPoint& point);
         void SetSamples(const AZStd::vector<Physics::HeightMaterialPoint>& samples);
         void SetSamples(const AZStd::vector<Physics::HeightMaterialPoint>& samples);
         float GetMinHeightBounds() const;
         float GetMinHeightBounds() const;
         void SetMinHeightBounds(float minBounds);
         void SetMinHeightBounds(float minBounds);

+ 2 - 0
Code/Framework/AzFramework/AzFramework/azframework_files.cmake

@@ -144,6 +144,8 @@ set(FILES
     DocumentPropertyEditor/DocumentSchema.h
     DocumentPropertyEditor/DocumentSchema.h
     DocumentPropertyEditor/PropertyEditorNodes.cpp
     DocumentPropertyEditor/PropertyEditorNodes.cpp
     DocumentPropertyEditor/PropertyEditorNodes.h
     DocumentPropertyEditor/PropertyEditorNodes.h
+    DocumentPropertyEditor/CvarAdapter.cpp
+    DocumentPropertyEditor/CvarAdapter.h
     FileFunc/FileFunc.h
     FileFunc/FileFunc.h
     FileFunc/FileFunc.cpp
     FileFunc/FileFunc.cpp
     Font/FontInterface.h
     Font/FontInterface.h

+ 3 - 3
Code/Framework/AzFramework/Tests/DocumentPropertyEditor/AdapterBuilderTests.cpp

@@ -14,9 +14,9 @@
 
 
 namespace AZ::DocumentPropertyEditor::Tests
 namespace AZ::DocumentPropertyEditor::Tests
 {
 {
-    using AdapterBuilderTests = DocumentPropertyEditorTestFixture;
+    using AdapterBuilderDpeTests = DocumentPropertyEditorTestFixture;
 
 
-    TEST_F(AdapterBuilderTests, VisitSimpleStructure)
+    TEST_F(AdapterBuilderDpeTests, VisitSimpleStructure)
     {
     {
         AdapterBuilder builder;
         AdapterBuilder builder;
         builder.BeginAdapter();
         builder.BeginAdapter();
@@ -54,7 +54,7 @@ namespace AZ::DocumentPropertyEditor::Tests
         EXPECT_TRUE(Dom::Utils::DeepCompareIsEqual(expectedDom, domFromBuilder));
         EXPECT_TRUE(Dom::Utils::DeepCompareIsEqual(expectedDom, domFromBuilder));
     }
     }
 
 
-    TEST_F(AdapterBuilderTests, VisitNestedRows)
+    TEST_F(AdapterBuilderDpeTests, VisitNestedRows)
     {
     {
         AdapterBuilder builder;
         AdapterBuilder builder;
         builder.BeginAdapter();
         builder.BeginAdapter();

+ 167 - 0
Code/Framework/AzFramework/Tests/DocumentPropertyEditor/CvarAdapterTests.cpp

@@ -0,0 +1,167 @@
+/*
+ * 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 <AzCore/Console/Console.h>
+#include <AzCore/Console/IConsole.h>
+#include <AzCore/Console/IConsoleTypes.h>
+#include <AzCore/Interface/Interface.h>
+#include <AzFramework/DocumentPropertyEditor/AdapterBuilder.h>
+#include <AzFramework/DocumentPropertyEditor/CvarAdapter.h>
+#include <AzFramework/DocumentPropertyEditor/PropertyEditorNodes.h>
+#include <Tests/DocumentPropertyEditor/DocumentPropertyEditorFixture.h>
+
+namespace AZ::DocumentPropertyEditor::Tests
+{
+    AZ_CVAR(int32_t, dpe_TestInt, 1, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "DPE test int32");
+    AZ_CVAR(uint8_t, dpe_TestUint, 22, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "DPE test uint8");
+    AZ_CVAR(double, dpe_TestDbl, 4.0, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "DPE test double");
+    AZ_CVAR(CVarFixedString, dpe_TestString, "test", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "DPE test string");
+    AZ_CVAR(bool, dpe_TestBool, false, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "DPE test bool");
+    AZ_CVAR(AZ::Vector2, dpe_TestVec2, AZ::Vector2::CreateZero(), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "DPE test vec2");
+    AZ_CVAR(AZ::Vector3, dpe_TestVec3, AZ::Vector3::CreateOne(), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "DPE test vec3");
+    AZ_CVAR(AZ::Color, dpe_TestColor, AZ::Color(), nullptr, ConsoleFunctorFlags::DontReplicate, "DPE test color");
+
+    class CvarAdapterDpeTests : public DocumentPropertyEditorTestFixture
+    {
+    public:
+        void SetUp() override
+        {
+            DocumentPropertyEditorTestFixture::SetUp();
+            m_console = AZStd::make_unique<AZ::Console>();
+            m_console->LinkDeferredFunctors(AZ::ConsoleFunctorBase::GetDeferredHead());
+            AZ::Interface<AZ::IConsole>::Register(m_console.get());
+            m_adapter = AZStd::make_unique<CvarAdapter>();
+        }
+
+        void TearDown() override
+        {
+            m_adapter.reset();
+            AZ::Interface<AZ::IConsole>::Unregister(m_console.get());
+            m_console.reset();
+            DocumentPropertyEditorTestFixture::TearDown();
+        }
+
+        Dom::Value GetEntryRow(AZStd::string_view cvarName)
+        {
+            Dom::Value rows = m_adapter->GetContents();
+            for (auto it = rows.ArrayBegin(); it != rows.ArrayEnd(); ++it)
+            {
+                Dom::Value label = (*it)[0].GetNodeValue();
+                if (label.GetString() == cvarName)
+                {
+                    return *it;
+                }
+            }
+            return {};
+        }
+
+        Dom::Value GetEntryValue(AZStd::string_view cvarName)
+        {
+            Dom::Value row = GetEntryRow(cvarName);
+            EXPECT_FALSE(row.IsNull());
+            return row[1].GetNodeValue();
+        }
+
+        void SetEntryValue(AZStd::string_view cvarName, Dom::Value value)
+        {
+            Dom::Value row = GetEntryRow(cvarName);
+            ASSERT_FALSE(row.IsNull());
+            auto result = Nodes::PropertyEditor::OnChanged.InvokeOnDomNode(row[1], value);
+            EXPECT_TRUE(result.IsSuccess());
+            AZ_Error("CvarAdapterDpeTests", result.IsSuccess(), "%s", result.GetError().c_str());
+        }
+
+        AZStd::unique_ptr<AZ::Console> m_console;
+        AZStd::unique_ptr<CvarAdapter> m_adapter;
+    };
+
+    TEST_F(CvarAdapterDpeTests, IntCvar)
+    {
+        EXPECT_EQ(static_cast<int32_t>(dpe_TestInt), GetEntryValue("dpe_TestInt").GetInt64());
+        SetEntryValue("dpe_TestInt", Dom::Value(42));
+        EXPECT_EQ(42, dpe_TestInt);
+        EXPECT_EQ(42, GetEntryValue("dpe_TestInt").GetInt64());
+    }
+
+    TEST_F(CvarAdapterDpeTests, UintCvar)
+    {
+        EXPECT_EQ(static_cast<uint8_t>(dpe_TestUint), GetEntryValue("dpe_TestUint").GetUint64());
+        SetEntryValue("dpe_TestUint", Dom::Value(42));
+        EXPECT_EQ(42, dpe_TestUint);
+        EXPECT_EQ(42, GetEntryValue("dpe_TestUint").GetUint64());
+    }
+
+    TEST_F(CvarAdapterDpeTests, DoubleCvar)
+    {
+        EXPECT_EQ(static_cast<double>(dpe_TestDbl), GetEntryValue("dpe_TestDbl").GetDouble());
+        SetEntryValue("dpe_TestDbl", Dom::Value(6.28));
+        EXPECT_EQ(6.28, dpe_TestDbl);
+        EXPECT_EQ(6.28, GetEntryValue("dpe_TestDbl").GetDouble());
+    }
+
+    TEST_F(CvarAdapterDpeTests, StringCvar)
+    {
+        EXPECT_EQ(static_cast<CVarFixedString>(dpe_TestString), GetEntryValue("dpe_TestString").GetString());
+        SetEntryValue("dpe_TestString", Dom::Value("new string", true));
+        EXPECT_EQ("new string", static_cast<CVarFixedString>(dpe_TestString));
+        EXPECT_EQ("new string", GetEntryValue("dpe_TestString").GetString());
+    }
+
+    TEST_F(CvarAdapterDpeTests, BoolCvar)
+    {
+        EXPECT_EQ(static_cast<bool>(dpe_TestBool), GetEntryValue("dpe_TestBool").GetBool());
+        SetEntryValue("dpe_TestBool", Dom::Value(true));
+        EXPECT_EQ(true, static_cast<bool>(dpe_TestBool));
+        EXPECT_EQ(true, GetEntryValue("dpe_TestBool").GetBool());
+    }
+
+    TEST_F(CvarAdapterDpeTests, Vec2Cvar)
+    {
+        Dom::Value value = GetEntryValue("dpe_TestVec2");
+        EXPECT_EQ(static_cast<AZ::Vector2>(dpe_TestVec2), AZ::Vector2((float)value[0].GetDouble(), (float)value[1].GetDouble()));
+        value[0].SetDouble(2.0);
+        value[1].SetDouble(4.5);
+        SetEntryValue("dpe_TestVec2", value);
+        value = GetEntryValue("dpe_TestVec2");
+        EXPECT_EQ(2.0, GetEntryValue("dpe_TestVec2")[0].GetDouble());
+        EXPECT_EQ(4.5, GetEntryValue("dpe_TestVec2")[1].GetDouble());
+        EXPECT_EQ(AZ::Vector2(2.0f, 4.5f), static_cast<AZ::Vector2>(dpe_TestVec2));
+    }
+
+    TEST_F(CvarAdapterDpeTests, Vec3Cvar)
+    {
+        Dom::Value value = GetEntryValue("dpe_TestVec3");
+        EXPECT_EQ(
+            static_cast<AZ::Vector3>(dpe_TestVec3),
+            AZ::Vector3((float)value[0].GetDouble(), (float)value[1].GetDouble(), (float)value[2].GetDouble()));
+        value[1].SetDouble(5.0);
+        SetEntryValue("dpe_TestVec3", value);
+        value = GetEntryValue("dpe_TestVec3");
+        EXPECT_EQ(5.0, GetEntryValue("dpe_TestVec3")[1].GetDouble());
+        EXPECT_EQ(5.f, static_cast<AZ::Vector3>(dpe_TestVec3).GetY());
+    }
+
+    TEST_F(CvarAdapterDpeTests, ColorCvar)
+    {
+        Dom::Value value = GetEntryValue("dpe_TestColor");
+        EXPECT_EQ(
+            static_cast<AZ::Color>(dpe_TestColor),
+            AZ::Color((float)value[0].GetDouble(), (float)value[1].GetDouble(), (float)value[2].GetDouble(), (float)value[3].GetDouble()));
+        value[0].SetDouble(0.0);
+        value[1].SetDouble(1.0);
+        value[2].SetDouble(0.5);
+        value[3].SetDouble(0.25);
+        SetEntryValue("dpe_TestColor", value);
+        value = GetEntryValue("dpe_TestColor");
+        EXPECT_EQ(0.0, GetEntryValue("dpe_TestColor")[0].GetDouble());
+        EXPECT_EQ(1.0, GetEntryValue("dpe_TestColor")[1].GetDouble());
+        EXPECT_EQ(0.5, GetEntryValue("dpe_TestColor")[2].GetDouble());
+        EXPECT_EQ(0.25, GetEntryValue("dpe_TestColor")[3].GetDouble());
+        EXPECT_EQ(AZ::Color(0.f, 1.f, 0.5f, 0.25f), static_cast<AZ::Color>(dpe_TestColor));
+    }
+} // namespace AZ::DocumentPropertyEditor::Tests

+ 57 - 0
Code/Framework/AzFramework/Tests/DocumentPropertyEditor/SchemaTests.cpp

@@ -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
+ *
+ */
+
+#include <AzCore/DOM/DomUtils.h>
+#include <AzCore/std/any.h>
+#include <AzFramework/DocumentPropertyEditor/AdapterBuilder.h>
+#include <AzFramework/DocumentPropertyEditor/PropertyEditorNodes.h>
+#include <Tests/DocumentPropertyEditor/DocumentPropertyEditorFixture.h>
+
+namespace AZ::DocumentPropertyEditor::Tests
+{
+    class SchemaDpeTests : public DocumentPropertyEditorTestFixture
+    {
+    public:
+        static constexpr auto intAttr = AttributeDefinition<int>("intAttr");
+        static constexpr auto doubleAttr = AttributeDefinition<double>("doubleAttr");
+        static constexpr auto strAttr = AttributeDefinition<AZStd::string_view>("strAttr");
+        static constexpr auto fnAttr = CallbackAttributeDefinition<int(int, int)>("fnAttr");
+    };
+
+    TEST_F(SchemaDpeTests, ValueToDom)
+    {
+        Dom::Value v;
+        v = intAttr.ValueToDom(2);
+        EXPECT_EQ(2, v.GetInt64());
+        v = doubleAttr.ValueToDom(4.5);
+        EXPECT_EQ(4.5, v.GetDouble());
+        v = strAttr.ValueToDom("test string");
+        EXPECT_EQ("test string", v.GetString());
+    }
+
+    TEST_F(SchemaDpeTests, InvokeCallback)
+    {
+        Dom::Value v = fnAttr.ValueToDom(
+            [](int x, int y)
+            {
+                return x + y;
+            });
+        EXPECT_EQ(5, fnAttr.InvokeOnDomValue(v, 2, 3).GetValue());
+        EXPECT_EQ(0, fnAttr.InvokeOnDomValue(v, 5, -5).GetValue());
+        EXPECT_FALSE(fnAttr.InvokeOnDomValue(Dom::Value(), 1, 2).IsSuccess());
+        EXPECT_FALSE(fnAttr
+                         .InvokeOnDomValue(
+                             Dom::Value::FromOpaqueValue(AZStd::any(
+                                 AZStd::function<int(int)>([](int x)
+                                 {
+                                     return x;
+                                 }))),
+                             1, 2)
+                         .IsSuccess());
+    }
+} // namespace AZ::DocumentPropertyEditor::Tests

+ 2 - 0
Code/Framework/AzFramework/Tests/frameworktests_files.cmake

@@ -34,4 +34,6 @@ set(FILES
     CameraState.cpp
     CameraState.cpp
     InputTests.cpp
     InputTests.cpp
     DocumentPropertyEditor/AdapterBuilderTests.cpp
     DocumentPropertyEditor/AdapterBuilderTests.cpp
+    DocumentPropertyEditor/SchemaTests.cpp
+    DocumentPropertyEditor/CvarAdapterTests.cpp
 )
 )

+ 36 - 0
Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h

@@ -12,6 +12,7 @@
 #include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
 #include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
 #include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
 #include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
 #include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
 #include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
+#include <AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h>
 #include <AzToolsFramework/ViewportSelection/EditorDefaultSelection.h>
 #include <AzToolsFramework/ViewportSelection/EditorDefaultSelection.h>
 #include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
 #include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
 #include <type_traits>
 #include <type_traits>
@@ -53,4 +54,39 @@ namespace UnitTest
     //! dependent on AzToolsFramework::ToolsApplication.
     //! dependent on AzToolsFramework::ToolsApplication.
     using IndirectCallManipulatorViewportInteractionFixture =
     using IndirectCallManipulatorViewportInteractionFixture =
         IndirectCallManipulatorViewportInteractionFixtureMixin<ToolsApplicationFixture>;
         IndirectCallManipulatorViewportInteractionFixtureMixin<ToolsApplicationFixture>;
+
+    //! Fixture to provide the direct call viewport interaction that is dependent on AllocatorsTestFixture.
+    //! \tparam FixtureT The fixture that provides the AllocatorsTestFixture functionality.
+    template<typename FixtureT>
+    class DirectCallManipulatorViewportInteractionFixtureMixin : public FixtureT
+    {
+        using DirectCallManipulatorViewportInteraction = AzManipulatorTestFramework::DirectCallManipulatorViewportInteraction;
+        using ImmediateModeActionDispatcher = AzManipulatorTestFramework::ImmediateModeActionDispatcher;
+
+    public:
+        void SetUp() override
+        {
+            FixtureT::SetUp();
+            m_viewportManipulatorInteraction =
+                AZStd::make_unique<DirectCallManipulatorViewportInteraction>(AZStd::make_shared<NullDebugDisplayRequests>());
+            m_actionDispatcher = AZStd::make_unique<ImmediateModeActionDispatcher>(*m_viewportManipulatorInteraction);
+            m_cameraState =
+                AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize);
+        }
+
+        void TearDown() override
+        {
+            m_actionDispatcher.reset();
+            m_viewportManipulatorInteraction.reset();
+            FixtureT::TearDown();
+        }
+
+        AzFramework::CameraState m_cameraState;
+        AZStd::unique_ptr<ImmediateModeActionDispatcher> m_actionDispatcher;
+        AZStd::unique_ptr<DirectCallManipulatorViewportInteraction> m_viewportManipulatorInteraction;
+    };
+
+    //! Fixture to provide the direct call viewport interaction that inherits from AllocatorsTestFixture for minimal overhead.
+    using DirectCallManipulatorViewportInteractionFixture =
+        DirectCallManipulatorViewportInteractionFixtureMixin<AllocatorsTestFixture>;
 } // namespace UnitTest
 } // namespace UnitTest

+ 3 - 0
Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h

@@ -26,6 +26,9 @@ namespace AzManipulatorTestFramework
         // ManipulatorViewportInteractionInterface ...
         // ManipulatorViewportInteractionInterface ...
         const ViewportInteractionInterface& GetViewportInteraction() const override;
         const ViewportInteractionInterface& GetViewportInteraction() const override;
         const ManipulatorManagerInterface& GetManipulatorManager() const override;
         const ManipulatorManagerInterface& GetManipulatorManager() const override;
+        // make non-const overloads visible
+        using ManipulatorViewportInteraction::GetManipulatorManager;
+        using ManipulatorViewportInteraction::GetViewportInteraction;
 
 
     private:
     private:
         AZStd::shared_ptr<CustomManipulatorManager> m_customManager;
         AZStd::shared_ptr<CustomManipulatorManager> m_customManager;

+ 2 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp

@@ -71,6 +71,7 @@
 #include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiSystemComponent.h>
 #include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiSystemComponent.h>
 #include <AzToolsFramework/Undo/UndoCacheInterface.h>
 #include <AzToolsFramework/Undo/UndoCacheInterface.h>
 #include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
 #include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
+#include <AzToolsFramework/Viewport/ViewBookmarkSystemComponent.h>
 #include <Entity/EntityUtilityComponent.h>
 #include <Entity/EntityUtilityComponent.h>
 #include <AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.h>
 #include <AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.h>
 #include <Prefab/ProceduralPrefabSystemComponent.h>
 #include <Prefab/ProceduralPrefabSystemComponent.h>
@@ -275,6 +276,7 @@ namespace AzToolsFramework
                 azrtti_typeid<Prefab::PrefabSystemComponent>(),
                 azrtti_typeid<Prefab::PrefabSystemComponent>(),
                 azrtti_typeid<Prefab::ProceduralPrefabSystemComponent>(),
                 azrtti_typeid<Prefab::ProceduralPrefabSystemComponent>(),
                 azrtti_typeid<EditorEntityFixupComponent>(),
                 azrtti_typeid<EditorEntityFixupComponent>(),
+                azrtti_typeid<AzToolsFramework::ViewBookmarkSystemComponent>(),
                 azrtti_typeid<Components::EditorComponentAPIComponent>(),
                 azrtti_typeid<Components::EditorComponentAPIComponent>(),
                 azrtti_typeid<Components::EditorLevelComponentAPIComponent>(),
                 azrtti_typeid<Components::EditorLevelComponentAPIComponent>(),
                 azrtti_typeid<Components::EditorEntityActionComponent>(),
                 azrtti_typeid<Components::EditorEntityActionComponent>(),

+ 5 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp

@@ -56,6 +56,9 @@
 #include <AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h>
 #include <AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h>
 #include <AzToolsFramework/Entity/EntityUtilityComponent.h>
 #include <AzToolsFramework/Entity/EntityUtilityComponent.h>
 #include <AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.h>
 #include <AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.h>
+#include <AzToolsFramework/Viewport/SharedViewBookmarkComponent.h>
+#include <AzToolsFramework/Viewport/LocalViewBookmarkComponent.h>
+#include <AzToolsFramework/Viewport/ViewBookmarkSystemComponent.h>
 #include <Prefab/ProceduralPrefabSystemComponent.h>
 #include <Prefab/ProceduralPrefabSystemComponent.h>
 
 
 AZ_DEFINE_BUDGET(AzToolsFramework);
 AZ_DEFINE_BUDGET(AzToolsFramework);
@@ -84,6 +87,8 @@ namespace AzToolsFramework
             Prefab::PrefabSystemComponent::CreateDescriptor(),
             Prefab::PrefabSystemComponent::CreateDescriptor(),
             Prefab::EditorPrefabComponent::CreateDescriptor(),
             Prefab::EditorPrefabComponent::CreateDescriptor(),
             Prefab::ProceduralPrefabSystemComponent::CreateDescriptor(),
             Prefab::ProceduralPrefabSystemComponent::CreateDescriptor(),
+            AzToolsFramework::ViewBookmarkSystemComponent::CreateDescriptor(),
+            AzToolsFramework::LocalViewBookmarkComponent::CreateDescriptor(),
             Components::EditorEntityActionComponent::CreateDescriptor(),
             Components::EditorEntityActionComponent::CreateDescriptor(),
             Components::EditorEntityIconComponent::CreateDescriptor(),
             Components::EditorEntityIconComponent::CreateDescriptor(),
             Components::EditorInspectorComponent::CreateDescriptor(),
             Components::EditorInspectorComponent::CreateDescriptor(),

+ 5 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h

@@ -43,6 +43,11 @@ namespace AzToolsFramework
 
 
         //! Returns whether the entity id provided is part of the focused sub-tree.
         //! Returns whether the entity id provided is part of the focused sub-tree.
         virtual bool IsInFocusSubTree(AZ::EntityId entityId) const = 0;
         virtual bool IsInFocusSubTree(AZ::EntityId entityId) const = 0;
+
+        //! Verifies if the entityId provided matches with the current focus root.
+        //! @return True if the entity provided is the focus root, false otherwise.
+        virtual bool IsFocusRoot(AZ::EntityId entityId) const = 0;
+
     };
     };
 
 
 } // namespace AzToolsFramework
 } // namespace AzToolsFramework

+ 14 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp

@@ -126,6 +126,20 @@ namespace AzToolsFramework
         return AzToolsFramework::IsInFocusSubTree(entityId, m_focusRoot);
         return AzToolsFramework::IsInFocusSubTree(entityId, m_focusRoot);
     }
     }
 
 
+    bool FocusModeSystemComponent::IsFocusRoot(AZ::EntityId entityId) const
+    {
+        if (m_focusRoot.IsValid())
+        {
+            return (entityId == m_focusRoot);
+        }
+        else
+        {
+            AZ::EntityId parentId;
+            EditorEntityInfoRequestBus::EventResult(parentId, entityId, &EditorEntityInfoRequestBus::Events::GetParent);
+            return !parentId.IsValid();
+        }
+    }
+
     void FocusModeSystemComponent::OnEntityInfoUpdatedAddChildEnd(AZ::EntityId parentId, AZ::EntityId childId)
     void FocusModeSystemComponent::OnEntityInfoUpdatedAddChildEnd(AZ::EntityId parentId, AZ::EntityId childId)
     {
     {
         // If the parent's entityId is in the list and the child isn't, add the child to the list.
         // If the parent's entityId is in the list and the child isn't, add the child to the list.

+ 1 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.h

@@ -46,6 +46,7 @@ namespace AzToolsFramework
         void SetFocusRoot(AZ::EntityId entityId) override;
         void SetFocusRoot(AZ::EntityId entityId) override;
         void ClearFocusRoot(AzFramework::EntityContextId entityContextId) override;
         void ClearFocusRoot(AzFramework::EntityContextId entityContextId) override;
         AZ::EntityId GetFocusRoot(AzFramework::EntityContextId entityContextId) override;
         AZ::EntityId GetFocusRoot(AzFramework::EntityContextId entityContextId) override;
+        bool IsFocusRoot(AZ::EntityId entityId) const override;
         const EntityIdList& GetFocusedEntities(AzFramework::EntityContextId entityContextId) override;
         const EntityIdList& GetFocusedEntities(AzFramework::EntityContextId entityContextId) override;
         bool IsInFocusSubTree(AZ::EntityId entityId) const override;
         bool IsInFocusSubTree(AZ::EntityId entityId) const override;
 
 

+ 7 - 1
Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceComponent.cpp

@@ -80,7 +80,13 @@ namespace AzToolsFramework
 
 
         // set up signals before we start thread.
         // set up signals before we start thread.
         m_shutdownThreadSignal = false;
         m_shutdownThreadSignal = false;
-        m_WorkerThread = AZStd::thread(AZStd::bind(&PerforceComponent::ThreadWorker, this));
+        m_WorkerThread = AZStd::thread(
+            { /*m_name =*/ "Perforce worker" },
+            [this]
+            {
+                ThreadWorker();
+            }
+        );
 
 
         SourceControlConnectionRequestBus::Handler::BusConnect();
         SourceControlConnectionRequestBus::Handler::BusConnect();
         SourceControlCommandBus::Handler::BusConnect();
         SourceControlCommandBus::Handler::BusConnect();

+ 14 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp

@@ -28,6 +28,7 @@
 #include <AzToolsFramework/API/ToolsApplicationAPI.h>
 #include <AzToolsFramework/API/ToolsApplicationAPI.h>
 #include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
 #include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
 #include <AzToolsFramework/Entity/EditorEntityContextBus.h>
 #include <AzToolsFramework/Entity/EditorEntityContextBus.h>
+#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
 #include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityInterface.h>
 #include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityInterface.h>
 #include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
 #include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
 #include <AzToolsFramework/ToolsComponents/TransformComponentBus.h>
 #include <AzToolsFramework/ToolsComponents/TransformComponentBus.h>
@@ -927,6 +928,12 @@ namespace AzToolsFramework
 
 
             AZ::EntityId actualValue = static_cast<AZ::EntityId>(*((AZ::EntityId*)newValue));
             AZ::EntityId actualValue = static_cast<AZ::EntityId>(*((AZ::EntityId*)newValue));
 
 
+            if (!actualValue.IsValid())
+            {
+                // Handled by the calling code.
+                return AZ::Success();
+            }
+
             // Prevent setting the parent to the entity itself.
             // Prevent setting the parent to the entity itself.
             if (actualValue == GetEntityId())
             if (actualValue == GetEntityId())
             {
             {
@@ -1177,6 +1184,12 @@ namespace AzToolsFramework
             return AZ::Edit::PropertyRefreshLevels::EntireTree;
             return AZ::Edit::PropertyRefreshLevels::EntireTree;
         }
         }
 
 
+        bool TransformComponent::ShowClearButtonHandler()
+        {
+            // Hide the clear button if the current entity is the focus root, which is the default value.
+            return(!m_focusModeInterface->IsFocusRoot(GetParentId()));
+        }
+
         void TransformComponent::Reflect(AZ::ReflectContext* context)
         void TransformComponent::Reflect(AZ::ReflectContext* context)
         {
         {
             // reflect data for script, serialization, editing..
             // reflect data for script, serialization, editing..
@@ -1215,6 +1228,7 @@ namespace AzToolsFramework
                             Attribute(AZ::Edit::Attributes::ChangeValidate, &TransformComponent::ValidatePotentialParent)->
                             Attribute(AZ::Edit::Attributes::ChangeValidate, &TransformComponent::ValidatePotentialParent)->
                             Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::ParentChangedInspector)->
                             Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::ParentChangedInspector)->
                             Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::DontGatherReference | AZ::Edit::SliceFlags::NotPushableOnSliceRoot)->
                             Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::DontGatherReference | AZ::Edit::SliceFlags::NotPushableOnSliceRoot)->
+                            Attribute(AZ::Edit::Attributes::ShowClearButtonHandler, &TransformComponent::ShowClearButtonHandler)->
                         DataElement(AZ::Edit::UIHandlers::Default, &TransformComponent::m_editorTransform, "Values", "")->
                         DataElement(AZ::Edit::UIHandlers::Default, &TransformComponent::m_editorTransform, "Values", "")->
                             Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::TransformChangedInspector)->
                             Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::TransformChangedInspector)->
                             Attribute(AZ::Edit::Attributes::AutoExpand, true)->
                             Attribute(AZ::Edit::Attributes::AutoExpand, true)->

+ 2 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h

@@ -161,6 +161,8 @@ namespace AzToolsFramework
             void UpdateCachedWorldTransform();
             void UpdateCachedWorldTransform();
             void ClearCachedWorldTransform();
             void ClearCachedWorldTransform();
 
 
+            bool ShowClearButtonHandler();
+
             // SliceEntityHierarchyRequestBus
             // SliceEntityHierarchyRequestBus
             AZ::EntityId GetSliceEntityParentId() override;
             AZ::EntityId GetSliceEntityParentId() override;
             AZStd::vector<AZ::EntityId> GetSliceEntityChildren() override;
             AZStd::vector<AZ::EntityId> GetSliceEntityChildren() override;

+ 31 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp

@@ -39,6 +39,7 @@ AZ_POP_DISABLE_WARNING
 #include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
 #include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
 #include <AzToolsFramework/Entity/EditorEntityRuntimeActivationBus.h>
 #include <AzToolsFramework/Entity/EditorEntityRuntimeActivationBus.h>
 #include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
 #include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
+#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
 #include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
 #include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
 #include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
 #include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
 #include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
 #include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
@@ -501,6 +502,11 @@ namespace AzToolsFramework
         m_readOnlyEntityPublicInterface = AZ::Interface<ReadOnlyEntityPublicInterface>::Get();
         m_readOnlyEntityPublicInterface = AZ::Interface<ReadOnlyEntityPublicInterface>::Get();
         AZ_Assert(m_readOnlyEntityPublicInterface != nullptr, "EntityPropertyEditor requires a ReadOnlyEntityPublicInterface instance on Initialize.");
         AZ_Assert(m_readOnlyEntityPublicInterface != nullptr, "EntityPropertyEditor requires a ReadOnlyEntityPublicInterface instance on Initialize.");
 
 
+        m_focusModeInterface = AZ::Interface<AzToolsFramework::FocusModeInterface>::Get();
+        AZ_Assert(m_focusModeInterface != nullptr, "EntityPropertyEditor requires a FocusModeInterface instance on Initialize.");
+
+        m_containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get();
+
         setObjectName("EntityPropertyEditor");
         setObjectName("EntityPropertyEditor");
         setAcceptDrops(true);
         setAcceptDrops(true);
 
 
@@ -5666,15 +5672,40 @@ namespace AzToolsFramework
         AZ_PROFILE_FUNCTION(AzToolsFramework);
         AZ_PROFILE_FUNCTION(AzToolsFramework);
         AzToolsFramework::EditorInspectorComponentNotificationBus::MultiHandler::BusConnect(entityId);
         AzToolsFramework::EditorInspectorComponentNotificationBus::MultiHandler::BusConnect(entityId);
         AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler::BusConnect(entityId);
         AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler::BusConnect(entityId);
+        AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull();
+        EditorEntityContextRequestBus::BroadcastResult(
+            editorEntityContextId, &EditorEntityContextRequestBus::Events::GetEditorEntityContextId);
+        AzToolsFramework::FocusModeNotificationBus::Handler::BusConnect(editorEntityContextId);
     }
     }
 
 
     void EntityPropertyEditor::DisconnectFromEntityBuses(const AZ::EntityId& entityId)
     void EntityPropertyEditor::DisconnectFromEntityBuses(const AZ::EntityId& entityId)
     {
     {
         AZ_PROFILE_FUNCTION(AzToolsFramework);
         AZ_PROFILE_FUNCTION(AzToolsFramework);
+        AzToolsFramework::FocusModeNotificationBus::Handler::BusDisconnect();
         AzToolsFramework::EditorInspectorComponentNotificationBus::MultiHandler::BusDisconnect(entityId);
         AzToolsFramework::EditorInspectorComponentNotificationBus::MultiHandler::BusDisconnect(entityId);
         AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler::BusDisconnect(entityId);
         AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler::BusDisconnect(entityId);
     }
     }
 
 
+    void EntityPropertyEditor::OnEditorFocusChanged(
+        [[maybe_unused]] AZ::EntityId previousFocusEntityId, [[maybe_unused]] AZ::EntityId newFocusEntityId)
+    {
+        // We need to wait for the Container Entity System to update before checking
+        QTimer::singleShot( 1, this, [this]()
+            {
+                bool enable = true;
+                for (AZ::EntityId entityId : m_overrideSelectedEntityIds)
+                {
+                    if (!m_focusModeInterface->IsInFocusSubTree(entityId) ||
+                        m_containerEntityInterface->IsUnderClosedContainerEntity(entityId))
+                    {
+                        enable = false;
+                        break;
+                    }
+                }
+                SetEditorUiEnabled(enable);
+            });
+    }
+
     static void SetPropertyEditorState(Ui::EntityPropertyEditorUI* propertyEditorUi, const bool on)
     static void SetPropertyEditorState(Ui::EntityPropertyEditorUI* propertyEditorUi, const bool on)
     {
     {
         // enable/disable all widgets relating to the entity inspector that should
         // enable/disable all widgets relating to the entity inspector that should

+ 12 - 1
Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx

@@ -28,8 +28,10 @@
 #include <AzToolsFramework/API/EntityPropertyEditorRequestsBus.h>
 #include <AzToolsFramework/API/EntityPropertyEditorRequestsBus.h>
 #include <AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h>
 #include <AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h>
 #include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
 #include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
+#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
 #include <AzToolsFramework/Entity/EditorEntityContextBus.h>
 #include <AzToolsFramework/Entity/EditorEntityContextBus.h>
 #include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityBus.h>
 #include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityBus.h>
+#include <AzToolsFramework/FocusMode/FocusModeNotificationBus.h>
 #include <AzToolsFramework/ToolsComponents/ComponentMimeData.h>
 #include <AzToolsFramework/ToolsComponents/ComponentMimeData.h>
 #include <AzToolsFramework/ToolsComponents/EditorInspectorComponentBus.h>
 #include <AzToolsFramework/ToolsComponents/EditorInspectorComponentBus.h>
 #include <AzQtComponents/Components/O3DEStylesheet.h>
 #include <AzQtComponents/Components/O3DEStylesheet.h>
@@ -64,7 +66,9 @@ namespace AzToolsFramework
     class ComponentModeCollectionInterface;
     class ComponentModeCollectionInterface;
     struct SourceControlFileInfo;
     struct SourceControlFileInfo;
     class ReadOnlyEntityPublicInterface;
     class ReadOnlyEntityPublicInterface;
-
+    class FocusModeInterface;
+    class ContainerEntityInterface;
+ 
     namespace AssetBrowser
     namespace AssetBrowser
     {
     {
         class ProductAssetBrowserEntry;
         class ProductAssetBrowserEntry;
@@ -119,6 +123,7 @@ namespace AzToolsFramework
         , public AZ::TickBus::Handler
         , public AZ::TickBus::Handler
         , private EditorWindowUIRequestBus::Handler
         , private EditorWindowUIRequestBus::Handler
         , private ReadOnlyEntityPublicNotificationBus::Handler
         , private ReadOnlyEntityPublicNotificationBus::Handler
+        , public FocusModeNotificationBus::Handler
     {
     {
         Q_OBJECT;
         Q_OBJECT;
     public:
     public:
@@ -159,6 +164,9 @@ namespace AzToolsFramework
         void SetPropertyEditingComplete(InstanceDataNode* pNode) override;
         void SetPropertyEditingComplete(InstanceDataNode* pNode) override;
         void SealUndoStack() override;
         void SealUndoStack() override;
 
 
+        // FocusModeNotificationBus overrides ...
+        void OnEditorFocusChanged(AZ::EntityId previousFocusEntityId, AZ::EntityId newFocusEntityId) override;
+
         // Context menu population for entity component properties.
         // Context menu population for entity component properties.
         void RequestPropertyContextMenu(InstanceDataNode* node, const QPoint& globalPos) override;
         void RequestPropertyContextMenu(InstanceDataNode* node, const QPoint& globalPos) override;
 
 
@@ -635,6 +643,9 @@ namespace AzToolsFramework
         // Reordering row widgets within the RPE.
         // Reordering row widgets within the RPE.
         static constexpr float MoveFadeSeconds = 0.5f;
         static constexpr float MoveFadeSeconds = 0.5f;
 
 
+        FocusModeInterface* m_focusModeInterface = nullptr;
+        ContainerEntityInterface* m_containerEntityInterface = nullptr;
+
         ReorderState m_currentReorderState = ReorderState::Inactive;
         ReorderState m_currentReorderState = ReorderState::Inactive;
         ComponentEditor* m_reorderRowWidgetEditor = nullptr;
         ComponentEditor* m_reorderRowWidgetEditor = nullptr;
         InstanceDataNode* m_nodeToMove = nullptr;
         InstanceDataNode* m_nodeToMove = nullptr;

+ 9 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp

@@ -331,6 +331,7 @@ namespace AzToolsFramework
 
 
     void PropertyEntityIdCtrl::SetCurrentEntityId(const AZ::EntityId& newEntityId, bool emitChange, const AZStd::string& nameOverride)
     void PropertyEntityIdCtrl::SetCurrentEntityId(const AZ::EntityId& newEntityId, bool emitChange, const AZStd::string& nameOverride)
     {
     {
+        m_entityIdLineEdit->setClearButtonEnabled(HasClearButton());
         m_entityIdLineEdit->SetEntityId(newEntityId, nameOverride);
         m_entityIdLineEdit->SetEntityId(newEntityId, nameOverride);
         m_componentsSatisfyingServices.clear();
         m_componentsSatisfyingServices.clear();
 
 
@@ -515,6 +516,14 @@ namespace AzToolsFramework
                 GUI->SetIncompatibleServices(incompatibleServices);
                 GUI->SetIncompatibleServices(incompatibleServices);
             }
             }
         }
         }
+        else if (attrib == AZ::Edit::Attributes::ShowClearButtonHandler)
+        {
+            bool value;
+            if (attrValue->Read<bool>(value))
+            {
+                GUI->SetHasClearButton(value);
+            }
+        }
     }
     }
 
 
     void EntityIdPropertyHandler::WriteGUIValuesIntoProperty(size_t index, PropertyEntityIdCtrl* GUI, property_t& instance, InstanceDataNode* node)
     void EntityIdPropertyHandler::WriteGUIValuesIntoProperty(size_t index, PropertyEntityIdCtrl* GUI, property_t& instance, InstanceDataNode* node)

+ 4 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.hxx

@@ -72,6 +72,9 @@ namespace AzToolsFramework
 
 
         void SetAcceptedEntityContext(AzFramework::EntityContextId contextId);
         void SetAcceptedEntityContext(AzFramework::EntityContextId contextId);
 
 
+        void SetHasClearButton(bool value){ m_hasClearButton = value; }
+        bool HasClearButton(){ return m_hasClearButton; }
+
     signals:
     signals:
         void OnEntityIdChanged(AZ::EntityId newEntityId);
         void OnEntityIdChanged(AZ::EntityId newEntityId);
 
 
@@ -99,6 +102,7 @@ namespace AzToolsFramework
         AzFramework::EntityContextId m_acceptedEntityContextId;
         AzFramework::EntityContextId m_acceptedEntityContextId;
         AZStd::list<AZStd::string> m_componentsSatisfyingServices;
         AZStd::list<AZStd::string> m_componentsSatisfyingServices;
 
 
+        bool m_hasClearButton{ true };
         QIcon m_pickerIcon;
         QIcon m_pickerIcon;
     };
     };
 
 

+ 6 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp

@@ -402,6 +402,12 @@ namespace AzToolsFramework
     {
     {
         Initialize(groupName, pParent, depth, labelWidth);
         Initialize(groupName, pParent, depth, labelWidth);
         ChangeSourceNode(node);
         ChangeSourceNode(node);
+
+        // Need to invoke RefreshAttributesFromNode manually since it won't be called
+        // by this version of Initialize so that any change notify (along with other attributes)
+        // will be respected when toggling the group element
+        RefreshAttributesFromNode(true);
+
         CreateGroupToggleSwitch();
         CreateGroupToggleSwitch();
     }
     }
 
 

+ 1 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/Mocks/MockFocusModeInterface.h

@@ -25,5 +25,6 @@ namespace UnitTest
         MOCK_METHOD1(GetFocusRoot, AZ::EntityId(AzFramework::EntityContextId entityContextId));
         MOCK_METHOD1(GetFocusRoot, AZ::EntityId(AzFramework::EntityContextId entityContextId));
         MOCK_METHOD1(GetFocusedEntities, const AzToolsFramework::EntityIdList&(AzFramework::EntityContextId entityContextId));
         MOCK_METHOD1(GetFocusedEntities, const AzToolsFramework::EntityIdList&(AzFramework::EntityContextId entityContextId));
         MOCK_CONST_METHOD1(IsInFocusSubTree, bool(AZ::EntityId entityId));
         MOCK_CONST_METHOD1(IsInFocusSubTree, bool(AZ::EntityId entityId));
+        MOCK_CONST_METHOD1(IsFocusRoot, bool(AZ::EntityId entityId));
     };
     };
 } // namespace UnitTest
 } // namespace UnitTest

+ 51 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/LocalViewBookmarkComponent.cpp

@@ -0,0 +1,51 @@
+/*
+ * 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 <AzCore/RTTI/ReflectContext.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <Viewport/ViewBookmarkLoaderInterface.h>
+#include <AzToolsFramework/Viewport/LocalViewBookmarkComponent.h>
+
+namespace AzToolsFramework
+{
+    void LocalViewBookmarkComponent::Reflect(AZ::ReflectContext* context)
+    {
+        ViewBookmark::Reflect(context);
+
+        if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<LocalViewBookmarkComponent, EditorComponentBase>()->Field(
+                "LocalBookmarkFileName", &LocalViewBookmarkComponent::m_localBookmarksFileName);
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+            {
+                editContext
+                    ->Class<LocalViewBookmarkComponent>(
+                        "Local View Bookmark Component",
+                        "The Local View Bookmark Component allows the user to store bookmarks in a custom setreg file.")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "Local View Bookmarks")
+                    ->Attribute(AZ::Edit::Attributes::AddableByUser, true)
+                    ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Level"))
+                    ->Attribute(AZ::Edit::Attributes::Category, "View Bookmarks")
+                    ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
+                    ->DataElement(
+                        AZ::Edit::UIHandlers::Default, &LocalViewBookmarkComponent::m_localBookmarksFileName, "Local Bookmarks File Name", "");
+            }
+        }
+    }
+
+    const AZStd::string& LocalViewBookmarkComponent::GetLocalBookmarksFileName() const
+    {
+        return m_localBookmarksFileName;
+    }
+
+    void LocalViewBookmarkComponent::SetLocalBookmarksFileName(AZStd::string localBookmarksFileName)
+    {
+        m_localBookmarksFileName = AZStd::move(localBookmarksFileName);
+    }
+
+} // namespace AzToolsFramework

+ 31 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/LocalViewBookmarkComponent.h

@@ -0,0 +1,31 @@
+/*
+ * 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 <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
+
+namespace AzToolsFramework
+{
+    //! @class LocalViewBookmarkComponent.
+    //! @brief Component that stores the name of the local View bookmark file associated to the prefab.
+    class LocalViewBookmarkComponent : public AzToolsFramework::Components::EditorComponentBase
+    {
+    public:
+
+        AZ_EDITOR_COMPONENT(LocalViewBookmarkComponent, "{28E5C3B7-3732-4EFB-985E-3F578A83A357}", EditorComponentBase);
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        const AZStd::string& GetLocalBookmarksFileName() const;
+        void SetLocalBookmarksFileName(AZStd::string localBookmarksFileName);
+
+    private:
+        //! name of the local View bookmark file associated to the prefab. located in project/user/SettingsRegistry/ViewBookmarks.
+        AZStd::string m_localBookmarksFileName;
+    };
+} // namespace AzToolsFramework

+ 514 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/LocalViewBookmarkLoader.cpp

@@ -0,0 +1,514 @@
+/*
+ * 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 <API/ToolsApplicationAPI.h>
+#include <AzCore/Settings/SettingsRegistry.h>
+#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
+#include <AzCore/StringFunc/StringFunc.h>
+#include <AzCore/Utils/Utils.h>
+#include <Entity/PrefabEditorEntityOwnershipInterface.h>
+#include <Prefab/PrefabSystemComponentInterface.h>
+#include <Viewport/LocalViewBookmarkLoader.h>
+
+namespace AzToolsFramework
+{
+    static constexpr const char* ViewBookmarksRegistryPath = "/O3DE/ViewBookmarks/";
+    static constexpr const char* LocalBookmarksKey = "LocalBookmarks";
+    static constexpr const char* LastKnownLocationKey = "LastKnownLocation";
+
+    // Temporary value until there is UI to expose the fields.
+    static constexpr int NumOfDefaultLocationsInLevel = 12;
+
+    void LocalViewBookmarkLoader::RegisterViewBookmarkLoaderInterface()
+    {
+        AZ::Interface<ViewBookmarkLoaderInterface>::Register(this);
+    }
+
+    void LocalViewBookmarkLoader::UnregisterViewBookmarkLoaderInterface()
+    {
+        AZ::Interface<ViewBookmarkLoaderInterface>::Unregister(this);
+    }
+
+    void LocalViewBookmarkLoader::SaveBookmarkSettingsFile()
+    {
+        auto registry = AZ::SettingsRegistry::Get();
+        if (!registry)
+        {
+            AZ_Warning("LocalViewBookmarkLoader", false, "Unable to access global settings registry. Editor Preferences cannot be saved");
+            return;
+        }
+
+        // Resolve path to user project folder
+        AZ::IO::FixedMaxPath editorBookmarkFilePath = AZ::IO::FixedMaxPath(AZ::Utils::GetProjectPath()) / "user/Registry/ViewBookmarks/";
+
+        editorBookmarkFilePath /= m_bookmarkfileName;
+
+        AZ::SettingsRegistryMergeUtils::DumperSettings dumperSettings;
+        dumperSettings.m_prettifyOutput = true;
+
+        AZStd::string bookmarkKey = "/" + m_bookmarkfileName;
+
+        dumperSettings.m_includeFilter = [&bookmarkKey](AZStd::string_view path)
+        {
+            AZStd::string_view o3dePrefixPath(bookmarkKey);
+            return o3dePrefixPath.starts_with(path.substr(0, o3dePrefixPath.size()));
+        };
+
+        AZStd::string stringBuffer;
+        AZ::IO::ByteContainerStream stringStream(&stringBuffer);
+        if (!AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream(*registry, "", stringStream, dumperSettings))
+        {
+            AZ_Warning(
+                "LocalViewBookmarkLoader", false, R"(Unable to save changes to the Editor Preferences registry file at "%s"\n)",
+                editorBookmarkFilePath.c_str());
+            return;
+        }
+
+        bool saved = false;
+        constexpr auto configurationMode =
+            AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
+        if (AZ::IO::SystemFile outputFile; outputFile.Open(editorBookmarkFilePath.c_str(), configurationMode))
+        {
+            saved = outputFile.Write(stringBuffer.data(), stringBuffer.size()) == stringBuffer.size();
+        }
+
+        // Once written to the desired file remove the key from the settings registry
+        registry->Remove(bookmarkKey + "/");
+        AZ_Warning(
+            "LocalViewBookmarkLoader", saved, R"(Unable to save Local View Bookmark file to path "%s"\n)", editorBookmarkFilePath.c_str());
+    }
+
+    bool LocalViewBookmarkLoader::SaveBookmark(const ViewBookmark& bookmark)
+    {
+        return SaveLocalBookmark(bookmark, ViewBookmarkType::Standard);
+    }
+
+    bool LocalViewBookmarkLoader::ModifyBookmarkAtIndex(const ViewBookmark& bookmark, int index)
+    {
+        if (index < 0 || index > m_localBookmarkCount)
+        {
+            return false;
+        }
+
+        LoadDefaultLocalViewBookmarks();
+
+        AZStd::string finalPath = "/" + m_bookmarkfileName + "/LocalBookmarks/" + AZStd::to_string(index);
+
+        bool success = false;
+        if (auto registry = AZ::SettingsRegistry::Get())
+        {
+            success = registry->SetObject(finalPath, bookmark);
+        }
+
+        // If we managed to add the bookmark
+        if (success)
+        {
+            SaveBookmarkSettingsFile();
+            LoadViewBookmarks();
+        }
+        return success;
+    }
+
+    bool LocalViewBookmarkLoader::SaveLastKnownLocation(const ViewBookmark& bookmark)
+    {
+        return SaveLocalBookmark(bookmark, ViewBookmarkType::LastKnownLocation);
+    }
+
+    bool LocalViewBookmarkLoader::LoadViewBookmarks()
+    {
+        struct ViewBookmarkVisitor : AZ::SettingsRegistryInterface::Visitor
+        {
+            ViewBookmarkVisitor()
+                : m_viewBookmarksKey{ "/O3DE/ViewBookmarks" } {};
+
+            AZ::SettingsRegistryInterface::VisitResponse Traverse(
+                AZStd::string_view path,
+                AZStd::string_view,
+                AZ::SettingsRegistryInterface::VisitAction action,
+                AZ::SettingsRegistryInterface::Type) override
+            {
+                if (action == AZ::SettingsRegistryInterface::VisitAction::Begin)
+                {
+                    // Strip off the last JSON pointer key from the path and if it matches the viewmark key then add an entry
+                    // to the ViewBookmark Map
+                    AZStd::optional<AZStd::string_view> localBookmarksID = AZ::StringFunc::TokenizeLast(path, "/");
+                    if (path == m_viewBookmarksKey && localBookmarksID && !localBookmarksID->empty())
+                    {
+                        AZStd::string_view bookmarkKey = localBookmarksID.value();
+
+                        if (auto existingBookmarkEntry = m_bookmarkMap.find(bookmarkKey) == m_bookmarkMap.end())
+                        {
+                            m_bookmarkMap.insert(AZStd::make_pair(bookmarkKey, AZStd::vector<ViewBookmark>{}));
+                        }
+                    }
+                }
+
+                return AZ::SettingsRegistryInterface::VisitResponse::Continue;
+            }
+
+            using AZ::SettingsRegistryInterface::Visitor::Visit;
+            void Visit(AZStd::string_view path, AZStd::string_view valueIndex, AZ::SettingsRegistryInterface::Type, double value) override
+            {
+                AZ::StringFunc::TokenizeLast(path, "/");
+                AZStd::optional<AZStd::string_view> dataType = AZ::StringFunc::TokenizeLast(path, "/");
+                AZStd::optional<AZStd::string_view> bookmarkIndexStr = AZ::StringFunc::TokenizeLast(path, "/");
+                AZStd::optional<AZStd::string_view> bookmarkType;
+                if (bookmarkIndexStr == LastKnownLocationKey)
+                {
+                    bookmarkType = bookmarkIndexStr;
+                }
+                else
+                {
+                    // differentiate between local Bookmarks and LastKnownLocation
+                    bookmarkType = AZ::StringFunc::TokenizeLast(path, "/");
+                }
+                AZStd::optional<AZStd::string_view> localBookmarksID = AZ::StringFunc::TokenizeLast(path, "/");
+
+                if (path == m_viewBookmarksKey && localBookmarksID && !localBookmarksID->empty())
+                {
+                    auto setVec3Fn = [value](AZ::Vector3& inout, int currentIndex)
+                    {
+                        switch (currentIndex)
+                        {
+                        case 0:
+                            inout.SetX(aznumeric_cast<float>(value));
+                            break;
+                        case 1:
+                            inout.SetY(aznumeric_cast<float>(value));
+                            break;
+                        case 2:
+                            inout.SetZ(aznumeric_cast<float>(value));
+                            break;
+                        default:
+                            AZ_Warning("LocalViewBookmarkLoader", false, "Trying to set an invalid index in a Vector3, index = %d", currentIndex);
+                            break;
+                        }
+                    };
+
+                    if (bookmarkType == LastKnownLocationKey)
+                    {
+                        int currentIndex = stoi(AZStd::string(valueIndex));
+                        if (dataType == "Position")
+                        {
+                            setVec3Fn(m_lastKnownLocation.m_position, currentIndex);
+                        }
+                        else if (dataType == "Rotation")
+                        {
+                            setVec3Fn(m_lastKnownLocation.m_rotation, currentIndex);
+                        }
+                    }
+                    else if (bookmarkType == LocalBookmarksKey)
+                    {
+                        auto existingBookmarkEntry = m_bookmarkMap.find(localBookmarksID.value());
+                        if (existingBookmarkEntry != m_bookmarkMap.end())
+                        {
+                            AZStd::vector<ViewBookmark>& bookmarks = existingBookmarkEntry->second;
+                            // if it is the first bookmark and it is the Position data it means it is the first one
+                            // and we have to create the Bookmark.
+                            if (valueIndex == "0" && dataType == "Position")
+                            {
+                                ViewBookmark bookmark;
+                                bookmark.m_position.SetX(aznumeric_cast<float>(value));
+                                bookmarks.push_back(bookmark);
+                            }
+                            else
+                            {
+                                int bookmarkIndex = stoi(AZStd::string(bookmarkIndexStr->data()));
+                                ViewBookmark& bookmark = bookmarks.at(bookmarkIndex);
+                                int currentIndex = stoi(AZStd::string(valueIndex));
+
+                                if (dataType == "Position")
+                                {
+                                    setVec3Fn(bookmark.m_position, currentIndex);
+                                }
+                                else if (dataType == "Rotation")
+                                {
+                                    setVec3Fn(bookmark.m_rotation, currentIndex);
+                                }
+                            }
+                        }
+                    }
+                }
+            };
+
+            const AZ::SettingsRegistryInterface::FixedValueString m_viewBookmarksKey;
+            AZStd::unordered_map<AZStd::string, AZStd::vector<ViewBookmark>> m_bookmarkMap;
+            ViewBookmark m_lastKnownLocation;
+        };
+
+        if (LocalViewBookmarkComponent* bookmarkComponent = RetrieveLocalViewBookmarkComponent())
+        {
+            // Get the file we want to merge into the settings registry.
+            if (!bookmarkComponent->GetLocalBookmarksFileName().empty())
+            {
+                auto registry = AZ::SettingsRegistry::Get();
+                if (!registry)
+                {
+                    AZ_Warning(
+                        "LocalViewBookmarkLoader", false, "Unable to access global settings registry. Editor Preferences cannot be saved");
+                    return false;
+                }
+
+                auto projectUserRegistryPath = AZ::IO::FixedMaxPath(AZ::Utils::GetProjectPath()) / "user/Registry/ViewBookmarks";
+                projectUserRegistryPath /= AZ::IO::FixedMaxPathString(bookmarkComponent->GetLocalBookmarksFileName());
+
+                // Merge the current viewBookmark file into the settings registry.
+                bool isMerged = registry->MergeSettingsFile(
+                    projectUserRegistryPath.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "/O3DE/ViewBookmarks");
+
+                if (isMerged)
+                {
+                    m_bookmarkfileName = bookmarkComponent->GetLocalBookmarksFileName();
+                    using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
+                    AZStd::string bookmarkKey = ViewBookmarksRegistryPath + m_bookmarkfileName;
+                    auto viewBookmarkSettingsKey = FixedValueString::format("%s",bookmarkKey.c_str());
+                    ViewBookmarkVisitor viewBookmarkVisitor;
+
+                    const bool visitedViewBookmarks = registry->Visit(viewBookmarkVisitor, viewBookmarkSettingsKey);
+
+                    if (visitedViewBookmarks)
+                    {
+                        m_localBookmarks = viewBookmarkVisitor.m_bookmarkMap.at(m_bookmarkfileName);
+                        m_localBookmarkCount = m_localBookmarks.size() - 1;
+                        m_lastKnownLocation = viewBookmarkVisitor.m_lastKnownLocation;
+                    }
+
+                    // once loaded we can remove the data from the settings registry.
+                    registry->Remove(bookmarkKey + "/");
+                    return visitedViewBookmarks;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    AZStd::optional<ViewBookmark> LocalViewBookmarkLoader::LoadBookmarkAtIndex(int index)
+    {
+        LoadViewBookmarks();
+        if (index >= 0 && index < m_localBookmarks.size())
+        {
+            return AZStd::optional<ViewBookmark>(m_localBookmarks.at(index));
+        }
+        AZ_Warning("LocalViewBookmarkLoader", false, "Couldn't load View Bookmark from file.");
+        return AZStd::nullopt;
+    }
+
+    bool LocalViewBookmarkLoader::RemoveBookmarkAtIndex(int index)
+    {
+        if (index < 0 || index > m_localBookmarkCount)
+        {
+            return false;
+        }
+
+        AZStd::string finalPath = "/" + m_bookmarkfileName + "/LocalBookmarks/" + AZStd::to_string(index);
+
+        bool success = false;
+        if (auto registry = AZ::SettingsRegistry::Get())
+        {
+            success = registry->Remove(finalPath);
+        }
+
+        if (!success)
+        {
+            AZ_Warning("LocalViewBookmarkLoader", false, "couldn't remove View Bookmark at index %d", index);
+            return false;
+        }
+
+        // If we managed to remove the bookmark
+        SaveBookmarkSettingsFile();
+        LoadViewBookmarks();
+
+        return success;
+
+    }
+
+    AZStd::optional<ViewBookmark> LocalViewBookmarkLoader::LoadLastKnownLocation() const
+    {
+        return m_lastKnownLocation;
+    }
+
+    LocalViewBookmarkComponent* LocalViewBookmarkLoader::RetrieveLocalViewBookmarkComponent()
+    {
+        AZ::EntityId levelEntityId;
+        AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
+            levelEntityId, &AzToolsFramework::ToolsApplicationRequests::GetCurrentLevelEntityId);
+
+        if (!levelEntityId.IsValid())
+        {
+            return nullptr;
+        }
+
+        AZ::Entity* levelEntity = nullptr;
+        AZ::ComponentApplicationBus::BroadcastResult(levelEntity, &AZ::ComponentApplicationBus::Events::FindEntity, levelEntityId);
+
+        if (!levelEntity)
+        {
+            return nullptr;
+        }
+
+        LocalViewBookmarkComponent* bookmarkComponent = levelEntity->FindComponent<LocalViewBookmarkComponent>();
+        if (bookmarkComponent)
+        {
+            return bookmarkComponent;
+        }
+
+        // If we didn't find a component then we add it and return it.
+        levelEntity->Deactivate();
+        levelEntity->CreateComponent<LocalViewBookmarkComponent>();
+        levelEntity->Activate();
+        bookmarkComponent = levelEntity->FindComponent<LocalViewBookmarkComponent>();
+        
+        AZ_Assert(bookmarkComponent, "Couldn't create LocalViewBookmarkComponent.");
+        return bookmarkComponent;
+    }
+
+    AZStd::string LocalViewBookmarkLoader::GenerateBookmarkFileName() const
+    {
+        auto* prefabEditorEntityOwnershipInterface = AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
+        AZ_Assert(prefabEditorEntityOwnershipInterface != nullptr, "PrefabEditorEntityOwnershipInterface is not found.");
+        AzToolsFramework::Prefab::TemplateId rootPrefabTemplateId = prefabEditorEntityOwnershipInterface->GetRootPrefabTemplateId();
+
+        if (rootPrefabTemplateId == AzToolsFramework::Prefab::InvalidTemplateId)
+        {
+            return AZStd::string();
+        }
+
+        auto* prefabSystemComponent = AZ::Interface<AzToolsFramework::Prefab::PrefabSystemComponentInterface>::Get();
+        AZ_Assert(
+            prefabSystemComponent != nullptr,
+            "Prefab System Component Interface could not be found. "
+            "It is a requirement for the LocalViewBookmarkLoader class. "
+            "Check that it is being correctly initialized.");
+
+        auto prefabTemplate = prefabSystemComponent->FindTemplate(rootPrefabTemplateId);
+        AZStd::string prefabTemplateName = prefabTemplate->get().GetFilePath().Filename().Stem().Native();
+
+        // To generate the file name in which we will store the view Bookmarks we use the name of the prefab + the timestamp
+        // e.g. LevelName_1639763579377.setreg
+        AZStd::chrono::system_clock::time_point now = AZStd::chrono::system_clock::now();
+        AZStd::string sTime = AZStd::string::format("%llu", now.time_since_epoch().count());
+        return prefabTemplateName.data() + AZStd::string("_") + sTime + ".setreg";
+    }
+
+    bool LocalViewBookmarkLoader::LoadDefaultLocalViewBookmarks()
+    {
+        // Write to the settings registry
+        auto registry = AZ::SettingsRegistry::Get();
+        if (!registry)
+        {
+            AZ_Warning("LocalViewBookmarkLoader", false, "Couldn't load Settings Registry");
+            return false;
+        }
+
+        LocalViewBookmarkComponent* bookmarkComponent = RetrieveLocalViewBookmarkComponent();
+        if (!bookmarkComponent)
+        {
+            AZ_Warning("LocalViewBookmarkLoader", false, "Couldn't find a LocalViewBookmarkComponent");
+            return false;
+        }
+
+        // if the field is not empty then we have a file linked to the prefab.
+        if (!bookmarkComponent->GetLocalBookmarksFileName().empty())
+        {
+            m_bookmarkfileName = bookmarkComponent->GetLocalBookmarksFileName();
+
+            AZ::IO::FixedMaxPath editorBookmarkFilePath = AZ::IO::FixedMaxPath(AZ::Utils::GetProjectPath()) / "user/Registry/ViewBookmarks/";
+            editorBookmarkFilePath /= m_bookmarkfileName;
+            AZ::IO::SystemFile outputFile;
+
+            //If the file doesn't exist but we got a valid filename from source control then let's create the file.
+            if (!outputFile.Exists(editorBookmarkFilePath.c_str()))
+            {
+                constexpr auto configurationMode = AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH |
+                    AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
+                outputFile.Open(editorBookmarkFilePath.c_str(), configurationMode);
+
+                // Initialize default locations to 0. This is a temporary solution to match the 12 locations of the legacy system.
+                // Once there is a UI for the view bookmarks these lines should be removed.
+                for (int i = 0; i < NumOfDefaultLocationsInLevel; i++)
+                {
+                    AZStd::string finalPath =
+                        "/" + m_bookmarkfileName + "/LocalBookmarks/" + AZStd::to_string(m_localBookmarkCount++);
+                    registry->SetObject(finalPath, ViewBookmark());
+                }
+
+                LoadViewBookmarks();
+                return true;
+            }
+            else
+            {
+                LoadViewBookmarks();
+
+                for (int i = 0; i < m_localBookmarks.size(); i++)
+                {
+                    AZStd::string finalPath = "/" + m_bookmarkfileName + "/LocalBookmarks/" + AZStd::to_string(i);
+                    registry->SetObject(finalPath, m_localBookmarks.at(i));
+                }
+
+                return true;
+            }
+        }
+        else // if the field is empty we don't have a file linked to the prefab, so we create one and we save it in the
+             // component
+        {
+            m_bookmarkfileName = GenerateBookmarkFileName();
+
+            // Initialize default locations to 0
+            for (int i = 0; i < NumOfDefaultLocationsInLevel; i++)
+            {
+                AZStd::string finalPath = "/" + m_bookmarkfileName + "/LocalBookmarks/" + AZStd::to_string(m_localBookmarkCount++);
+                registry->SetObject(finalPath, ViewBookmark());
+            }
+
+            LoadViewBookmarks();
+            bookmarkComponent->SetLocalBookmarksFileName(m_bookmarkfileName);
+            return true;
+        }
+    }
+
+    bool LocalViewBookmarkLoader::SaveLocalBookmark(const ViewBookmark& bookmark, ViewBookmarkType bookmarkType)
+    {
+        LoadDefaultLocalViewBookmarks();
+
+        AZStd::string finalPath;
+
+        switch (bookmarkType)
+        {
+        case ViewBookmarkType::Standard:
+            finalPath = "/" + m_bookmarkfileName + "/LocalBookmarks/" + AZStd::to_string(m_localBookmarkCount++);
+            break;
+        case ViewBookmarkType::LastKnownLocation:
+            finalPath = "/" + m_bookmarkfileName + "/LastKnownLocation";
+            break;
+        }
+
+        bool success = false;
+        // Write to the settings registry
+        if (auto registry = AZ::SettingsRegistry::Get())
+        {
+            success = registry->SetObject(finalPath, bookmark);
+        }
+
+        if (!success)
+        {
+             AZ_Warning(
+                 "LocalViewBookmarkLoader", false, "View Bookmark x=%.4f, y=%.4f, z=%.4f couldn't be saved", bookmark.m_position.GetX(),
+                 bookmark.m_position.GetY(), bookmark.m_position.GetZ());
+            return false; 
+        }
+
+        // If we managed to add the bookmark
+        SaveBookmarkSettingsFile();
+
+        //Once we have written into our viewbookmark file let's load the new values.
+        LoadViewBookmarks();
+
+        return success;
+    }
+} // namespace AzToolsFramework

+ 58 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/LocalViewBookmarkLoader.h

@@ -0,0 +1,58 @@
+/*
+ * 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 <AzCore/Settings/SettingsRegistryImpl.h>
+#include <Viewport/LocalViewBookmarkComponent.h>
+#include <Viewport/ViewBookmarkLoaderInterface.h>
+
+namespace AzToolsFramework
+{
+    //! @class LocalViewBookmarkLoader.
+    //! @brief class used to load/store local ViewBookmarks from project/user/Registry/ViewBookmarks.
+    class LocalViewBookmarkLoader final : public ViewBookmarkLoaderInterface
+    {
+    public:
+        AZ_CLASS_ALLOCATOR(LocalViewBookmarkLoader, AZ::SystemAllocator, 0);
+        AZ_RTTI(LocalViewBookmarkLoader, "{A64F2300-0958-4430-9EEA-1D457997E618}", ViewBookmarkLoaderInterface);
+
+        enum class ViewBookmarkType : int
+        {
+            Standard,
+            LastKnownLocation
+        };
+
+        void RegisterViewBookmarkLoaderInterface();
+        void UnregisterViewBookmarkLoaderInterface();
+
+        bool SaveBookmark(const ViewBookmark& bookmark) override;
+        bool ModifyBookmarkAtIndex(const ViewBookmark& bookmark, int index) override;
+        bool SaveLastKnownLocation(const ViewBookmark& bookmark) override;
+        bool RemoveBookmarkAtIndex(int index) override;
+
+        AZStd::optional<ViewBookmark> LoadBookmarkAtIndex(int index) override;
+        AZStd::optional<ViewBookmark> LoadLastKnownLocation() const override;
+
+    private:
+        bool LoadViewBookmarks() override;
+        void SaveBookmarkSettingsFile() override;
+        bool SaveLocalBookmark(const ViewBookmark& bookmark, ViewBookmarkType bookmarkType);
+        bool LoadDefaultLocalViewBookmarks();
+
+        LocalViewBookmarkComponent* RetrieveLocalViewBookmarkComponent();
+
+        AZStd::string GenerateBookmarkFileName() const;
+
+    private:
+        AZStd::vector<ViewBookmark> m_localBookmarks;
+        AZStd::optional<ViewBookmark> m_lastKnownLocation = AZStd::nullopt;
+        size_t m_localBookmarkCount = 0;
+        AZStd::string m_bookmarkfileName;
+    };
+
+} // namespace AzToolsFramework

+ 111 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/SharedViewBookmarkComponent.cpp

@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#include <AzCore/RTTI/BehaviorContext.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Utils/Utils.h>
+#include <AzToolsFramework/Viewport/SharedViewBookmarkComponent.h>
+
+namespace AzToolsFramework
+{
+    void EditorViewBookmarks::Reflect(AZ::ReflectContext* context)
+    {
+        if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<EditorViewBookmarks>()->Field("ViewBookmarks", &EditorViewBookmarks::m_viewBookmarks);
+
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+            {
+                editContext->Class<EditorViewBookmarks>("EditorViewBookmarks", "")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "Editor View Bookmarks")
+                    ->DataElement(AZ::Edit::UIHandlers::Default, &EditorViewBookmarks::m_viewBookmarks, "View Bookmarks", "")
+                    ->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, true)
+                    ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
+                    ->Attribute(AZ::Edit::Attributes::IndexedChildNameLabelOverride, &EditorViewBookmarks::GetBookmarkLabel);
+            }
+        }
+    }
+
+    AZStd::string EditorViewBookmarks::GetBookmarkLabel(int index) const
+    {
+        return AZStd::string::format("View Bookmark %d", index);
+    }
+
+    void SharedViewBookmarkComponent::Reflect(AZ::ReflectContext* context)
+    {
+        EditorViewBookmarks::Reflect(context);
+
+        if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->RegisterGenericType<EditorViewBookmarks>();
+
+            serializeContext->Class<SharedViewBookmarkComponent, EditorComponentBase>()->Version(0)->Field(
+                "ViewBookmarks", &SharedViewBookmarkComponent::m_viewBookmark);
+
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+            {
+                editContext
+                    ->Class<SharedViewBookmarkComponent>(
+                        "Shared View Bookmark Component", "The ViewBookmark Component allows to store bookmarks for a prefab")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                    ->Attribute(AZ::Edit::Attributes::AddableByUser, false)
+                    ->Attribute(AZ::Edit::Attributes::Category, "View Bookmarks")
+                    ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
+                    ->DataElement(
+                        AZ::Edit::UIHandlers::Default, &SharedViewBookmarkComponent::m_viewBookmark, "ViewBookmarks", "ViewBookmarks")
+                    ->Attribute(AZ::Edit::Attributes::AutoExpand, false);
+            }
+        }
+    }
+
+    AZStd::optional<ViewBookmark> SharedViewBookmarkComponent::GetBookmarkAtIndex(int index) const
+    {
+        if (index >= 0 && index < m_viewBookmark.m_viewBookmarks.size())
+        {
+            return AZStd::optional<ViewBookmark>(m_viewBookmark.m_viewBookmarks[index]);
+        }
+        return AZStd::nullopt;
+    }
+
+    void SharedViewBookmarkComponent::AddBookmark(ViewBookmark viewBookmark)
+    {
+        m_viewBookmark.m_viewBookmarks.push_back(AZStd::move(viewBookmark));
+    }
+
+    bool SharedViewBookmarkComponent::RemoveBookmarkAtIndex(int index)
+    {
+        if (index >= 0 && index < m_viewBookmark.m_viewBookmarks.size())
+        {
+            m_viewBookmark.m_viewBookmarks.erase(m_viewBookmark.m_viewBookmarks.cbegin() + index);
+            return true;
+        }
+
+        return false;
+    }
+
+    bool SharedViewBookmarkComponent::ModifyBookmarkAtIndex(int index, const ViewBookmark& newBookmark)
+    {
+        if (index >= 0 && index < m_viewBookmark.m_viewBookmarks.size())
+        {
+            m_viewBookmark.m_viewBookmarks[index] = newBookmark;
+            return true;
+        }
+        return false;
+    }
+
+    void SharedViewBookmarkComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
+    {
+        services.push_back(AZ_CRC_CE("EditorViewbookmarkingService"));
+    }
+
+    void SharedViewBookmarkComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
+    {
+        services.push_back(AZ_CRC_CE("EditorViewbookmarkingService"));
+    }
+
+} // namespace AzToolsFramework

+ 55 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/SharedViewBookmarkComponent.h

@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#pragma once
+
+#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
+#include <Viewport/ViewBookmarkLoaderInterface.h>
+
+namespace AzToolsFramework
+{
+    //! @class EditorViewBookmarks.
+    //! @brief struct that stores a vector of View bookmarks.
+    struct EditorViewBookmarks final
+    {
+        AZ_CLASS_ALLOCATOR(EditorViewBookmarks, AZ::SystemAllocator, 0);
+        AZ_TYPE_INFO(EditorViewBookmarks, "{EA0B8FF9-F706-4115-8226-E3F54F1EE8A1}");
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        AZStd::string GetBookmarkLabel(int index) const;
+
+        AZStd::vector<ViewBookmark> m_viewBookmarks;
+    };
+
+    //! @class SharedViewBookmarkComponent.
+    //! @brief component that stores a vector of View bookmarks stored in the prefab.
+    //! so they can be shared in version control easily.
+    class SharedViewBookmarkComponent : public AzToolsFramework::Components::EditorComponentBase
+    {
+    public:
+        static constexpr const char* const ViewBookmarkComponentTypeId = "{6959832F-9382-4C7D-83AC-380DA9F138DE}";
+
+        AZ_EDITOR_COMPONENT(SharedViewBookmarkComponent, ViewBookmarkComponentTypeId, EditorComponentBase);
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        AZStd::optional<ViewBookmark> GetBookmarkAtIndex(int index) const;
+        void AddBookmark(ViewBookmark viewBookmark);
+        bool RemoveBookmarkAtIndex(int index);
+        bool ModifyBookmarkAtIndex(int index, const ViewBookmark& newBookmark);
+
+    protected:
+        static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
+        static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
+
+    private:
+        //! A user editable list of View Bookmarks
+        EditorViewBookmarks m_viewBookmark;
+    };
+
+} // namespace AzToolsFramework

+ 88 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewBookmarkLoaderInterface.h

@@ -0,0 +1,88 @@
+/*
+ * 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 <AzCore/Math/Vector3.h>
+#include <AzCore/Interface/Interface.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Serialization/EditContext.h>
+
+
+namespace AzToolsFramework
+{
+    //! @class ViewBookmark
+    //! @brief struct that store viewport camera properties that can be serialized and loaded
+    struct ViewBookmark
+    {
+        AZ_CLASS_ALLOCATOR(ViewBookmark, AZ::SystemAllocator, 0);
+        AZ_TYPE_INFO(ViewBookmark, "{9D6601B9-922F-4E90-BEB2-4D3D709DADD7}");
+
+        ViewBookmark() = default;
+
+        static void Reflect(AZ::ReflectContext* context)
+        {
+            if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+            {
+                serializeContext->Class<ViewBookmark>()
+                    ->Version(0)
+                    ->Field("Position", &ViewBookmark::m_position)
+                    ->Field("Rotation", &ViewBookmark::m_rotation);
+
+                if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+                {
+                    editContext->Class<ViewBookmark>("ViewBookmark Data", "")
+                        ->ClassElement(AZ::Edit::ClassElements::EditorData, "ViewBookmark")
+                        ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
+                        ->DataElement(AZ::Edit::UIHandlers::Vector3, &ViewBookmark::m_position, "Position", "")
+                        ->DataElement(AZ::Edit::UIHandlers::Vector3, &ViewBookmark::m_rotation, "Rotation", "");
+                }
+            }
+        }
+
+        bool operator==(const ViewBookmark& other) const
+        {
+            return m_position == other.m_position && m_rotation == other.m_rotation;
+        }
+
+        bool operator!=(const ViewBookmark& other) const
+        {
+            return !(*this == other);
+        }
+
+        bool IsZero() const
+        {
+            return m_position == AZ::Vector3::CreateZero() && m_rotation == AZ::Vector3::CreateZero();
+        }
+
+        AZ::Vector3 m_position = AZ::Vector3::CreateZero();
+
+        //! Rotation in radians.
+        AZ::Vector3 m_rotation = AZ::Vector3::CreateZero();
+
+    };
+
+    //! @class ViewBookmarkIntereface
+    //! @brief Interface for saving/loading View Bookmarks.
+    class ViewBookmarkLoaderInterface
+    {
+    public:
+        AZ_RTTI(ViewBookmarkLoaderInterface, "{71E7E178-4107-4975-A6E6-1C4B005C981A}")
+
+        virtual bool SaveBookmark(const ViewBookmark& bookmark) = 0;
+        virtual bool ModifyBookmarkAtIndex(const ViewBookmark& bookmark, int index) = 0;
+        virtual bool SaveLastKnownLocation(const ViewBookmark& bookmark) = 0;
+        virtual bool LoadViewBookmarks() = 0;
+        virtual AZStd::optional<ViewBookmark> LoadBookmarkAtIndex(int index) = 0;
+        virtual AZStd::optional<ViewBookmark> LoadLastKnownLocation() const = 0;
+        virtual bool RemoveBookmarkAtIndex(int index) = 0;
+
+    private:
+        virtual void SaveBookmarkSettingsFile() = 0;
+    };
+} // namespace AzToolsFramework

+ 36 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewBookmarkSystemComponent.cpp

@@ -0,0 +1,36 @@
+/*
+ * 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 <Viewport/ViewBookmarkSystemComponent.h>
+
+namespace AzToolsFramework
+{
+    void ViewBookmarkSystemComponent::Activate()
+    {
+        m_viewBookmarkLoader.RegisterViewBookmarkLoaderInterface();
+    }
+
+    void ViewBookmarkSystemComponent::Deactivate()
+    {
+        m_viewBookmarkLoader.UnregisterViewBookmarkLoaderInterface();
+    }
+
+    void ViewBookmarkSystemComponent::Reflect(AZ::ReflectContext* context)
+    {
+        if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serialize->Class<ViewBookmarkSystemComponent, AZ::Component>()->Version(0);
+        }
+    }
+
+    void ViewBookmarkSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
+    {
+        provided.push_back(AZ_CRC_CE("ViewBookmarkSystem"));
+    }
+
+} // namespace AzToolsFramework

+ 38 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewBookmarkSystemComponent.h

@@ -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
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Component/Component.h>
+#include <Viewport/LocalViewBookmarkLoader.h>
+
+namespace AzToolsFramework
+{
+    //! @class ViewBookmarkSystemComponent
+    //! @brief System Component that holds functionality for the ViewBookmarks
+    class ViewBookmarkSystemComponent final : public AZ::Component
+    {
+    public:
+        AZ_COMPONENT(ViewBookmarkSystemComponent, "{FDD852BA-5F9E-4676-B121-D4B2FDEA7F55}");
+
+        ViewBookmarkSystemComponent() = default;
+
+        virtual ~ViewBookmarkSystemComponent() = default;
+
+        // AZ::Component overrides ...
+        void Activate() override;
+        void Deactivate() override;
+
+        static void Reflect(AZ::ReflectContext* context);
+        static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
+
+    private:
+        //! Used for loading/saving View Bookmarks.
+        LocalViewBookmarkLoader m_viewBookmarkLoader;
+    };
+} // namespace AzToolsFramework

+ 23 - 7
Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp

@@ -117,10 +117,30 @@ namespace AzToolsFramework
     static EntityData EntityDataFromEntityId(const AZ::EntityId entityId)
     static EntityData EntityDataFromEntityId(const AZ::EntityId entityId)
     {
     {
         bool visible = false;
         bool visible = false;
-        EditorEntityInfoRequestBus::EventResult(visible, entityId, &EditorEntityInfoRequestBus::Events::IsVisible);
-
         bool locked = false;
         bool locked = false;
-        EditorEntityInfoRequestBus::EventResult(locked, entityId, &EditorEntityInfoRequestBus::Events::IsLocked);
+        bool iconHidden = false;
+
+        // Check to see if the given entity is an Editor entity or a Runtime entity.
+        bool isEditorEntity = false;
+        AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult(
+            isEditorEntity, &AzToolsFramework::EditorEntityContextRequests::IsEditorEntity, entityId);
+
+        if (isEditorEntity)
+        {
+            EditorEntityInfoRequestBus::EventResult(visible, entityId, &EditorEntityInfoRequestBus::Events::IsVisible);
+            EditorEntityInfoRequestBus::EventResult(locked, entityId, &EditorEntityInfoRequestBus::Events::IsLocked);
+            EditorEntityIconComponentRequestBus::EventResult(
+                iconHidden, entityId, &EditorEntityIconComponentRequests::IsEntityIconHiddenInViewport);
+        }
+        else
+        {
+            // If this is a runtime entity, default visible / locked / iconHidden to true. This will cause the entity to be displayed
+            // but not selectable assuming it is listening to the debug display bus.
+
+            visible = true;
+            locked = true;
+            iconHidden = true;
+        }
 
 
         bool inFocus = false;
         bool inFocus = false;
         if (auto focusModeInterface = AZ::Interface<FocusModeInterface>::Get())
         if (auto focusModeInterface = AZ::Interface<FocusModeInterface>::Get())
@@ -134,10 +154,6 @@ namespace AzToolsFramework
             descendantOfClosedContainer = containerEntityInterface->IsUnderClosedContainerEntity(entityId);
             descendantOfClosedContainer = containerEntityInterface->IsUnderClosedContainerEntity(entityId);
         }
         }
 
 
-        bool iconHidden = false;
-        EditorEntityIconComponentRequestBus::EventResult(
-            iconHidden, entityId, &EditorEntityIconComponentRequests::IsEntityIconHiddenInViewport);
-
         AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
         AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
         AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
         AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
 
 

+ 9 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake

@@ -487,6 +487,15 @@ set(FILES
     Viewport/EditorContextMenu.cpp
     Viewport/EditorContextMenu.cpp
     Viewport/VertexContainerDisplay.h
     Viewport/VertexContainerDisplay.h
     Viewport/VertexContainerDisplay.cpp
     Viewport/VertexContainerDisplay.cpp
+    Viewport/LocalViewBookmarkComponent.h
+    Viewport/LocalViewBookmarkComponent.cpp
+    Viewport/SharedViewBookmarkComponent.h
+    Viewport/SharedViewBookmarkComponent.cpp
+    Viewport/LocalViewBookmarkLoader.h
+    Viewport/LocalViewBookmarkLoader.cpp
+    Viewport/ViewBookmarkLoaderInterface.h
+    Viewport/ViewBookmarkSystemComponent.h
+    Viewport/ViewBookmarkSystemComponent.cpp
     Viewport/ViewportInteractionHelpers.h
     Viewport/ViewportInteractionHelpers.h
     Viewport/ViewportInteractionHelpers.cpp
     Viewport/ViewportInteractionHelpers.cpp
     Viewport/ViewportMessages.h
     Viewport/ViewportMessages.h

+ 109 - 29
Code/Framework/AzToolsFramework/Tests/ManipulatorCoreTests.cpp

@@ -8,66 +8,95 @@
 
 
 #include <AzCore/Component/Entity.h>
 #include <AzCore/Component/Entity.h>
 #include <AzCore/Serialization/SerializeContext.h>
 #include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/UnitTest/TestTypes.h>
+#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h>
 #include <AzTest/AzTest.h>
 #include <AzTest/AzTest.h>
 #include <AzToolsFramework/Application/ToolsApplication.h>
 #include <AzToolsFramework/Application/ToolsApplication.h>
 #include <AzToolsFramework/Manipulators/LinearManipulator.h>
 #include <AzToolsFramework/Manipulators/LinearManipulator.h>
-#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
 #include <AzToolsFramework/ToolsComponents/EditorLockComponent.h>
 #include <AzToolsFramework/ToolsComponents/EditorLockComponent.h>
 #include <AzToolsFramework/ToolsComponents/EditorVisibilityComponent.h>
 #include <AzToolsFramework/ToolsComponents/EditorVisibilityComponent.h>
-#include <AzCore/UnitTest/TestTypes.h>
-
+#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
 #include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
 #include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
 
 
-using namespace AzToolsFramework;
-
 namespace UnitTest
 namespace UnitTest
 {
 {
-    class ManipulatorCoreFixture
-        : public ToolsApplicationFixture
+    class ManipulatorCoreFixture : public AllocatorsTestFixture
     {
     {
     public:
     public:
-        void SetUpEditorFixtureImpl() override
+        void SetUp() override
         {
         {
-            m_linearManipulator = LinearManipulator::MakeShared(AZ::Transform::CreateIdentity());
+            AllocatorsTestFixture::SetUp();
+
+            m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
+
+            m_transformComponentDescriptor =
+                AZStd::unique_ptr<AZ::ComponentDescriptor>(AzToolsFramework::Components::TransformComponent::CreateDescriptor());
+            m_transformComponentDescriptor->Reflect(&(*m_serializeContext));
+
+            m_lockComponentDescriptor =
+                AZStd::unique_ptr<AZ::ComponentDescriptor>(AzToolsFramework::Components::EditorLockComponent::CreateDescriptor());
+            m_lockComponentDescriptor->Reflect(&(*m_serializeContext));
 
 
-            m_entityId = CreateDefaultEditorEntity("Default", &m_entity);
+            m_visibilityComponentDescriptor =
+                AZStd::unique_ptr<AZ::ComponentDescriptor>(AzToolsFramework::Components::EditorVisibilityComponent::CreateDescriptor());
+            m_visibilityComponentDescriptor->Reflect(&(*m_serializeContext));
 
 
-            if (const auto* transformComponent = m_entity->FindComponent<Components::TransformComponent>())
+            m_linearManipulator = AzToolsFramework::LinearManipulator::MakeShared(AZ::Transform::CreateIdentity());
+
+            m_entity = AZStd::make_unique<AZ::Entity>();
+            // add required components for the Editor entity
+            m_entity->CreateComponent<AzToolsFramework::Components::TransformComponent>();
+            m_entity->CreateComponent<AzToolsFramework::Components::EditorLockComponent>();
+            m_entity->CreateComponent<AzToolsFramework::Components::EditorVisibilityComponent>();
+
+            m_entity->Init();
+            m_entity->Activate();
+
+            if (const auto* transformComponent = m_entity->FindComponent<AzToolsFramework::Components::TransformComponent>())
             {
             {
                 m_transformComponentId = transformComponent->GetId();
                 m_transformComponentId = transformComponent->GetId();
-                m_linearManipulator->AddEntityComponentIdPair(
-                    AZ::EntityComponentIdPair{ m_entityId, m_transformComponentId });
+                m_linearManipulator->AddEntityComponentIdPair(AZ::EntityComponentIdPair{ m_entityId, m_transformComponentId });
             }
             }
 
 
-            if (const auto* lockComponent = m_entity->FindComponent<Components::EditorLockComponent>())
+            if (const auto* lockComponent = m_entity->FindComponent<AzToolsFramework::Components::EditorLockComponent>())
             {
             {
                 m_lockComponentId = lockComponent->GetId();
                 m_lockComponentId = lockComponent->GetId();
-                m_linearManipulator->AddEntityComponentIdPair(
-                    AZ::EntityComponentIdPair{ m_entityId, m_lockComponentId });
+                m_linearManipulator->AddEntityComponentIdPair(AZ::EntityComponentIdPair{ m_entityId, m_lockComponentId });
             }
             }
 
 
-            if (const auto* visibilityComponent = m_entity->FindComponent<Components::EditorVisibilityComponent>())
+            if (const auto* visibilityComponent = m_entity->FindComponent<AzToolsFramework::Components::EditorVisibilityComponent>())
             {
             {
                 m_visibiltyComponentId = visibilityComponent->GetId();
                 m_visibiltyComponentId = visibilityComponent->GetId();
-                m_linearManipulator->AddEntityComponentIdPair(
-                    AZ::EntityComponentIdPair{ m_entityId, m_visibiltyComponentId });
+                m_linearManipulator->AddEntityComponentIdPair(AZ::EntityComponentIdPair{ m_entityId, m_visibiltyComponentId });
             }
             }
 
 
-            m_editorEntityComponentChangeDetector
-                = AZStd::make_unique<EditorEntityComponentChangeDetector>(m_entityId);
+            m_editorEntityComponentChangeDetector = AZStd::make_unique<EditorEntityComponentChangeDetector>(m_entityId);
         }
         }
 
 
-        void TearDownEditorFixtureImpl() override
+        void TearDown() override
         {
         {
+            m_editorEntityComponentChangeDetector.reset();
+            m_linearManipulator.reset();
+            m_entity.reset();
+            m_transformComponentDescriptor.reset();
+            m_lockComponentDescriptor.reset();
+            m_visibilityComponentDescriptor.reset();
+            m_serializeContext.reset();
+
+            AllocatorsTestFixture::TearDown();
         }
         }
 
 
-        AZStd::shared_ptr<LinearManipulator> m_linearManipulator;
-        AZ::Entity* m_entity = nullptr;
         AZ::EntityId m_entityId;
         AZ::EntityId m_entityId;
+        AZStd::unique_ptr<AZ::Entity> m_entity;
+        AZStd::shared_ptr<AzToolsFramework::LinearManipulator> m_linearManipulator;
         AZStd::unique_ptr<EditorEntityComponentChangeDetector> m_editorEntityComponentChangeDetector;
         AZStd::unique_ptr<EditorEntityComponentChangeDetector> m_editorEntityComponentChangeDetector;
+        AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
         AZ::ComponentId m_transformComponentId;
         AZ::ComponentId m_transformComponentId;
+        AZStd::unique_ptr<AZ::ComponentDescriptor> m_transformComponentDescriptor;
         AZ::ComponentId m_lockComponentId;
         AZ::ComponentId m_lockComponentId;
+        AZStd::unique_ptr<AZ::ComponentDescriptor> m_lockComponentDescriptor;
         AZ::ComponentId m_visibiltyComponentId;
         AZ::ComponentId m_visibiltyComponentId;
+        AZStd::unique_ptr<AZ::ComponentDescriptor> m_visibilityComponentDescriptor;
     };
     };
 
 
     TEST_F(ManipulatorCoreFixture, AllEntityIdComponentPairsRemovedFromManipulatorAfterRemoveEntity)
     TEST_F(ManipulatorCoreFixture, AllEntityIdComponentPairsRemovedFromManipulatorAfterRemoveEntity)
@@ -98,7 +127,7 @@ namespace UnitTest
 
 
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
         // When
         // When
-         m_linearManipulator->RemoveEntityComponentIdPair(entityLockComponentIdPair);
+        m_linearManipulator->RemoveEntityComponentIdPair(entityLockComponentIdPair);
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -118,11 +147,9 @@ namespace UnitTest
 
 
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
         // When
         // When
-        m_linearManipulator->OnLeftMouseDown(
-            AzToolsFramework::ViewportInteraction::MouseInteraction{}, 0.0f);
+        m_linearManipulator->OnLeftMouseDown(AzToolsFramework::ViewportInteraction::MouseInteraction{}, 0.0f);
 
 
-        m_linearManipulator->OnLeftMouseUp(
-            AzToolsFramework::ViewportInteraction::MouseInteraction{});
+        m_linearManipulator->OnLeftMouseUp(AzToolsFramework::ViewportInteraction::MouseInteraction{});
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -134,4 +161,57 @@ namespace UnitTest
         EXPECT_TRUE(m_editorEntityComponentChangeDetector->PropertyDisplayInvalidated());
         EXPECT_TRUE(m_editorEntityComponentChangeDetector->PropertyDisplayInvalidated());
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
     }
     }
+
+    using ManipulatorCoreInteractionFixture = DirectCallManipulatorViewportInteractionFixtureMixin<ManipulatorCoreFixture>;
+
+    TEST_F(ManipulatorCoreInteractionFixture, TestInteraction)
+    {
+        // setup viewport/camera
+        m_cameraState.m_viewportSize = AzFramework::ScreenSize(1280, 720);
+        AzFramework::SetCameraTransform(m_cameraState, AZ::Transform::CreateIdentity());
+
+        AzToolsFramework::ManipulatorViews views;
+        views.emplace_back(AzToolsFramework::CreateManipulatorViewSphere(
+            // note: use a small radius for the manipulator view/bounds to ensure precise mouse movement
+            AZ::Color{}, 0.001f,
+            [](const AzToolsFramework::ViewportInteraction::MouseInteraction&, bool, const AZ::Color&)
+            {
+                return AZ::Color{};
+            }));
+
+        m_linearManipulator->SetViews(views);
+        m_linearManipulator->Register(m_viewportManipulatorInteraction->GetManipulatorManagerId());
+
+        // the initial starting position of the manipulator
+        const auto initialTransformWorld = AZ::Transform::CreateTranslation(AZ::Vector3(0.0f, 10.0f, 0.0f));
+        // where the linear manipulator should end up
+        const auto finalTransformWorld = AZ::Transform::CreateTranslation(AZ::Vector3(2.0f, 10.0f, 0.0f));
+
+        // calculate the position in screen space of the initial position of the manipulator
+        const auto initialPositionScreen = AzFramework::WorldToScreen(initialTransformWorld.GetTranslation(), m_cameraState);
+        // calculate the position in screen space of the final position of the manipulator
+        const auto finalPositionScreen = AzFramework::WorldToScreen(finalTransformWorld.GetTranslation(), m_cameraState);
+
+        m_linearManipulator->SetSpace(AZ::Transform::CreateIdentity());
+        m_linearManipulator->SetLocalTransform(initialTransformWorld);
+        m_linearManipulator->InstallMouseMoveCallback(
+            [this](const AzToolsFramework::LinearManipulator::Action& action)
+            {
+                // move the manipulator
+                m_linearManipulator->SetLocalPosition(action.LocalPosition());
+            });
+
+        // press and drag the mouse (starting where the surface manipulator is)
+        m_actionDispatcher->CameraState(m_cameraState)
+            ->MousePosition(initialPositionScreen)
+            ->MouseLButtonDown()
+            ->MousePosition(finalPositionScreen)
+            ->MouseLButtonUp();
+
+        // read back the position of the manipulator now
+        const AZ::Transform finalManipulatorTransform = m_linearManipulator->GetLocalTransform();
+
+        // ensure final world positions match
+        EXPECT_THAT(finalManipulatorTransform, IsCloseTolerance(finalTransformWorld, 0.01f));
+    }
 } // namespace UnitTest
 } // namespace UnitTest

+ 4 - 1
Code/Legacy/CryCommon/ISystem.h

@@ -1053,7 +1053,10 @@ void* GetModuleShutdownISystemSymbol();
 //   Interface of the DLL.
 //   Interface of the DLL.
 extern "C"
 extern "C"
 {
 {
-    CRYSYSTEM_API ISystem* CreateSystemInterface(const SSystemInitParams& initParams);
+#if !defined(AZ_MONOLITHIC_BUILD)
+    CRYSYSTEM_API
+#endif
+    ISystem* CreateSystemInterface(const SSystemInitParams& initParams);
 }
 }
 
 
 // Description:
 // Description:

+ 4 - 1
Code/Legacy/CrySystem/DllMain.cpp

@@ -63,7 +63,10 @@ AZ_POP_DISABLE_WARNING
 
 
 extern "C"
 extern "C"
 {
 {
-CRYSYSTEM_API ISystem* CreateSystemInterface(const SSystemInitParams& startupParams)
+#if !defined(AZ_MONOLITHIC_BUILD)
+CRYSYSTEM_API
+#endif
+ISystem* CreateSystemInterface(const SSystemInitParams& startupParams)
 {
 {
     CSystem* pSystem = NULL;
     CSystem* pSystem = NULL;
 
 

+ 1 - 1
Code/Tools/AssetProcessor/native/tests/AssetProcessorMessagesTests.cpp

@@ -205,7 +205,7 @@ namespace AssetProcessorMessagesTests
             AZStd::atomic_bool finished = false;
             AZStd::atomic_bool finished = false;
             auto start = AZStd::chrono::monotonic_clock::now();
             auto start = AZStd::chrono::monotonic_clock::now();
 
 
-            auto thread = AZStd::thread([&finished, &func]()
+            auto thread = AZStd::thread({/*m_name =*/ "MessageTests"}, [&finished, &func]()
                 {
                 {
                     func();
                     func();
                     finished = true;
                     finished = true;

+ 4 - 0
Code/Tools/ProjectManager/Source/Application.cpp

@@ -22,6 +22,7 @@
 #include <QDir>
 #include <QDir>
 #include <QMessageBox>
 #include <QMessageBox>
 #include <QInputDialog>
 #include <QInputDialog>
+#include <QIcon>
 
 
 namespace O3DE::ProjectManager
 namespace O3DE::ProjectManager
 {
 {
@@ -69,6 +70,9 @@ namespace O3DE::ProjectManager
             AZ_Warning("ProjectManager", false, "Failed to init logging");
             AZ_Warning("ProjectManager", false, "Failed to init logging");
         }
         }
 
 
+        // Set window icon after QGuiApplication is created otherwise QPixmap for the icon fails to intialize
+        QApplication::setWindowIcon(QIcon(":/ProjectManager-Icon.ico"));
+
         m_pythonBindings = AZStd::make_unique<PythonBindings>(GetEngineRoot());
         m_pythonBindings = AZStd::make_unique<PythonBindings>(GetEngineRoot());
 
 
         if (!m_pythonBindings->PythonStarted())
         if (!m_pythonBindings->PythonStarted())

+ 1 - 0
Code/Tools/SerializeContextTools/Converter.cpp

@@ -577,6 +577,7 @@ namespace AZ
             AZ::IO::FixedMaxPath gemModuleSourcePath;
             AZ::IO::FixedMaxPath gemModuleSourcePath;
             AZ::ModuleManagerRequestBus::Broadcast([&gemModuleSourcePath, &gemName, gemModuleClassId = entity.m_moduleClassId](AZ::ModuleManagerRequests* request)
             AZ::ModuleManagerRequestBus::Broadcast([&gemModuleSourcePath, &gemName, gemModuleClassId = entity.m_moduleClassId](AZ::ModuleManagerRequests* request)
             {
             {
+                AZ_UNUSED(gemModuleClassId);
                 auto EnumerateGemModules = [&gemModuleSourcePath, &gemName, &gemModuleClassId](const AZ::ModuleData& moduleData) -> bool
                 auto EnumerateGemModules = [&gemModuleSourcePath, &gemName, &gemModuleClassId](const AZ::ModuleData& moduleData) -> bool
                 {
                 {
                     AZ::Module* moduleInst = moduleData.GetModule();
                     AZ::Module* moduleInst = moduleData.GetModule();

+ 0 - 24
Gems/Atom/Asset/Shader/Code/Source/Editor/AtomShaderCapabilitiesConfigFile.cpp

@@ -1,24 +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
- *
- */
-
-#include <AtomShaderCapabilitiesConfigFile.h>
-
-namespace AZ::ShaderBuilder::AtomShaderConfig
-{
-    void CapabilitiesConfigFile::Reflect(AZ::ReflectContext* context)
-    {
-        if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
-        {
-            serializeContext->Class<CapabilitiesConfigFile>()
-                ->Version(0)
-                ->Field("DescriptorCounts", &CapabilitiesConfigFile::m_descriptorCounts)
-                ->Field("MaxSpaces", &CapabilitiesConfigFile::m_maxSpaces)
-                ;
-        }
-    }
-}

+ 0 - 40
Gems/Atom/Asset/Shader/Code/Source/Editor/AtomShaderCapabilitiesConfigFile.h

@@ -1,40 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#pragma once
-
-#include <AzCore/Preprocessor/Enum.h>
-#include <AzCore/RTTI/ReflectContext.h>
-#include <AzCore/Serialization/SerializeContext.h>
-#include <AzCore/Serialization/DataPatch.h>
-#include <AzCore/std/string/string.h>
-#include <AzCore/std/containers/unordered_map.h>
-
-namespace AZ::ShaderBuilder::AtomShaderConfig
-{
-    AZ_ENUM(DescriptorSpace,
-            Sets,
-            Spaces,
-            Samplers,
-            Textures,
-            Buffers);
-
-    struct CapabilitiesConfigFile final
-    {
-        AZ_RTTI(CapabilitiesConfigFile, "{D3A25140-0F6C-4547-B4E4-0C7B7DE852E6}");
-
-        static void Reflect(AZ::ReflectContext* context);
-
-        //! string key: stringifed version of DescriptorSpace.
-        //! int value : -1 for unlimited, or by-specification minimal guaranteed capacity.
-        AZStd::unordered_map<AZStd::string, int> m_descriptorCounts;
-
-        //! The max number of spaces supported by the API.
-        int m_maxSpaces = -1;
-    };
-}

+ 0 - 136
Gems/Atom/Asset/Shader/Code/Source/Editor/AtomShaderConfig.cpp

@@ -1,136 +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
- *
- */
-
-#include "AtomShaderConfig.h"
-
-#include <AzCore/IO/SystemFile.h>
-#include <AzFramework/StringFunc/StringFunc.h>
-#include <AzFramework/Platform/PlatformDefaults.h>
-
-#include <AzCore/Serialization/Json/JsonUtils.h>
-
-
-namespace AZ
-{
-    namespace ShaderBuilder
-    {
-        namespace AtomShaderConfig
-        {
-            [[maybe_unused]] static constexpr char AtomShaderConfigName[] = "AtomShaderConfig";
-
-            bool MutateToFirstAbsoluteFolderThatExists(AZStd::string& relativeFolder, AZStd::vector<AZStd::string>& watchFolders)
-            {
-                if (!AzFramework::StringFunc::Path::IsRelative(relativeFolder.c_str()))
-                {
-                    return true;
-                }
-                for (AZStd::string folder : watchFolders)
-                {
-                    AzFramework::StringFunc::Path::Normalize(relativeFolder); // this is an external input, so defense is indicated.
-                    AzFramework::StringFunc::Path::Normalize(folder);
-                    AZStd::string absoluteOutput;
-                    AzFramework::StringFunc::Path::Join(folder.c_str(),
-                        relativeFolder.c_str(),
-                        absoluteOutput,
-                        true   /* join overlapping */,
-                        false  /* case insensitive */);
-                    if (AZ::IO::SystemFile::Exists(absoluteOutput.c_str()))
-                    {
-                        relativeFolder = std::move(absoluteOutput);
-                        return true;
-                    }
-                }
-                return false;
-            }
-
-            AZStd::string GetAssetConfigPath(const char* platformFolder)
-            {
-                bool success = false;
-                AZStd::vector<AZStd::string> scanFoldersVector;
-                AzToolsFramework::AssetSystemRequestBus::BroadcastResult(success,
-                    &AzToolsFramework::AssetSystemRequestBus::Events::GetScanFolders,
-                    scanFoldersVector);
-                AZ_Warning(AtomShaderConfigName, success, "Could not acquire a list of scan folders from the database.");
-                if (success)
-                {
-                    // platform specific shader build user configuration
-                    static constexpr char ConfigFileName[] = "AtomShaderCapabilities.json";
-                    static constexpr char ConfigPalFolder[] = "Config/Platform";
-                    AZStd::string assetRoot = ConfigPalFolder;
-                    if (MutateToFirstAbsoluteFolderThatExists(assetRoot, scanFoldersVector))
-                    {
-                        AZStd::string configFile;
-                        AzFramework::StringFunc::Path::Join(assetRoot.c_str(), platformFolder, configFile);
-                        AzFramework::StringFunc::Path::Join(configFile.c_str(), ConfigFileName, configFile);
-                        return configFile;
-                    }
-                }
-                return {};
-            }
-
-            CapabilitiesConfigFile GetMinDescriptorSetsFromConfigFile(const char* platformFolder)
-            {
-                CapabilitiesConfigFile limits;
-                AZStd::string configFilePath = GetAssetConfigPath(platformFolder);
-                if (IO::SystemFile::Exists(configFilePath.c_str()))
-                {
-                    Outcome loadResult = JsonSerializationUtils::LoadObjectFromFile(limits, configFilePath);
-                    AZ_Warning(AtomShaderConfigName, loadResult.IsSuccess(), "Failed to load capabilities settings from file [%s]", configFilePath.c_str());
-                }
-                return limits;
-            }
-
-            // @config argument comes from a platform abstracted folder
-            AZStd::string FormatSupplementaryArgumentsFromConfigAtomShader(const CapabilitiesConfigFile& config)
-            {
-                AZStd::string commandLineArguments;
-                // the map config.m_counts is the deserialized JSON data from the config file about hardware capabilities.
-                // the keys are unsanitized, therefore they could be anything in the wild.
-                // proceed if any element of the map's values has is a non -1:
-                if (AZStd::any_of(AZStd::begin(config.m_descriptorCounts), AZStd::end(config.m_descriptorCounts), [](auto pair) { return pair.second != -1; }))
-                {
-                    commandLineArguments = " --min-descriptors=";
-                    // for each key that indeed corresponds to an element of the DescriptorSpace enumerators, let's fetch it
-                    // and convert it to a string:
-                    AZStd::array<AZStd::string, AzEnumTraits<DescriptorSpace>::Count> valuesAsString = { {"-1","-1","-1","-1","-1"} };
-                    for (const auto& enumElement : DescriptorSpaceMembers)
-                    {
-                        auto iterator = config.m_descriptorCounts.find(enumElement.m_string);
-                        if (iterator != config.m_descriptorCounts.end())
-                        {
-                            valuesAsString[enumElement.m_value] = AZStd::to_string(iterator->second);
-                        }
-                    }
-                    AzFramework::StringFunc::Join(commandLineArguments,
-                        AZStd::begin(valuesAsString),
-                        AZStd::end(valuesAsString),
-                        ",");
-                }
-
-                if (config.m_maxSpaces != -1)
-                {
-                    commandLineArguments += AZStd::string::format(" --max-spaces=%d", config.m_maxSpaces);
-                }
-                return commandLineArguments;
-            }
-
-            void AddParametersFromConfigFile(AZStd::string& parameters, const AssetBuilderSDK::PlatformInfo& platform)
-            {
-                auto platformId = static_cast<AzFramework::PlatformId>(
-                    AzFramework::PlatformHelper::GetPlatformIndexFromName(platform.m_identifier.c_str()));
-                // The platforms available don't match the PAL folders. But the tags enrich it just enough to be able to rehabilitate android:
-                const char* palFolder = platform.HasTag("android") ? "Android"
-                    : AzFramework::PlatformIdToPalFolder(platformId);
-
-                CapabilitiesConfigFile minDescriptors = GetMinDescriptorSetsFromConfigFile(palFolder);
-                parameters += FormatSupplementaryArgumentsFromConfigAtomShader(minDescriptors);
-            }
-
-        } // namespace AtomShaderConfig
-    } // namespace ShaderBuilder
-} //namespace AZ

+ 0 - 32
Gems/Atom/Asset/Shader/Code/Source/Editor/AtomShaderConfig.h

@@ -1,32 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-#pragma once
-
-#include <AssetBuilderSDK/AssetBuilderSDK.h>
-
-#include "AtomShaderCapabilitiesConfigFile.h"
-
-namespace AZ
-{
-    namespace ShaderBuilder
-    {
-        namespace AtomShaderConfig
-        {
-            bool MutateToFirstAbsoluteFolderThatExists(AZStd::string& relativeFolder, AZStd::vector<AZStd::string>& watchFolders);
-
-            AZStd::string GetAssetConfigPath(const char* platformFolder);
-
-            CapabilitiesConfigFile GetMinDescriptorSetsFromConfigFile(const char* platformFolder);
-
-            // @config argument comes from a platform abstracted folder
-            AZStd::string FormatSupplementaryArgumentsFromConfigAtomShader(const CapabilitiesConfigFile& config);
-
-            void AddParametersFromConfigFile(AZStd::string& parameters, const AssetBuilderSDK::PlatformInfo& platform);
-        } // namespace AtomShaderConfig
-    } // namespace ShaderBuilder
-} //namespace AZ

+ 3 - 2
Gems/Atom/Asset/Shader/Code/Source/Editor/AzslCompiler.cpp

@@ -120,9 +120,10 @@ namespace AZ
 
 
         namespace SubProducts = ShaderBuilderUtility::AzslSubProducts;
         namespace SubProducts = ShaderBuilderUtility::AzslSubProducts;
 
 
-        Outcome<SubProducts::Paths> AzslCompiler::EmitFullData(const AZStd::string& parameters, const AZStd::string& outputFile /* = ""*/) const
+        Outcome<SubProducts::Paths> AzslCompiler::EmitFullData(const AZStd::vector<AZStd::string>& azslcArguments, const AZStd::string& outputFile /* = ""*/) const
         {
         {
-            bool success = Compile("--full " + parameters, outputFile);
+            const auto azslArgsStr = RHI::ShaderBuildArguments::ListAsString(azslcArguments);
+            bool success = Compile(azslArgsStr, outputFile);
             if (!success)
             if (!success)
             {
             {
                 return Failure();
                 return Failure();

+ 2 - 1
Gems/Atom/Asset/Shader/Code/Source/Editor/AzslCompiler.h

@@ -35,7 +35,8 @@ namespace AZ
             AzslCompiler(const AZStd::string& inputFilePath);
             AzslCompiler(const AZStd::string& inputFilePath);
 
 
             //! compile with --full and generate all .json files
             //! compile with --full and generate all .json files
-            Outcome<ShaderBuilderUtility::AzslSubProducts::Paths> EmitFullData(const AZStd::string& parameters, const AZStd::string& outputFile = "") const;
+            Outcome<ShaderBuilderUtility::AzslSubProducts::Paths> EmitFullData(const AZStd::vector<AZStd::string>& azslcArguments,
+                const AZStd::string& outputFile = "") const;
             //! compile to HLSL independently
             //! compile to HLSL independently
             bool EmitShader(AZ::IO::GenericStream& outputStream, const AZStd::string& extraCompilerParams) const;
             bool EmitShader(AZ::IO::GenericStream& outputStream, const AZStd::string& extraCompilerParams) const;
             //! compile with --ia independently and populate document @output
             //! compile with --ia independently and populate document @output

+ 3 - 5
Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp

@@ -13,6 +13,7 @@
 
 
 #include <Atom/RHI.Edit/ShaderPlatformInterface.h>
 #include <Atom/RHI.Edit/ShaderPlatformInterface.h>
 #include <Atom/RHI.Edit/Utils.h>
 #include <Atom/RHI.Edit/Utils.h>
+#include <Atom/RHI.Edit/ShaderBuildOptions.h>
 
 
 #include <Atom/RPI.Reflect/Asset/AssetHandler.h>
 #include <Atom/RPI.Reflect/Asset/AssetHandler.h>
 #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
 #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
@@ -26,8 +27,6 @@
 #include <AzCore/Settings/SettingsRegistry.h>
 #include <AzCore/Settings/SettingsRegistry.h>
 
 
 #include <CommonFiles/Preprocessor.h>
 #include <CommonFiles/Preprocessor.h>
-#include <CommonFiles/GlobalBuildOptions.h>
-#include <Editor/AtomShaderCapabilitiesConfigFile.h>
 
 
 namespace AZ
 namespace AZ
 {
 {
@@ -45,9 +44,8 @@ namespace AZ
 
 
             PreprocessorOptions::Reflect(context);
             PreprocessorOptions::Reflect(context);
             RHI::ShaderCompilerProfiling::Reflect(context);
             RHI::ShaderCompilerProfiling::Reflect(context);
-            AtomShaderConfig::CapabilitiesConfigFile::Reflect(context);
-            GlobalBuildOptions::Reflect(context);
-            RHI::ShaderCompilerArguments::Reflect(context);
+            RHI::ShaderBuildArguments::Reflect(context);
+            RHI::ShaderBuildOptions::Reflect(context);
         }
         }
 
 
         void AzslShaderBuilderSystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
         void AzslShaderBuilderSystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)

+ 0 - 81
Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/GlobalBuildOptions.cpp

@@ -1,81 +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
- *
- */
-
-#include <CommonFiles/GlobalBuildOptions.h>
-
-#include <AzFramework/StringFunc/StringFunc.h>
-#include <AzFramework/API/ApplicationAPI.h>
-
-#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
-
-#include <AzCore/Serialization/Json/JsonUtils.h>
-
-namespace AZ
-{
-    namespace ShaderBuilder
-    {
-        void GlobalBuildOptions::Reflect(AZ::ReflectContext* context)
-        {
-            if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
-            {
-                serializeContext->Class<GlobalBuildOptions>()
-                    ->Version(1)
-                    ->Field("PreprocessorOptions", &GlobalBuildOptions::m_preprocessorSettings)
-                    ->Field("ShaderCompilerArguments", &GlobalBuildOptions::m_compilerArguments);
-            }
-        }
-
-        namespace
-        {
-            // this function wraps BroadcastResult on GetSourceInfoBySourcePath
-            // return value: whether the search query succeeded or not
-            bool MutateToAbsolutePathIfFound(AZStd::string& relativePathToSearch)
-            {
-                bool found = false;
-                if (AzFramework::StringFunc::Path::IsRelative(relativePathToSearch.c_str()))
-                {
-                    AZ::Data::AssetInfo sourceInfo;
-                    AZStd::string watchFolder;
-                    AzToolsFramework::AssetSystemRequestBus::BroadcastResult(found,
-                                                                             &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath,
-                                                                             relativePathToSearch.c_str(),
-                                                                             sourceInfo,
-                                                                             watchFolder);
-                    if (found)
-                    {
-                        AZStd::string absoluteOutput;
-                        AzFramework::StringFunc::Path::Join(watchFolder.c_str(), relativePathToSearch.c_str(), absoluteOutput);
-                        relativePathToSearch = std::move(absoluteOutput);
-                    }
-                }
-                return found;
-            }
-        }
-
-        GlobalBuildOptions ReadBuildOptions(const char* builderName, const char* optionalIncludeFolder)
-        {
-            GlobalBuildOptions output;
-            // try to parse some config file for eventual additional options
-            AZStd::string globalBuildOption = "Config/shader_global_build_options.json";
-            bool found = MutateToAbsolutePathIfFound(globalBuildOption);
-            if (found)
-            {
-                // load settings in a temporary object to be able to do some input treatment, before merging with the final options
-                Outcome loadResult = AZ::JsonSerializationUtils::LoadObjectFromFile(output, globalBuildOption);
-                AZ_Warning(builderName, loadResult.IsSuccess(), "Failed to load shader-build environment include paths settings from file [%s]", globalBuildOption.c_str());
-                AZ_Warning(builderName, loadResult.IsSuccess(), "  Details: %s", loadResult.GetError().c_str());
-            }
-            else
-            {
-                AZ_TracePrintf(builderName, "config file [%s] not found.", globalBuildOption.c_str());
-            }
-            InitializePreprocessorOptions(output.m_preprocessorSettings, builderName, optionalIncludeFolder);
-            return output;
-        }
-    }
-}

+ 0 - 37
Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/GlobalBuildOptions.h

@@ -1,37 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#pragma once
-
-#include <CommonFiles/Preprocessor.h>
-#include <Atom/RHI.Edit/ShaderCompilerArguments.h>
-
-namespace AZ
-{
-    namespace ShaderBuilder
-    {
-        //! represents the json config file contents of project-wide shader_global_build_options's file.
-        struct GlobalBuildOptions final
-        {
-            AZ_RTTI(GlobalBuildOptions, "{F7F1247D-A417-43E1-9B52-84DD226A9E1A}");
-
-            static void Reflect(AZ::ReflectContext* context);
-
-            //! include paths and defines
-            PreprocessorOptions m_preprocessorSettings;
-
-            //! command line arguments related to warnings, optimizations, matrices order and others.
-            RHI::ShaderCompilerArguments m_compilerArguments;
-        };
-
-        //! Reads the global options used when compiling shaders. The options are defined in <GameProject>/Config/shader_global_build_options.json
-        //! @param builderName: A string with the name of the builder calling this API. Used for trace debugging.
-        //! @param optionalIncludeFolder: An additional directory to add to the list of include folders for the C-preprocessor.
-        GlobalBuildOptions ReadBuildOptions(const char* builderName, const char* optionalIncludeFolder = nullptr);
-    }
-}

+ 130 - 57
Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/Preprocessor.cpp

@@ -196,8 +196,76 @@ namespace AZ
         // McppBinder ends
         // McppBinder ends
         ///////////////////////////////////////////////////////////////////////
         ///////////////////////////////////////////////////////////////////////
 
 
-        bool PreprocessFile(const AZStd::string& fullPath, PreprocessorData& outputData, const PreprocessorOptions& options
-            , bool collectDiagnostics, bool preprocessIncludedFiles)
+        // @returns true if a string starts with "-I", which is how the C-preprocessor understands include paths.  Examples:
+        // "-Isome/dir" (true)
+        // "-I/full/path/" (true)
+        // "-DMacro" (false)
+        static bool IsArgumentAnIncludeDirectory(const AZStd::string& argument)
+        {
+            if (argument.size() < 2)
+            {
+                return false;
+            }
+            return (argument[0] == '-') && (argument[1] == 'I');
+        }
+
+        // Transforms relative include path arguments. If the argument is not an include path the same argument is returned.
+        // @param argument A single command line arguments for the C-preprocessor.
+        // @param rootDir The root directory that will be joined with the relative path.
+        // @returns A copy of @argument if it is NOT an include path argument. If it is a include path then:
+        //      - If the directory is an absolute path:
+        //          - and it exists, a copy of @argument is returned.
+        //          - and it doesn't exist, an empty string is returned.
+        //      - If the directory is a relative path, it is transformed into an absolute directory by joining @rootDir with the relative path.
+        //          - If the directory exists a string as an include path argument is returned.
+        //          - If the directory doesn't exist and empty string is returned.
+        static AZStd::string NormalizeIncludePathArgument(const AZStd::string& argument, const AZ::IO::FixedMaxPath& rootDir)
+        {
+            if (!IsArgumentAnIncludeDirectory(argument))
+            {
+                return argument;
+            }
+
+            AZStd::string includeDirectory = argument.substr(2);
+            // Trim spaces at both ends.
+            AZ::StringFunc::TrimWhiteSpace(includeDirectory, true, true);
+            if (AZ::StringFunc::Path::IsRelative(includeDirectory.c_str()))
+            {
+                AZ::IO::FixedMaxPath absoluteDirectory = rootDir / includeDirectory;
+                if (!AZ::IO::SystemFile::Exists(absoluteDirectory.c_str()))
+                {
+                    AZ_Error("Preprocessor", false, "The directory argument: %s, doesn't exist as an absolute path: %s. Skipping...",
+                        argument.c_str(), absoluteDirectory.c_str());
+                    return {};
+                }
+                return AZStd::string::format("-I%s", absoluteDirectory.c_str());
+            }
+
+            // It's an absolute directory. Does it exist?
+            if (!AZ::IO::SystemFile::Exists(includeDirectory.c_str()))
+            {
+                AZ_Error("Preprocessor", false, "The absolute directory argument: %s, doesn't exist as an absolute path: %s. Skipping...",
+                    argument.c_str(), includeDirectory.c_str());
+                return {};
+            }
+
+            // The aboslute directory exists, return the argument as is.
+            return argument;
+        }
+
+        AZStd::vector<AZStd::string> AppendIncludePathsToArgumentList(const AZStd::vector<AZStd::string>& preprocessorArguments, AZStd::vector<AZStd::string> includePaths)
+        {
+            auto newList = preprocessorArguments;
+            for (const AZStd::string& folder : includePaths)
+            {
+                newList.push_back(AZStd::string::format("-I%s", folder.c_str()));
+            }
+            return newList;
+        }
+
+        bool PreprocessFile(const AZStd::string& fullPath, PreprocessorData& outputData
+            , const AZStd::vector<AZStd::string>& preprocessorArguments
+            , bool collectDiagnostics)
         {
         {
             // create a wrapper instance
             // create a wrapper instance
             McppBinder mcpp(outputData, collectDiagnostics);
             McppBinder mcpp(outputData, collectDiagnostics);
@@ -205,36 +273,40 @@ namespace AZ
             // create the argc/argv
             // create the argc/argv
             const char* processName = "builder";
             const char* processName = "builder";
             const char* inputPath = fullPath.c_str();
             const char* inputPath = fullPath.c_str();
-            // let's create the equivalent of that expression but in dynamic form:
-            //const char* argv[] = { processName, szInPath, "-C", "-+", "-D macro1"..., "-I path"..., NULL };
-            AZStd::vector< const char* > argv;
-            argv.reserve(5 + options.m_predefinedMacros.size() * 2 + options.m_projectIncludePaths.size() * 2);
+
+            AZStd::vector< AZStd::string > argv;
+            argv.reserve(2 /*processName + inputPath*/ + preprocessorArguments.size());
             argv.push_back(processName);
             argv.push_back(processName);
             argv.push_back(inputPath);
             argv.push_back(inputPath);
-            if (!preprocessIncludedFiles)
-            {
-                argv.push_back("-z");
-            }
-            argv.push_back("-C");  // conserve comments
-            argv.push_back("-+");  // C++ mode
-            for (const AZStd::string& macroDef : options.m_predefinedMacros)
-            {
-                argv.push_back("-D");
-                argv.push_back(&macroDef[0]); // pointers to the string data will be stable for the duration of the call
-            }
-            for (const AZStd::string& folder : options.m_projectIncludePaths)
+
+            // The include directories in C-preprocessor arguments, when relative, are relative
+            // to the current project.
+            const AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
+            for (const auto& cppArgument : preprocessorArguments)
             {
             {
-                argv.push_back("-I");
-                argv.push_back(&folder[0]);  // pointers to the string data will be stable for the duration of the call
+                auto normalizedArgument = NormalizeIncludePathArgument(cppArgument, projectPath);
+                if (normalizedArgument.empty())
+                {
+                    // An empty string means there was an error. The proper message is produced by NormalizePreprocessorIncludePath().
+                    return false;
+                }
+                argv.emplace_back(AZStd::move(normalizedArgument));
             }
             }
-            argv.push_back(nullptr); // usual argv terminator
+
             // output the command line:
             // output the command line:
             AZStd::string stringifiedCommandLine;
             AZStd::string stringifiedCommandLine;
-            AZ::StringFunc::Join(stringifiedCommandLine, argv.begin(), argv.end() - 1, " ");
+            AZ::StringFunc::Join(stringifiedCommandLine, argv.begin(), argv.end(), " ");
             AZ_TracePrintf("Preprocessor", "%s", stringifiedCommandLine.c_str());
             AZ_TracePrintf("Preprocessor", "%s", stringifiedCommandLine.c_str());
             // when we don't specify an -o outfile, mcpp uses stdout.
             // when we don't specify an -o outfile, mcpp uses stdout.
-            // the trick is that since we hijacked putc & puts, stdout will not be written. 
-            bool result = mcpp.StartPreprocessWithCommandLine(aznumeric_cast<int>(argv.size()) - 1, argv.data());
+            // the trick is that since we hijacked putc & puts, stdout will not be written.
+            AZStd::vector< const char* > argsOfCstr;
+            argsOfCstr.reserve(argv.size() + 1);
+            for (const auto& arg : argv)
+            {
+                argsOfCstr.push_back(&arg[0]);
+            }
+            argsOfCstr.push_back(nullptr); // usual argv terminator
+            bool result = mcpp.StartPreprocessWithCommandLine(aznumeric_cast<int>(argsOfCstr.size()) - 1, argsOfCstr.data());
             return result;
             return result;
         }
         }
 
 
@@ -280,56 +352,55 @@ namespace AZ
             }
             }
         }
         }
 
 
-        // populate options with scan folders and contents of parsing shader_global_build_options.json
-        void InitializePreprocessorOptions(
-            PreprocessorOptions& options, [[maybe_unused]] const char* builderName, const char* optionalIncludeFolder)
+        AZStd::vector<AZStd::string> BuildListOfIncludeDirectories([[maybe_unused]] const char* builderName, const char* optionalIncludeFolder)
         {
         {
             AZ_TraceContext("Init include-paths lookup options", "preprocessor");
             AZ_TraceContext("Init include-paths lookup options", "preprocessor");
 
 
-            // get the scan folders of the projects:
-            bool success = true;
-            AZStd::vector<AZStd::string> scanFoldersVector;
-            AzToolsFramework::AssetSystemRequestBus::BroadcastResult(success,
-                &AzToolsFramework::AssetSystemRequestBus::Events::GetScanFolders,
-                scanFoldersVector);
-            AZ_Warning(builderName, success, "Preprocessor option: Could not acquire a list of scan folders from the database.");
+            AZStd::vector<AZStd::string> includePaths;
 
 
-            // Add the project path to list of include paths
-            AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
-            auto FindPath = [](AZ::IO::PathView searchPath)
+            if (optionalIncludeFolder)
+            {
+                if (AZ::IO::SystemFile::Exists(optionalIncludeFolder))
+                {
+                    includePaths.emplace_back(AZStd::move(AZ::IO::Path(optionalIncludeFolder).LexicallyNormal().Native()));
+                }
+            }
+
+            auto PathCompare = [](AZ::IO::PathView searchPath)
             {
             {
                 return [searchPath](AZStd::string_view includePathView)
                 return [searchPath](AZStd::string_view includePathView)
                 {
                 {
                     return searchPath == AZ::IO::PathView(includePathView);
                     return searchPath == AZ::IO::PathView(includePathView);
                 };
                 };
             };
             };
-            if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(projectPath));
-                it == options.m_projectIncludePaths.end())
-            {
-                options.m_projectIncludePaths.emplace_back(projectPath.c_str(), projectPath.Native().size());
-            }
-            if (optionalIncludeFolder)
+
+            // Add the project path to list of include paths
+            AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
+            if (auto it = AZStd::find_if(includePaths.begin(), includePaths.end(), PathCompare(projectPath));
+                it == includePaths.end())
             {
             {
-                if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(optionalIncludeFolder));
-                    it == options.m_projectIncludePaths.end())
-                {
-                    if (AZ::IO::SystemFile::Exists(optionalIncludeFolder))
-                    {
-                        options.m_projectIncludePaths.emplace_back(AZStd::move(AZ::IO::Path(optionalIncludeFolder).LexicallyNormal().Native()));
-                    }
-                }
+                includePaths.emplace_back(projectPath.c_str(), projectPath.Native().size());
             }
             }
+
+            // get the scan folders of the projects:
+            bool success = true;
+            AZStd::vector<AZStd::string> scanFoldersVector;
+            AzToolsFramework::AssetSystemRequestBus::BroadcastResult(success,
+                &AzToolsFramework::AssetSystemRequestBus::Events::GetScanFolders,
+                scanFoldersVector);
+            AZ_Warning(builderName, success, "Preprocessor option: Could not acquire a list of scan folders from the database.");
+
             // but while we transfer to the set, we're going to keep only folders where +/ShaderLib exists
             // but while we transfer to the set, we're going to keep only folders where +/ShaderLib exists
             for (AZ::IO::Path shaderScanFolder : scanFoldersVector)
             for (AZ::IO::Path shaderScanFolder : scanFoldersVector)
             {
             {
                 shaderScanFolder /= "ShaderLib";
                 shaderScanFolder /= "ShaderLib";
-                if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(shaderScanFolder));
-                    it == options.m_projectIncludePaths.end())
+                if (auto it = AZStd::find_if(includePaths.begin(), includePaths.end(), PathCompare(shaderScanFolder));
+                    it == includePaths.end())
                 {
                 {
                     // the folders constructed this fashion constitute the base of automatic include search paths
                     // the folders constructed this fashion constitute the base of automatic include search paths
                     if (AZ::IO::SystemFile::Exists(shaderScanFolder.c_str()))
                     if (AZ::IO::SystemFile::Exists(shaderScanFolder.c_str()))
                     {
                     {
-                        options.m_projectIncludePaths.emplace_back(AZStd::move(shaderScanFolder.LexicallyNormal().Native()));
+                        includePaths.emplace_back(AZStd::move(shaderScanFolder.LexicallyNormal().Native()));
                     }
                     }
                 }
                 }
             }
             }
@@ -337,14 +408,16 @@ namespace AZ
             // finally the <engineroot>/Gems fallback
             // finally the <engineroot>/Gems fallback
             AZ::IO::Path engineGemsFolder(AZStd::string_view{ AZ::Utils::GetEnginePath() });
             AZ::IO::Path engineGemsFolder(AZStd::string_view{ AZ::Utils::GetEnginePath() });
             engineGemsFolder /= "Gems";
             engineGemsFolder /= "Gems";
-            if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(engineGemsFolder));
-                it == options.m_projectIncludePaths.end())
+            if (auto it = AZStd::find_if(includePaths.begin(), includePaths.end(), PathCompare(engineGemsFolder));
+                it == includePaths.end())
             {
             {
                 if (AZ::IO::SystemFile::Exists(engineGemsFolder.c_str()))
                 if (AZ::IO::SystemFile::Exists(engineGemsFolder.c_str()))
                 {
                 {
-                    options.m_projectIncludePaths.emplace_back(AZStd::move(engineGemsFolder.Native()));
+                    includePaths.emplace_back(AZStd::move(engineGemsFolder.Native()));
                 }
                 }
             }
             }
+
+            return includePaths;
         }
         }
 
 
     } // namespace ShaderBuilder
     } // namespace ShaderBuilder

+ 10 - 20
Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/Preprocessor.h

@@ -67,38 +67,28 @@ namespace AZ
             //!   or "output diagnostics to std.err" or "enable digraphs/trigraphs"...
             //!   or "output diagnostics to std.err" or "enable digraphs/trigraphs"...
         };
         };
 
 
-        //! You can use this canonicalized way to initialize preprocessor options
-        //! It will populate your option with a default base of include folders given by the Asset Processor scan folders.
-        //! This is going to look for a Config/shader_global_build_options.json in one of the scan folders
-        //!  (that file can specify additional include files and preprocessor macros).
-        //! @param options: Outout parameter, will contain the preprocessor options.
         //! @param builderName: Used for debugging.
         //! @param builderName: Used for debugging.
-        //! @param optionalIncludeFolder: If not null, will be added to the list of include folders for the c-preprocessor in @options.
-        void InitializePreprocessorOptions(PreprocessorOptions& options, const char* builderName, const char* optionalIncludeFolder = nullptr);
+        //! @param optionalIncludeFolder: If not null, will be added at the beginning of the returned list of include folders.
+        //! @returns A list of fully qualified directory paths that will be given to the c-preprocessor to find the included files in .azsl files.
+        AZStd::vector<AZStd::string> BuildListOfIncludeDirectories(const char* builderName, const char* optionalIncludeFolder = nullptr);
+
+        // @returns A new list of command arguments for the C-Preprocessor where each string in @includePaths
+        //     is appended to @preprocessorArguments as "-I<path>".
+        AZStd::vector<AZStd::string> AppendIncludePathsToArgumentList(const AZStd::vector<AZStd::string>& preprocessorArguments, AZStd::vector<AZStd::string> includePaths);
 
 
         /**
         /**
         * Runs the preprocessor on the given source file path, and stores results in outputData.
         * Runs the preprocessor on the given source file path, and stores results in outputData.
         * @param fullPath   The file to preprocess
         * @param fullPath   The file to preprocess
         * @param outputData Collects data from the preprocessor. This will be filled out as much as possible, even if preprocessing fails.
         * @param outputData Collects data from the preprocessor. This will be filled out as much as possible, even if preprocessing fails.
-        * @param options    Control of macros to define and paths to solve includes
+        * @param preprocessorArguments The command line arguments for the C-preprocessor.
         * @param collectDiagnostics If true, warnings and errors will be collected in outputData.diagnostics instead of using AZ_Warning and AZ_Error.
         * @param collectDiagnostics If true, warnings and errors will be collected in outputData.diagnostics instead of using AZ_Warning and AZ_Error.
-        * @param preprocessIncludedFiles  By default MCPP follows the chain of included files
-        *        and extracts the content of each file and dumps it in the output.
-        *        Setting this flag to false will prevent mcpp from preprocessing the included files,
-        *        so the produced content will come only from the file given as input to MCPP.
-        *        Setting to false is handy, for example, for the SrgLayoutBuilder from creating SRGs from included files.
-        *        REMARK: You can make the argument of why not simply leave the @m_projectIncludePaths empty?
-        *        It will cause MCPP to error because it won't find the included files. So, in reality the chain
-        *        of included files is validated, but their content won't make it into the output.
-        *        A change is required in azslc so it skips #include lines. SEE: [ATOM-5302]
         * @return false if the preprocessor failed
         * @return false if the preprocessor failed
         */
         */
         bool PreprocessFile(
         bool PreprocessFile(
             const AZStd::string& fullPath,
             const AZStd::string& fullPath,
             PreprocessorData& outputData,
             PreprocessorData& outputData,
-            const PreprocessorOptions& options,
-            bool collectDiagnostics = false,
-            bool preprocessIncludedFiles = true);
+            const AZStd::vector<AZStd::string>& preprocessorArguments,
+            bool collectDiagnostics = false);
 
 
         //! Replace all ocurrences of #line "whatever" by #line "whatwewant"
         //! Replace all ocurrences of #line "whatever" by #line "whatwewant"
         void MutateLineDirectivesFileOrigin(
         void MutateLineDirectivesFileOrigin(

+ 28 - 42
Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp

@@ -9,7 +9,6 @@
 #include "ShaderAssetBuilder.h"
 #include "ShaderAssetBuilder.h"
 
 
 #include <CommonFiles/Preprocessor.h>
 #include <CommonFiles/Preprocessor.h>
-#include <CommonFiles/GlobalBuildOptions.h>
 
 
 #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
 #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
 #include <Atom/RPI.Reflect/Shader/ShaderAssetCreator.h>
 #include <Atom/RPI.Reflect/Shader/ShaderAssetCreator.h>
@@ -50,7 +49,7 @@
 #include "ShaderVariantAssetBuilder.h"
 #include "ShaderVariantAssetBuilder.h"
 #include "ShaderBuilderUtility.h"
 #include "ShaderBuilderUtility.h"
 #include "ShaderPlatformInterfaceRequest.h"
 #include "ShaderPlatformInterfaceRequest.h"
-#include "AtomShaderConfig.h"
+#include "ShaderBuildArgumentsManager.h"
 
 
 #include <AssetBuilderSDK/AssetBuilderSDK.h>
 #include <AssetBuilderSDK/AssetBuilderSDK.h>
 #include <AssetBuilderSDK/SerializationDependencies.h>
 #include <AssetBuilderSDK/SerializationDependencies.h>
@@ -196,10 +195,10 @@ namespace AZ
                 // report the failure.
                 // report the failure.
             }
             }
 
 
-            GlobalBuildOptions buildOptions = ReadBuildOptions(ShaderAssetBuilderName);
+            auto projectIncludePaths = BuildListOfIncludeDirectories(ShaderAssetBuilderName);
 
 
             AZStd::unordered_set<AZStd::string> includedFiles;
             AZStd::unordered_set<AZStd::string> includedFiles;
-            GetListOfIncludedFiles(azslFullPath, buildOptions.m_preprocessorSettings.m_projectIncludePaths, includedFilesParser, includedFiles);
+            GetListOfIncludedFiles(azslFullPath, projectIncludePaths, includedFilesParser, includedFiles);
             for (auto includePath : includedFiles)
             for (auto includePath : includedFiles)
             {
             {
                 AssetBuilderSDK::SourceFileDependency includeFileDependency;
                 AssetBuilderSDK::SourceFileDependency includeFileDependency;
@@ -340,7 +339,15 @@ namespace AZ
             // The directory where the Azsl file was found must be added to the list of include paths
             // The directory where the Azsl file was found must be added to the list of include paths
             AZStd::string azslFolderPath;
             AZStd::string azslFolderPath;
             AzFramework::StringFunc::Path::GetFolderPath(azslFullPath.c_str(), azslFolderPath);
             AzFramework::StringFunc::Path::GetFolderPath(azslFullPath.c_str(), azslFolderPath);
-            GlobalBuildOptions buildOptions = ReadBuildOptions(ShaderAssetBuilderName, azslFolderPath.c_str());
+            auto projectIncludePaths = BuildListOfIncludeDirectories(ShaderAssetBuilderName, azslFolderPath.c_str());
+
+            ShaderBuildArgumentsManager buildArgsManager;
+            buildArgsManager.Init();
+            // A job always runs on behalf of an Asset Processing platform (aka PlatformInfo).
+            // Let's merge the shader build arguments of the current PlatformInfo with the global
+            // set of arguments.
+            const auto platformName = ShaderBuilderUtility::GetPlatformNameFromPlatformInfo(request.m_platformInfo);
+            buildArgsManager.PushArgumentScope(platformName);
 
 
             // Request the list of valid shader platform interfaces for the target platform.
             // Request the list of valid shader platform interfaces for the target platform.
             AZStd::vector<RHI::ShaderPlatformInterface*> platformInterfaces = ShaderBuilderUtility::DiscoverEnabledShaderPlatformInterfaces(
             AZStd::vector<RHI::ShaderPlatformInterface*> platformInterfaces = ShaderBuilderUtility::DiscoverEnabledShaderPlatformInterfaces(
@@ -410,17 +417,14 @@ namespace AZ
             // Remark: In general, the work done by the ShaderVariantAssetBuilder is similar, but it will start from the HLSL file created; in step 2, mentioned above; by this builder,
             // Remark: In general, the work done by the ShaderVariantAssetBuilder is similar, but it will start from the HLSL file created; in step 2, mentioned above; by this builder,
             // for each supervariant. 
             // for each supervariant. 
 
 
-            // At this moment We have global build options that should be merged with the build options that are common
-            // to all the supervariants of this shader.
-            buildOptions.m_compilerArguments.Merge(shaderSourceData.m_compiler);
-            buildOptions.m_preprocessorSettings.m_predefinedMacros.insert(
-                buildOptions.m_preprocessorSettings.m_predefinedMacros.end(),
-                shaderSourceData.m_definitions.begin(), shaderSourceData.m_definitions.end());
-
             for (RHI::ShaderPlatformInterface* shaderPlatformInterface : platformInterfaces)
             for (RHI::ShaderPlatformInterface* shaderPlatformInterface : platformInterfaces)
             {
             {
                 AZStd::string apiName(shaderPlatformInterface->GetAPIName().GetCStr());
                 AZStd::string apiName(shaderPlatformInterface->GetAPIName().GetCStr());
                 AZ_TraceContext("Platform API", apiName);
                 AZ_TraceContext("Platform API", apiName);
+
+                buildArgsManager.PushArgumentScope(apiName);
+                buildArgsManager.PushArgumentScope(shaderSourceData.m_removeBuildArguments, shaderSourceData.m_addBuildArguments, shaderSourceData.m_definitions);
+
                 // Signal the begin of shader data for an RHI API.
                 // Signal the begin of shader data for an RHI API.
                 shaderAssetCreator.BeginAPI(shaderPlatformInterface->GetAPIType());
                 shaderAssetCreator.BeginAPI(shaderPlatformInterface->GetAPIType());
 
 
@@ -440,21 +444,12 @@ namespace AZ
                     return;
                     return;
                 }
                 }
 
 
-                // Cache common AZSLC invokation arguments related with the current RHI Backend.
-                // Each supervariant can, optionally, remove or add more arguments for AZSLc.
-                AZStd::string commonAzslcCompilerParameters =
-                    shaderPlatformInterface->GetAzslCompilerParameters(buildOptions.m_compilerArguments);
-                commonAzslcCompilerParameters += " ";
-                commonAzslcCompilerParameters +=
-                    shaderPlatformInterface->GetAzslCompilerWarningParameters(buildOptions.m_compilerArguments);
-                AtomShaderConfig::AddParametersFromConfigFile(commonAzslcCompilerParameters, request.m_platformInfo);
-
                 // The register number only makes sense if the platform uses "spaces",
                 // The register number only makes sense if the platform uses "spaces",
                 // since the register Id of the resource will not change even if the pipeline layout changes.
                 // since the register Id of the resource will not change even if the pipeline layout changes.
                 // We can pass in a default ShaderCompilerArguments because all we care about is whether the shaderPlatformInterface
                 // We can pass in a default ShaderCompilerArguments because all we care about is whether the shaderPlatformInterface
                 // appends the "--use-spaces" flag.
                 // appends the "--use-spaces" flag.
-                const bool platformUsesRegisterSpaces =
-                    (AzFramework::StringFunc::Find(commonAzslcCompilerParameters, "--use-spaces") != AZStd::string::npos);
+                const auto& azslcArguments = buildArgsManager.GetCurrentArguments().m_azslcArguments;
+                const bool platformUsesRegisterSpaces = RHI::ShaderBuildArguments::HasArgument(azslcArguments, "--use-spaces");
 
 
                 uint32_t supervariantIndex = 0;
                 uint32_t supervariantIndex = 0;
                 for (const auto& supervariantInfo : supervariantList)
                 for (const auto& supervariantInfo : supervariantList)
@@ -466,21 +461,14 @@ namespace AZ
                         return;
                         return;
                     }
                     }
 
 
+                    buildArgsManager.PushArgumentScope(supervariantInfo.m_removeBuildArguments, supervariantInfo.m_addBuildArguments, supervariantInfo.m_definitions);
+
                     shaderAssetCreator.BeginSupervariant(supervariantInfo.m_name);
                     shaderAssetCreator.BeginSupervariant(supervariantInfo.m_name);
 
 
-                    // Let's combine the global macro definitions, with the macro definitions particular to this
-                    // supervariant. Two steps:
-                    // 1- Supervariants can specify which macros to remove from the global definitions.
-                    AZStd::vector<AZStd::string> macroDefinitionNamesToRemove = supervariantInfo.GetCombinedListOfMacroDefinitionNamesToRemove();
-                    PreprocessorOptions preprocessorOptions = buildOptions.m_preprocessorSettings;
-                    preprocessorOptions.RemovePredefinedMacros(macroDefinitionNamesToRemove);
-                    // 2- Supervariants can specify which macros to add.
-                    AZStd::vector<AZStd::string> macroDefinitionsToAdd = supervariantInfo.GetMacroDefinitionsToAdd();
-                    preprocessorOptions.m_predefinedMacros.insert(
-                        preprocessorOptions.m_predefinedMacros.end(), macroDefinitionsToAdd.begin(), macroDefinitionsToAdd.end());
                     // Run the preprocessor.
                     // Run the preprocessor.
                     PreprocessorData output;
                     PreprocessorData output;
-                    const bool preprocessorSuccess = PreprocessFile(prependedAzslFilePath, output, preprocessorOptions, true, true);
+                    auto preprocessorArguments = AppendIncludePathsToArgumentList(buildArgsManager.GetCurrentArguments().m_preprocessorArguments, projectIncludePaths);
+                    const bool preprocessorSuccess = PreprocessFile(prependedAzslFilePath, output, preprocessorArguments,  true);
                     RHI::ReportMessages(ShaderAssetBuilderName, output.diagnostics, !preprocessorSuccess);
                     RHI::ReportMessages(ShaderAssetBuilderName, output.diagnostics, !preprocessorSuccess);
                     // Dump the preprocessed string as a flat AZSL file with extension .azslin, which will be given to AZSLc to generate the HLSL file.
                     // Dump the preprocessed string as a flat AZSL file with extension .azslin, which will be given to AZSLc to generate the HLSL file.
                     AZStd::string superVariantAzslinStemName = shaderFileName;
                     AZStd::string superVariantAzslinStemName = shaderFileName;
@@ -498,15 +486,11 @@ namespace AZ
                     }
                     }
                     AZ_TracePrintf(ShaderAssetBuilderName, "Preprocessed AZSL File: %s \n", prependedAzslFilePath.c_str());
                     AZ_TracePrintf(ShaderAssetBuilderName, "Preprocessed AZSL File: %s \n", prependedAzslFilePath.c_str());
 
 
-                    // Before transpiling the flat-AZSL(.azslin) file into HLSL it is necessary
-                    // to setup the AZSLc arguments as required by the current supervariant.
-                    AZStd::string azslcCompilerParameters = supervariantInfo.GetCustomizedArgumentsForAzslc(commonAzslcCompilerParameters);
-
                     // Ready to transpile the azslin file into HLSL.
                     // Ready to transpile the azslin file into HLSL.
                     ShaderBuilder::AzslCompiler azslc(azslinFullPath);
                     ShaderBuilder::AzslCompiler azslc(azslinFullPath);
                     AZStd::string hlslFullPath = AZStd::string::format("%s_%s.hlsl", superVariantAzslinStemName.c_str(), apiName.c_str());
                     AZStd::string hlslFullPath = AZStd::string::format("%s_%s.hlsl", superVariantAzslinStemName.c_str(), apiName.c_str());
                     AzFramework::StringFunc::Path::Join(request.m_tempDirPath.c_str(), hlslFullPath.c_str(), hlslFullPath, true);
                     AzFramework::StringFunc::Path::Join(request.m_tempDirPath.c_str(), hlslFullPath.c_str(), hlslFullPath, true);
-                    auto emitFullOutcome = azslc.EmitFullData(azslcCompilerParameters, hlslFullPath);
+                    auto emitFullOutcome = azslc.EmitFullData(buildArgsManager.GetCurrentArguments().m_azslcArguments, hlslFullPath);
                     if (!emitFullOutcome.IsSuccess())
                     if (!emitFullOutcome.IsSuccess())
                     {
                     {
                         response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
                         response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
@@ -608,7 +592,7 @@ namespace AZ
 
 
                     RHI::Ptr<RHI::PipelineLayoutDescriptor> pipelineLayoutDescriptor =
                     RHI::Ptr<RHI::PipelineLayoutDescriptor> pipelineLayoutDescriptor =
                         ShaderBuilderUtility::BuildPipelineLayoutDescriptorForApi(
                         ShaderBuilderUtility::BuildPipelineLayoutDescriptorForApi(
-                            ShaderAssetBuilderName, srgLayoutList, shaderEntryPoints, buildOptions.m_compilerArguments, rootConstantData,
+                            ShaderAssetBuilderName, srgLayoutList, shaderEntryPoints, buildArgsManager.GetCurrentArguments(), rootConstantData,
                             shaderPlatformInterface, bindingDependencies);
                             shaderPlatformInterface, bindingDependencies);
                     if (!pipelineLayoutDescriptor)
                     if (!pipelineLayoutDescriptor)
                     {
                     {
@@ -674,7 +658,7 @@ namespace AZ
                     ShaderVariantCreationContext shaderVariantCreationContext = {
                     ShaderVariantCreationContext shaderVariantCreationContext = {
                         *shaderPlatformInterface,
                         *shaderPlatformInterface,
                         request.m_platformInfo,
                         request.m_platformInfo,
-                        buildOptions.m_compilerArguments,
+                        buildArgsManager.GetCurrentArguments(),
                         request.m_tempDirPath,
                         request.m_tempDirPath,
                         shaderAssetBuildTimestamp,
                         shaderAssetBuildTimestamp,
                         shaderSourceData,
                         shaderSourceData,
@@ -734,11 +718,13 @@ namespace AZ
                         }
                         }
                     }
                     }
 
 
-
+                    buildArgsManager.PopArgumentScope();
                     supervariantIndex++;
                     supervariantIndex++;
 
 
                 } // end for the supervariant
                 } // end for the supervariant
 
 
+                buildArgsManager.PopArgumentScope(); // Pop  .shader arguments
+                buildArgsManager.PopArgumentScope(); // Pop rhi api arguments.
                 shaderAssetCreator.EndAPI();
                 shaderAssetCreator.EndAPI();
 
 
             } // end for all ShaderPlatformInterfaces
             } // end for all ShaderPlatformInterfaces

+ 237 - 0
Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuildArgumentsManager.cpp

@@ -0,0 +1,237 @@
+/*
+ * 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 "ShaderBuildArgumentsManager.h"
+
+#include <AzCore/Settings/SettingsRegistry.h>
+#include <AzCore/Utils/Utils.h>
+#include <AzCore/Serialization/Json/JsonUtils.h>
+#include <AzCore/IO/FileIO.h>
+
+#include <Atom/RPI.Edit/Common/JsonUtils.h>
+#include <Atom/RHI.Edit/ShaderBuildOptions.h>
+
+namespace AZ
+{
+    namespace ShaderBuilder
+    {
+        static AZStd::string ResolvePathAliases(AZStd::string_view inPath)
+        {
+            AZ::IO::FixedMaxPath resolvedPath;
+            
+            auto fileIO = AZ::IO::FileIOBase::GetInstance();
+            const bool success = fileIO->ResolvePath(resolvedPath, inPath);
+            
+            if (success)
+            {
+                return AZStd::string(resolvedPath.c_str());
+            }
+
+            return { inPath };
+        }
+
+        void ShaderBuildArgumentsManager::Init()
+        {
+            AZStd::unordered_map<AZStd::string, AZ::RHI::ShaderBuildArguments> removeBuildArgumentsMap;
+            AZStd::unordered_map<AZStd::string, AZ::RHI::ShaderBuildArguments> addBuildArgumentsMap;
+            auto configFiles = DiscoverConfigurationFiles();
+            for (auto const& [scopeName, jsonFilePath] : configFiles)
+            {
+                AZ::RHI::ShaderBuildOptions shaderBuildOptions;
+                if (!AZ::RPI::JsonUtils::LoadObjectFromFile(jsonFilePath.c_str(), shaderBuildOptions))
+                {
+                    AZ_Error(
+                        LogName, false, "Failed to load shader build options file=<%s> for scope=<%s>", jsonFilePath.c_str(),
+                        scopeName.c_str());
+                    continue;
+                }
+                const auto addedDefinitionCount = shaderBuildOptions.m_addBuildArguments.AppendDefinitions(shaderBuildOptions.m_definitions);
+                AZ_Assert(addedDefinitionCount >= 0, "Failed to add definitions");
+
+                removeBuildArgumentsMap.emplace(scopeName, AZStd::move(shaderBuildOptions.m_removeBuildArguments));
+                addBuildArgumentsMap.emplace(scopeName, AZStd::move(shaderBuildOptions.m_addBuildArguments));
+            }
+            Init(AZStd::move(removeBuildArgumentsMap), AZStd::move(addBuildArgumentsMap));
+        }
+
+        void ShaderBuildArgumentsManager::Init(AZStd::unordered_map<AZStd::string, AZ::RHI::ShaderBuildArguments> && removeBuildArgumentsMap
+                                             , AZStd::unordered_map<AZStd::string, AZ::RHI::ShaderBuildArguments> && addBuildArgumentsMap)
+        {
+            m_removeBuildArgumentsMap.clear();
+            m_removeBuildArgumentsMap.swap(removeBuildArgumentsMap);
+
+            m_addBuildArgumentsMap.clear();
+            m_addBuildArgumentsMap.swap(addBuildArgumentsMap);
+
+            m_argumentsStack = {};
+            m_argumentsNameStack = {};
+            m_argumentsStack.push(m_addBuildArgumentsMap[""]);
+            m_argumentsNameStack.push("");
+        }
+
+        const AZ::RHI::ShaderBuildArguments& ShaderBuildArgumentsManager::PushArgumentsInternal(const AZStd::string& name, const AZ::RHI::ShaderBuildArguments& arguments)
+        {
+            m_argumentsNameStack.push(name);
+            m_argumentsStack.push(arguments);
+            return m_argumentsStack.top();
+        }
+
+        const AZ::RHI::ShaderBuildArguments& ShaderBuildArgumentsManager::PushArgumentScope(const AZStd::string& name)
+        {
+            AZ_Assert(!name.empty(), "This function requires non empty names");
+            const auto& currentTopName = m_argumentsNameStack.top();
+            auto newTopName = currentTopName.empty() ? name : AZStd::string::format("%s.%s", currentTopName.c_str(), name.c_str());
+
+            auto it = m_addBuildArgumentsMap.find(newTopName);
+            if (it == m_addBuildArgumentsMap.end())
+            {
+                // It is normal not to have arguments for a specific key. Because this class works as a stack we'll just push a copy
+                // of whatever is currently at the top of the stack.
+                return PushArgumentsInternal(newTopName, GetCurrentArguments());
+            }
+
+            // Init() guarantees that if there's an Add set of arguments, there is also a Remove set of arguments. BUT either of both, the Add and the Remove Sets can be empty,
+            // what matters is that they are valid instances of ShaderBuildArguments class.
+            auto removeIt = m_removeBuildArgumentsMap.find(newTopName);
+            AZ_Assert(removeIt != m_removeBuildArgumentsMap.end(), "There must be an instance of arguments to remove for %s", currentTopName.c_str());
+
+            auto newArguments = GetCurrentArguments() - removeIt->second;
+            return PushArgumentsInternal(newTopName, newArguments + it->second);
+        }
+
+        const AZ::RHI::ShaderBuildArguments& ShaderBuildArgumentsManager::PushArgumentScope(const AZ::RHI::ShaderBuildArguments& removeArguments,
+            const AZ::RHI::ShaderBuildArguments& addArguments, const AZStd::vector<AZStd::string>& definitions)
+        {
+            const AZStd::string anyName("?");
+            const auto& currentTopName = m_argumentsNameStack.top();
+            auto newTopName = currentTopName.empty() ? anyName : AZStd::string::format("%s.%s", currentTopName.c_str(), anyName.c_str());
+
+            auto newArguments = GetCurrentArguments() - removeArguments;
+            const auto addedDefinitionCount = newArguments.AppendDefinitions(definitions);
+            AZ_Assert(addedDefinitionCount >= 0, "Failed to add definitions");
+
+            return PushArgumentsInternal(newTopName, newArguments + addArguments);
+        }
+
+
+        const AZ::RHI::ShaderBuildArguments& ShaderBuildArgumentsManager::GetCurrentArguments() const
+        {
+            return m_argumentsStack.top();
+        }
+
+
+        void ShaderBuildArgumentsManager::PopArgumentScope()
+        {
+            // We always keep the global scope.
+            if (m_argumentsStack.size() > 1)
+            {
+                m_argumentsStack.pop();
+                m_argumentsNameStack.pop();
+            }
+        }
+
+        void DiscoverConfigurationFilesInDirectoryRecursively(const AZ::IO::FixedMaxPath& dirPath, const AZStd::string& keyName,
+            AZStd::unordered_map<AZStd::string, AZ::IO::FixedMaxPath>& discoveredFiles)
+        {
+            auto findFileCB = [&](const char * fileName, bool isFile) -> bool
+            {
+                if (fileName[0] == '.')
+                {
+                    return true;
+                }
+                AZ::IO::FixedMaxPath fullPath = dirPath / fileName;
+                if (isFile)
+                {
+                    discoveredFiles[keyName] = fullPath;
+                }
+                else
+                {
+                    AZStd::string subKeyName = AZStd::string::format("%s%s%s", keyName.c_str(), keyName.empty() ? "" : ".", fileName);
+                    DiscoverConfigurationFilesInDirectoryRecursively(fullPath, subKeyName, discoveredFiles);
+                }
+                return true;
+            };
+
+            AZ::IO::FixedMaxPath filter(dirPath);
+            filter /= "*";
+            AZ::IO::SystemFile::FindFiles(filter.c_str(), findFileCB);
+        }
+
+        AZStd::unordered_map<AZStd::string, AZ::IO::FixedMaxPath> ShaderBuildArgumentsManager::DiscoverConfigurationFilesInDirectory(const AZ::IO::FixedMaxPath& dirPath)
+        {
+            AZStd::unordered_map<AZStd::string, AZ::IO::FixedMaxPath> configurationFiles;
+
+            auto jsonPath = dirPath / ShaderBuildOptionsJson;
+            if (AZ::IO::SystemFile::Exists(jsonPath.c_str()))
+            {
+                // The global scope has no name.
+                configurationFiles[""] = jsonPath;
+            }
+
+            AZ::IO::FixedMaxPath platformsDirPath(dirPath);
+            platformsDirPath /= PlatformsDir;
+
+            DiscoverConfigurationFilesInDirectoryRecursively(platformsDirPath, "", configurationFiles);
+
+            return configurationFiles;
+        }
+
+
+        AZ::IO::FixedMaxPath ShaderBuildArgumentsManager::GetDefaultConfigDirectoryPath()
+        {
+            AZStd::string defaultConfigDirectory(DefaultConfigPathDirectory);
+            defaultConfigDirectory = ResolvePathAliases(defaultConfigDirectory);
+            // The default directory, which contains factory settings, must always exist.
+            AZ_Assert(AZ::IO::SystemFile::Exists(defaultConfigDirectory.c_str()), "The default directory with shader build arguments must exist: %s", defaultConfigDirectory.c_str());
+            return { defaultConfigDirectory };
+        }
+
+        AZ::IO::FixedMaxPath ShaderBuildArgumentsManager::GetUserConfigDirectoryPath()
+        {
+            AZStd::string userConfig;
+            auto settingsRegistry = AZ::SettingsRegistry::Get();
+            if (settingsRegistry)
+            {
+                settingsRegistry->Get(userConfig, ConfigPathRegistryKey);
+            }
+            if (userConfig.empty())
+            {
+                return {};
+            }
+            userConfig = ResolvePathAliases(userConfig);
+            return { userConfig };
+        }
+
+        AZStd::unordered_map<AZStd::string, AZ::IO::FixedMaxPath> ShaderBuildArgumentsManager::DiscoverConfigurationFiles()
+        {
+            const auto defaultConfigDirectoryPath = GetDefaultConfigDirectoryPath();
+            auto configFiles = DiscoverConfigurationFilesInDirectory(defaultConfigDirectoryPath);
+            auto userConfigPath = GetUserConfigDirectoryPath();
+            if (userConfigPath.empty() || (defaultConfigDirectoryPath == userConfigPath))
+            {
+                // The user chose not to customize the command line arguments.
+                // Let's return the Atom's default.
+                return configFiles;
+            }
+
+            auto userConfigFiles = DiscoverConfigurationFilesInDirectory(userConfigPath);
+
+            // Replace only the file paths that are customized by the user.
+            for (auto const& [key, val] : configFiles)
+            {
+                const auto itor = userConfigFiles.find(key);
+                if (itor == userConfigFiles.end())
+                {
+                    continue;
+                }
+                configFiles[key] = userConfigFiles[key];
+            }
+            return configFiles;
+        }
+    } // namespace ShaderBuilder
+} // AZ

+ 146 - 0
Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuildArgumentsManager.h

@@ -0,0 +1,146 @@
+/*
+ * 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 <AzCore/base.h>
+#include <AzCore/IO/Path/Path.h>
+
+#include "CommonFiles/CommonTypes.h"
+#include <Atom/RHI.Edit/ShaderBuildArguments.h> 
+
+
+namespace UnitTest
+{
+    class ShaderBuildArgumentsTests;
+}
+
+namespace AZ
+{
+    namespace ShaderBuilder
+    {
+        //! This class manages a stack of ShaderBuildArguments.
+        //! It simplifies command line argument definition at each level
+        //! of the shader build hierarchy:
+        //! 
+        //! {
+        //! push(global arguments)
+        //!     {
+        //!     push(PlatformInfo arguments)
+        //!         {
+        //!         push(RHI arguments)
+        //!             {
+        //!             push(.shader arguments)
+        //!                 {
+        //!                 push(shader.supervariant arguments)
+        //!                 ...
+        //!                 -- build shader with current arguments. --
+        //!                 ...
+        //!                 pop()
+        //!                 }
+        //!             pop() 
+        //!             }
+        //!         pop()
+        //!         }
+        //!     pop()
+        //!     }
+        //! pop()
+        //! }
+        //!
+        //! At each push(), two set of arguments are necessary, the "remove" set and the "add" set.
+        //! The idea is that it allows deep customization of all the shader build arguments by removing
+        //! or adding arguments at each level.
+        class ShaderBuildArgumentsManager final
+        {
+        public:
+            AZ_CLASS_ALLOCATOR(ShaderBuildArgumentsManager, AZ::SystemAllocator, 0);
+
+            static constexpr char LogName[] = "ShaderBuildArgumentsManager";
+
+            // The value of this registry key is customizable by the user.
+            static constexpr char ConfigPathRegistryKey[] = "/O3DE/Atom/Shaders/Build/ConfigPath";
+
+            static constexpr char DefaultConfigPathDirectory[] = "@gemroot:AtomShader@/Config";
+            static constexpr char ShaderBuildOptionsJson[] = "shader_build_options.json";
+            static constexpr char PlatformsDir[] = "Platform";
+
+            //! Always loads all the factory arguments provided by the Atom Gem. In addition
+            //! it checks if the user customized all or some of the arguments with the registry key: @ConfigPathRegistryKey (see above)
+            void Init();
+
+            //! Pushes a new scope of arguments into the stack . The arguments to push are searched internally by the given @name,
+            //! but if such arguments are not found, which is a common situation, then the current set of arguments at the top of the stack
+            //! are pushed again on top of the stack, so subsequent calls to PopArgumentScope() work seamlessly.
+            //! @param name Substring of the internally owned set of arguments.
+            //! For example if the user wants to use the arguments for dx12 on Windows ("Windows.dx12"),
+            //! then it is expected that this function should be called twice, as follows:
+            //!     PushArguments("Windows")
+            //!     PushArguments("dx12")
+            //! The names come from the directory structure under the Platform/ folder:
+            //! - Platform/
+            //!   - Windows/  (Platform name)
+            //!     - dx12/   (RHI name)
+            //!     - vulkan/ (RHI name)
+            //! @returns The resulting (combined, with - and +) set of arguments at the top of the stack.
+            const AZ::RHI::ShaderBuildArguments& PushArgumentScope(const AZStd::string& name);
+
+            //! Similar to above, but the arguments being pushed are anonymous.
+            //! @param removeArguments List of arguments to remove from the top of the stack.
+            //! @param addArguments List of arguments to add to the top of the stack.
+            //! @param definitions Additional arguments, specialized for the C-preprocessor, of the form "MACRO", or "MACRO=VALUE".
+            //! @returns The resulting (combined, with - and +) set of arguments at the top of the stack.
+            const AZ::RHI::ShaderBuildArguments& PushArgumentScope(const AZ::RHI::ShaderBuildArguments& removeArguments,
+                                                               const AZ::RHI::ShaderBuildArguments& addArguments,
+                                                               const AZStd::vector<AZStd::string>& definitions);
+
+            //! @returns The resulting (combined, with - and +) set of arguments at the top of the stack.
+            const AZ::RHI::ShaderBuildArguments& GetCurrentArguments() const;
+
+            //! Your typical stack popping function.
+            //! @remark: The "" (global) arguments are never popped, regardless of how many times this function is called.
+            void PopArgumentScope();
+
+        private:
+            friend class ::UnitTest::ShaderBuildArgumentsTests;
+            void Init(AZStd::unordered_map<AZStd::string, AZ::RHI::ShaderBuildArguments> && removeBuildArgumentsMap
+                    , AZStd::unordered_map<AZStd::string, AZ::RHI::ShaderBuildArguments> && addBuildArgumentsMap);
+
+            //! @returns A fully qualified path where the factory settings, as provided by Atom, are found.
+            AZ::IO::FixedMaxPath GetDefaultConfigDirectoryPath();
+
+            //! @returns A fully qualified path where the user customized command line arguments are found.
+            //!     The returned path will be empty if the user did not customize the path in the registry.
+            AZ::IO::FixedMaxPath GetUserConfigDirectoryPath();
+
+            //! @param dirPath Starting directory for the search of  shader_build_options.json files.
+            //! @returns A map where the key is the name of the scope, and the value is a fully qualified file path.
+            //! Remarks: Posible scope names are:
+            //!     "global"
+            //!     "<platform>". Example "Android", "Windows", etc
+            //!     "<platform>.<rhi>". Example "Windows.dx12" or "Windows.vulkan".
+            AZStd::unordered_map<AZStd::string, AZ::IO::FixedMaxPath> DiscoverConfigurationFilesInDirectory(const AZ::IO::FixedMaxPath& dirPath);
+
+            AZStd::unordered_map<AZStd::string, AZ::IO::FixedMaxPath> DiscoverConfigurationFiles();
+
+            const AZ::RHI::ShaderBuildArguments& PushArgumentsInternal(const AZStd::string& name, const AZ::RHI::ShaderBuildArguments& arguments);
+
+            //! In this map we store which arguments should be removed for a fully qualified scope of arguments.
+            //! A fully qualified scope name can be:
+            //!     "Windows" or "Windows.dx12" or "Windows.vulkan".
+            AZStd::unordered_map<AZStd::string, AZ::RHI::ShaderBuildArguments> m_removeBuildArgumentsMap;
+
+            //! In this map we store which arguments should be added for a fully qualified scope of arguments.
+            //! A fully qualified scope name can be:
+            //!     "" (The global scope) or "Windows" or "Windows.dx12" or "Windows.vulkan".
+            AZStd::unordered_map<AZStd::string, AZ::RHI::ShaderBuildArguments> m_addBuildArgumentsMap;
+
+            AZStd::stack<AZ::RHI::ShaderBuildArguments> m_argumentsStack;
+            AZStd::stack<AZStd::string> m_argumentsNameStack;
+        };
+    } // ShaderBuilder namespace
+} // AZ

+ 15 - 3
Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.cpp

@@ -37,7 +37,6 @@
 
 
 #include "ShaderPlatformInterfaceRequest.h"
 #include "ShaderPlatformInterfaceRequest.h"
 #include "ShaderBuilder_Traits_Platform.h"
 #include "ShaderBuilder_Traits_Platform.h"
-#include "AtomShaderConfig.h"
 
 
 #include "SrgLayoutUtility.h"
 #include "SrgLayoutUtility.h"
 
 
@@ -535,7 +534,7 @@ namespace AZ
 
 
             RHI::Ptr<RHI::PipelineLayoutDescriptor> BuildPipelineLayoutDescriptorForApi(
             RHI::Ptr<RHI::PipelineLayoutDescriptor> BuildPipelineLayoutDescriptorForApi(
                 [[maybe_unused]] const char* builderName, const RPI::ShaderResourceGroupLayoutList& srgLayoutList, const MapOfStringToStageType& shaderEntryPoints,
                 [[maybe_unused]] const char* builderName, const RPI::ShaderResourceGroupLayoutList& srgLayoutList, const MapOfStringToStageType& shaderEntryPoints,
-                const RHI::ShaderCompilerArguments& shaderCompilerArguments, const RootConstantData& rootConstantData,
+                const RHI::ShaderBuildArguments& shaderBuildArguments, const RootConstantData& rootConstantData,
                 RHI::ShaderPlatformInterface* shaderPlatformInterface, BindingDependencies& bindingDependencies /*inout*/)
                 RHI::ShaderPlatformInterface* shaderPlatformInterface, BindingDependencies& bindingDependencies /*inout*/)
             {
             {
                 PruneNonEntryFunctions(bindingDependencies, shaderEntryPoints);
                 PruneNonEntryFunctions(bindingDependencies, shaderEntryPoints);
@@ -624,7 +623,7 @@ namespace AZ
 
 
                 // Build platform-specific PipelineLayoutDescriptor data, and finalize
                 // Build platform-specific PipelineLayoutDescriptor data, and finalize
                 if (!shaderPlatformInterface->BuildPipelineLayoutDescriptor(
                 if (!shaderPlatformInterface->BuildPipelineLayoutDescriptor(
-                        pipelineLayoutDescriptor, srgInfos, rootConstantInfo, shaderCompilerArguments))
+                        pipelineLayoutDescriptor, srgInfos, rootConstantInfo, shaderBuildArguments))
                 {
                 {
                     AZ_Error(builderName, false, "Failed to build pipeline layout descriptor");
                     AZ_Error(builderName, false, "Failed to build pipeline layout descriptor");
                     return nullptr;
                     return nullptr;
@@ -885,6 +884,19 @@ namespace AZ
                 return AZ::Success(AZStd::move(listOfFilePaths));
                 return AZ::Success(AZStd::move(listOfFilePaths));
             }
             }
 
 
+            AZStd::string GetPlatformNameFromPlatformInfo(const AssetBuilderSDK::PlatformInfo& platformInfo)
+            {
+                auto platformId = AZ::PlatformDefaults::PlatformHelper::GetPlatformIdFromName(platformInfo.m_identifier);
+                switch (platformId)
+                {
+                case AZ::PlatformDefaults::PlatformId::PC :
+                case AZ::PlatformDefaults::PlatformId::SERVER : // Fallthrough. "pc" and "server" are both treated as "Windows".
+                    return { "Windows" };
+                default:
+                    return AZ::PlatformDefaults::PlatformIdToPalFolder(platformId);
+                }
+            }
+
         }  // namespace ShaderBuilderUtility
         }  // namespace ShaderBuilderUtility
     } // namespace ShaderBuilder
     } // namespace ShaderBuilder
 } // AZ
 } // AZ

+ 2 - 1
Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.h

@@ -81,7 +81,7 @@ namespace AZ
                 const char* builderName,
                 const char* builderName,
                 const RPI::ShaderResourceGroupLayoutList& srgLayoutList,
                 const RPI::ShaderResourceGroupLayoutList& srgLayoutList,
                 const MapOfStringToStageType& shaderEntryPoints,
                 const MapOfStringToStageType& shaderEntryPoints,
-                const RHI::ShaderCompilerArguments& shaderCompilerArguments,
+                const RHI::ShaderBuildArguments& shaderBuildArguments,
                 const RootConstantData& rootConstantData,
                 const RootConstantData& rootConstantData,
                 RHI::ShaderPlatformInterface* shaderPlatformInterface,
                 RHI::ShaderPlatformInterface* shaderPlatformInterface,
                 BindingDependencies& bindingDependencies /*inout*/);
                 BindingDependencies& bindingDependencies /*inout*/);
@@ -141,6 +141,7 @@ namespace AZ
                 const uint32_t rhiUniqueIndex, const AZStd::string& platformIdentifier, const AZStd::string& shaderJsonPath,
                 const uint32_t rhiUniqueIndex, const AZStd::string& platformIdentifier, const AZStd::string& shaderJsonPath,
                 const uint32_t supervariantIndex, RPI::ShaderAssetSubId shaderAssetSubId);
                 const uint32_t supervariantIndex, RPI::ShaderAssetSubId shaderAssetSubId);
 
 
+            AZStd::string GetPlatformNameFromPlatformInfo(const AssetBuilderSDK::PlatformInfo& platformInfo);
 
 
             class IncludedFilesParser
             class IncludedFilesParser
             {
             {

+ 26 - 15
Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp

@@ -53,9 +53,8 @@
 #include "AzslData.h"
 #include "AzslData.h"
 #include "AzslCompiler.h"
 #include "AzslCompiler.h"
 #include <CommonFiles/Preprocessor.h>
 #include <CommonFiles/Preprocessor.h>
-#include <CommonFiles/GlobalBuildOptions.h>
 #include <ShaderPlatformInterfaceRequest.h>
 #include <ShaderPlatformInterfaceRequest.h>
-#include "AtomShaderConfig.h"
+#include "ShaderBuildArgumentsManager.h"
 
 
 namespace AZ
 namespace AZ
 {
 {
@@ -738,6 +737,8 @@ namespace AZ
 
 
             const auto& jobParameters = request.m_jobDescription.m_jobParameters;
             const auto& jobParameters = request.m_jobDescription.m_jobParameters;
             const AZStd::string& shaderSourceFileFullPath = jobParameters.at(ShaderSourceFilePathJobParam);
             const AZStd::string& shaderSourceFileFullPath = jobParameters.at(ShaderSourceFilePathJobParam);
+            auto descriptorParseOutcome = ShaderBuilderUtility::LoadShaderDataJson(shaderSourceFileFullPath);
+            RPI::ShaderSourceData shaderSourceData = descriptorParseOutcome.TakeValue();
             AZStd::string shaderFileName;
             AZStd::string shaderFileName;
             AzFramework::StringFunc::Path::GetFileName(shaderSourceFileFullPath.c_str(), shaderFileName);
             AzFramework::StringFunc::Path::GetFileName(shaderSourceFileFullPath.c_str(), shaderFileName);
 
 
@@ -769,10 +770,13 @@ namespace AZ
 
 
             auto supervariantList = ShaderBuilderUtility::GetSupervariantListFromShaderSourceData(shaderSourceDescriptor);
             auto supervariantList = ShaderBuilderUtility::GetSupervariantListFromShaderSourceData(shaderSourceDescriptor);
 
 
-            GlobalBuildOptions buildOptions = ReadBuildOptions(ShaderVariantAssetBuilderName);
-            // At this moment We have global build options that should be merged with the build options that are common
-            // to all the supervariants of this shader.
-            buildOptions.m_compilerArguments.Merge(shaderSourceDescriptor.m_compiler);
+            ShaderBuildArgumentsManager buildArgsManager;
+            buildArgsManager.Init();
+            // A job always runs on behalf of an Asset Processing platform (aka PlatformInfo).
+            // Let's merge the shader build arguments of the current PlatformInfo with the global
+            // set of arguments.
+            const auto platformName = ShaderBuilderUtility::GetPlatformNameFromPlatformInfo(request.m_platformInfo);
+            buildArgsManager.PushArgumentScope(platformName);
 
 
             //! The ShaderOptionGroupLayout is common across all RHIs & Supervariants
             //! The ShaderOptionGroupLayout is common across all RHIs & Supervariants
             RPI::Ptr<RPI::ShaderOptionGroupLayout> shaderOptionGroupLayout = nullptr;
             RPI::Ptr<RPI::ShaderOptionGroupLayout> shaderOptionGroupLayout = nullptr;
@@ -780,7 +784,11 @@ namespace AZ
             // Generate shaders for each of those ShaderPlatformInterfaces.
             // Generate shaders for each of those ShaderPlatformInterfaces.
             for (RHI::ShaderPlatformInterface* shaderPlatformInterface : platformInterfaces)
             for (RHI::ShaderPlatformInterface* shaderPlatformInterface : platformInterfaces)
             {
             {
-                AZ_TraceContext("ShaderPlatformInterface", shaderPlatformInterface->GetAPIName().GetCStr());
+                AZStd::string apiName(shaderPlatformInterface->GetAPIName().GetCStr());
+                AZ_TraceContext("Platform API", apiName);
+
+                buildArgsManager.PushArgumentScope(apiName);
+                buildArgsManager.PushArgumentScope(shaderSourceData.m_removeBuildArguments, shaderSourceData.m_addBuildArguments, shaderSourceData.m_definitions);
 
 
                 // Loop through all the Supervariants.
                 // Loop through all the Supervariants.
                 uint32_t supervariantIndexCounter = 0;
                 uint32_t supervariantIndexCounter = 0;
@@ -796,6 +804,8 @@ namespace AZ
                         return;
                         return;
                     }
                     }
 
 
+                    buildArgsManager.PushArgumentScope(supervariantInfo.m_removeBuildArguments, supervariantInfo.m_addBuildArguments, supervariantInfo.m_definitions);
+
                     AZStd::string shaderStemNamePrefix = shaderFileName;
                     AZStd::string shaderStemNamePrefix = shaderFileName;
                     if (supervariantIndex.GetIndex() > 0)
                     if (supervariantIndex.GetIndex() > 0)
                     {
                     {
@@ -856,10 +866,8 @@ namespace AZ
                     RHI::Ptr<RHI::PipelineLayoutDescriptor> pipelineLayoutDescriptor;
                     RHI::Ptr<RHI::PipelineLayoutDescriptor> pipelineLayoutDescriptor;
                     if (shaderPlatformInterface->VariantCompilationRequiresSrgLayoutData())
                     if (shaderPlatformInterface->VariantCompilationRequiresSrgLayoutData())
                     {
                     {
-                        AZStd::string azslcCompilerParameters =
-                            shaderPlatformInterface->GetAzslCompilerParameters(buildOptions.m_compilerArguments);
-                        const bool platformUsesRegisterSpaces =
-                            (AzFramework::StringFunc::Find(azslcCompilerParameters, "--use-spaces") != AZStd::string::npos);
+                        const auto& azslcArguments = buildArgsManager.GetCurrentArguments().m_azslcArguments;
+                        const bool platformUsesRegisterSpaces = RHI::ShaderBuildArguments::HasArgument(azslcArguments, "--use-spaces");
                     
                     
                         RPI::ShaderResourceGroupLayoutList srgLayoutList;
                         RPI::ShaderResourceGroupLayoutList srgLayoutList;
                         RootConstantData rootConstantData;
                         RootConstantData rootConstantData;
@@ -884,7 +892,7 @@ namespace AZ
                         
                         
                         pipelineLayoutDescriptor =
                         pipelineLayoutDescriptor =
                             ShaderBuilderUtility::BuildPipelineLayoutDescriptorForApi(
                             ShaderBuilderUtility::BuildPipelineLayoutDescriptorForApi(
-                                ShaderVariantAssetBuilderName, srgLayoutList, shaderEntryPoints, buildOptions.m_compilerArguments, rootConstantData,
+                                ShaderVariantAssetBuilderName, srgLayoutList, shaderEntryPoints, buildArgsManager.GetCurrentArguments(), rootConstantData,
                                 shaderPlatformInterface, bindingDependencies);
                                 shaderPlatformInterface, bindingDependencies);
                         if (!pipelineLayoutDescriptor)
                         if (!pipelineLayoutDescriptor)
                         {
                         {
@@ -899,7 +907,7 @@ namespace AZ
                     // Setup the shader variant creation context:
                     // Setup the shader variant creation context:
                     ShaderVariantCreationContext shaderVariantCreationContext =
                     ShaderVariantCreationContext shaderVariantCreationContext =
                     {
                     {
-                        *shaderPlatformInterface, request.m_platformInfo, buildOptions.m_compilerArguments, request.m_tempDirPath,
+                        *shaderPlatformInterface, request.m_platformInfo, buildArgsManager.GetCurrentArguments(), request.m_tempDirPath,
                         shaderVariantAssetBuildTimestamp,
                         shaderVariantAssetBuildTimestamp,
                         shaderSourceDescriptor,
                         shaderSourceDescriptor,
                         *shaderOptionGroupLayout.get(),
                         *shaderOptionGroupLayout.get(),
@@ -949,9 +957,12 @@ namespace AZ
                             response.m_outputProducts.push_back(AZStd::move(jobProduct));
                             response.m_outputProducts.push_back(AZStd::move(jobProduct));
                         }
                         }
                     }
                     }
+                    buildArgsManager.PopArgumentScope(); // Pop the supervariant build arguments.
                     supervariantIndexCounter++;
                     supervariantIndexCounter++;
                 } // End of supervariant for block
                 } // End of supervariant for block
-                
+
+                buildArgsManager.PopArgumentScope(); // Pop the .shader build arguments.
+                buildArgsManager.PopArgumentScope(); // Pop the RHI build arguments.
             }
             }
 
 
             response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
             response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
@@ -1103,7 +1114,7 @@ namespace AZ
                 RHI::ShaderPlatformInterface::StageDescriptor descriptor;
                 RHI::ShaderPlatformInterface::StageDescriptor descriptor;
                 bool shaderWasCompiled = creationContext.m_shaderPlatformInterface.CompilePlatformInternal(
                 bool shaderWasCompiled = creationContext.m_shaderPlatformInterface.CompilePlatformInternal(
                     creationContext.m_platformInfo, variantShaderSourcePath, shaderEntryName, assetBuilderShaderType,
                     creationContext.m_platformInfo, variantShaderSourcePath, shaderEntryName, assetBuilderShaderType,
-                    creationContext.m_tempDirPath, descriptor, creationContext.m_shaderCompilerArguments);
+                    creationContext.m_tempDirPath, descriptor, creationContext.m_shaderBuildArguments);
 
 
                 if (!shaderWasCompiled)
                 if (!shaderWasCompiled)
                 {
                 {

+ 1 - 1
Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h

@@ -33,7 +33,7 @@ namespace AZ
         {
         {
             RHI::ShaderPlatformInterface& m_shaderPlatformInterface;
             RHI::ShaderPlatformInterface& m_shaderPlatformInterface;
             const AssetBuilderSDK::PlatformInfo& m_platformInfo;
             const AssetBuilderSDK::PlatformInfo& m_platformInfo;
-            const RHI::ShaderCompilerArguments& m_shaderCompilerArguments;
+            const RHI::ShaderBuildArguments& m_shaderBuildArguments;
             //! Used to write temporary files during shader compilation, like *.hlsl, or *.air, or *.metallib, etc.
             //! Used to write temporary files during shader compilation, like *.hlsl, or *.air, or *.metallib, etc.
             const AZStd::string& m_tempDirPath;
             const AZStd::string& m_tempDirPath;
             //! Used to synchronize versions of the ShaderAsset and ShaderVariantAsset,
             //! Used to synchronize versions of the ShaderAsset and ShaderVariantAsset,

+ 2 - 0
Gems/Atom/Asset/Shader/Code/Tests/Common/ShaderBuilderTestFixture.cpp

@@ -11,6 +11,8 @@
 #include <AzCore/Memory/PoolAllocator.h>
 #include <AzCore/Memory/PoolAllocator.h>
 #include <AzCore/Name/NameDictionary.h>
 #include <AzCore/Name/NameDictionary.h>
 
 
+#include <AzslShaderBuilderSystemComponent.h>
+
 namespace UnitTest
 namespace UnitTest
 {
 {
     void ShaderBuilderTestFixture::SetUp()
     void ShaderBuilderTestFixture::SetUp()

+ 8 - 0
Gems/Atom/Asset/Shader/Code/Tests/Common/ShaderBuilderTestFixture.h

@@ -9,6 +9,13 @@
 #pragma once
 #pragma once
 
 
 #include <AzCore/UnitTest/TestTypes.h>
 #include <AzCore/UnitTest/TestTypes.h>
+#include <AzCore/Component/ComponentApplication.h> // Galib
+#include <AzFramework/IO/LocalFileIO.h>
+#include <AzCore/Serialization/Json/JsonSystemComponent.h>
+#include <AzCore/Serialization/Json/RegistrationContext.h>
+#include <AzCore/Serialization/ObjectStream.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Serialization/Utils.h>
 
 
 namespace UnitTest
 namespace UnitTest
 {
 {
@@ -25,6 +32,7 @@ namespace UnitTest
         void SetUp() override;
         void SetUp() override;
         void TearDown() override;
         void TearDown() override;
         ///////////////////////////////////////////////////////////////////////
         ///////////////////////////////////////////////////////////////////////
+
     };
     };
 } // namespace UnitTest
 } // namespace UnitTest
 
 

Some files were not shown because too many files changed in this diff